Merge pull request #486 from FreeCodeCamp/staging
merge new curriculum, help/pair/bug functionality, jobs page
This commit is contained in:
25
.eslintrc
25
.eslintrc
@ -7,6 +7,10 @@
|
||||
"mocha": true,
|
||||
"node": true
|
||||
},
|
||||
"parser": "babel-eslint",
|
||||
"plugins": [
|
||||
"react"
|
||||
],
|
||||
"globals": {
|
||||
"window": true,
|
||||
"$": true,
|
||||
@ -41,7 +45,7 @@
|
||||
"valid-jsdoc": 2,
|
||||
"valid-typeof": 2,
|
||||
|
||||
"block-scoped-var": 2,
|
||||
"block-scoped-var": 0,
|
||||
"complexity": 0,
|
||||
"consistent-return": 2,
|
||||
"curly": 2,
|
||||
@ -215,6 +219,21 @@
|
||||
"max-params": 0,
|
||||
"max-statements": 0,
|
||||
"no-bitwise": 1,
|
||||
"no-plusplus": 0
|
||||
"no-plusplus": 0,
|
||||
|
||||
"react/display-name": 1,
|
||||
"react/jsx-boolean-value": 1,
|
||||
"react/jsx-quotes": [1, "single", "avoid-escape"],
|
||||
"react/jsx-no-undef": 1,
|
||||
"react/jsx-sort-props": 1,
|
||||
"react/jsx-uses-react": 1,
|
||||
"react/jsx-uses-vars": 1,
|
||||
"react/no-did-mount-set-state": 2,
|
||||
"react/no-did-update-set-state": 2,
|
||||
"react/no-multi-comp": 2,
|
||||
"react/prop-types": 2,
|
||||
"react/react-in-jsx-scope": 1,
|
||||
"react/self-closing-comp": 1,
|
||||
"react/wrap-multilines": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
271
app.js
271
app.js
@ -33,28 +33,27 @@ var express = require('express'),
|
||||
forceDomain = require('forcedomain'),
|
||||
lessMiddleware = require('less-middleware'),
|
||||
|
||||
/**
|
||||
* Controllers (route handlers).
|
||||
*/
|
||||
homeController = require('./controllers/home'),
|
||||
resourcesController = require('./controllers/resources'),
|
||||
userController = require('./controllers/user'),
|
||||
nonprofitController = require('./controllers/nonprofits'),
|
||||
bonfireController = require('./controllers/bonfire'),
|
||||
coursewareController = require('./controllers/courseware'),
|
||||
fieldGuideController = require('./controllers/fieldGuide'),
|
||||
challengeMapController = require('./controllers/challengeMap'),
|
||||
/**
|
||||
* Controllers (route handlers).
|
||||
*/
|
||||
homeController = require('./controllers/home'),
|
||||
resourcesController = require('./controllers/resources'),
|
||||
userController = require('./controllers/user'),
|
||||
nonprofitController = require('./controllers/nonprofits'),
|
||||
fieldGuideController = require('./controllers/fieldGuide'),
|
||||
challengeMapController = require('./controllers/challengeMap'),
|
||||
challengeController = require('./controllers/challenge'),
|
||||
|
||||
/**
|
||||
* Stories
|
||||
*/
|
||||
storyController = require('./controllers/story'),
|
||||
/**
|
||||
* Stories
|
||||
*/
|
||||
storyController = require('./controllers/story'),
|
||||
|
||||
/**
|
||||
* API keys and Passport configuration.
|
||||
*/
|
||||
secrets = require('./config/secrets'),
|
||||
passportConf = require('./config/passport');
|
||||
/**
|
||||
* API keys and Passport configuration.
|
||||
*/
|
||||
secrets = require('./config/secrets'),
|
||||
passportConf = require('./config/passport');
|
||||
|
||||
/**
|
||||
* Create Express server.
|
||||
@ -66,9 +65,9 @@ var app = express();
|
||||
*/
|
||||
mongoose.connect(secrets.db);
|
||||
mongoose.connection.on('error', function () {
|
||||
console.error(
|
||||
'MongoDB Connection Error. Please make sure that MongoDB is running.'
|
||||
);
|
||||
console.error(
|
||||
'MongoDB Connection Error. Please make sure that MongoDB is running.'
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
@ -92,11 +91,11 @@ app.use(logger('dev'));
|
||||
app.use(bodyParser.json());
|
||||
app.use(bodyParser.urlencoded({extended: true}));
|
||||
app.use(expressValidator({
|
||||
customValidators: {
|
||||
matchRegex: function (param, regex) {
|
||||
return regex.test(param);
|
||||
}
|
||||
customValidators: {
|
||||
matchRegex: function (param, regex) {
|
||||
return regex.test(param);
|
||||
}
|
||||
}
|
||||
}));
|
||||
app.use(methodOverride());
|
||||
app.use(cookieParser());
|
||||
@ -118,11 +117,11 @@ app.use(helmet.xssFilter());
|
||||
app.use(helmet.noSniff());
|
||||
app.use(helmet.frameguard());
|
||||
app.use(function(req, res, next) {
|
||||
res.header('Access-Control-Allow-Origin', '*');
|
||||
res.header('Access-Control-Allow-Headers',
|
||||
'Origin, X-Requested-With, Content-Type, Accept'
|
||||
);
|
||||
next();
|
||||
res.header('Access-Control-Allow-Origin', '*');
|
||||
res.header('Access-Control-Allow-Headers',
|
||||
'Origin, X-Requested-With, Content-Type, Accept'
|
||||
);
|
||||
next();
|
||||
});
|
||||
|
||||
var trusted = [
|
||||
@ -160,39 +159,41 @@ var trusted = [
|
||||
'*.ytimg.com',
|
||||
'*.bitly.com',
|
||||
'http://cdn.inspectlet.com/',
|
||||
'http://hn.inspectlet.com/'
|
||||
'http://hn.inspectlet.com/',
|
||||
'*.simplyhired.com',
|
||||
'*.simply-partner.com'
|
||||
];
|
||||
|
||||
app.use(helmet.csp({
|
||||
defaultSrc: trusted,
|
||||
scriptSrc: [
|
||||
'*.optimizely.com',
|
||||
'*.aspnetcdn.com',
|
||||
'*.d3js.org'
|
||||
].concat(trusted),
|
||||
'connect-src': [
|
||||
].concat(trusted),
|
||||
styleSrc: trusted,
|
||||
imgSrc: [
|
||||
/* allow all input since we have user submitted images for public profile*/
|
||||
'*'
|
||||
].concat(trusted),
|
||||
fontSrc: ['*.googleapis.com'].concat(trusted),
|
||||
mediaSrc: [
|
||||
'*.amazonaws.com',
|
||||
'*.twitter.com'
|
||||
].concat(trusted),
|
||||
frameSrc: [
|
||||
defaultSrc: trusted,
|
||||
scriptSrc: [
|
||||
'*.optimizely.com',
|
||||
'*.aspnetcdn.com',
|
||||
'*.d3js.org'
|
||||
].concat(trusted),
|
||||
'connect-src': [
|
||||
].concat(trusted),
|
||||
styleSrc: trusted,
|
||||
imgSrc: [
|
||||
/* allow all input since we have user submitted images for public profile*/
|
||||
'*'
|
||||
].concat(trusted),
|
||||
fontSrc: ['*.googleapis.com'].concat(trusted),
|
||||
mediaSrc: [
|
||||
'*.amazonaws.com',
|
||||
'*.twitter.com'
|
||||
].concat(trusted),
|
||||
frameSrc: [
|
||||
|
||||
'*.gitter.im',
|
||||
'*.gitter.im https:',
|
||||
'*.vimeo.com',
|
||||
'*.twitter.com',
|
||||
'*.ghbtns.com'
|
||||
].concat(trusted),
|
||||
reportOnly: false, // set to true if you only want to report errors
|
||||
setAllHeaders: false, // set to true if you want to set all headers
|
||||
safari5: false // set to true if you want to force buggy CSP in Safari 5
|
||||
'*.gitter.im',
|
||||
'*.gitter.im https:',
|
||||
'*.vimeo.com',
|
||||
'*.twitter.com',
|
||||
'*.ghbtns.com'
|
||||
].concat(trusted),
|
||||
reportOnly: false, // set to true if you only want to report errors
|
||||
setAllHeaders: false, // set to true if you want to set all headers
|
||||
safari5: false // set to true if you want to force buggy CSP in Safari 5
|
||||
}));
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
@ -204,15 +205,15 @@ app.use(function (req, res, next) {
|
||||
app.use(express.static(__dirname + '/public', {maxAge: 86400000 }));
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
// Remember original destination before login.
|
||||
var path = req.path.split('/')[1];
|
||||
if (/auth|login|logout|signin|signup|fonts|favicon/i.test(path)) {
|
||||
return next();
|
||||
} else if (/\/stories\/comments\/\w+/i.test(req.path)) {
|
||||
return next();
|
||||
}
|
||||
req.session.returnTo = req.path;
|
||||
next();
|
||||
// Remember original destination before login.
|
||||
var path = req.path.split('/')[1];
|
||||
if (/auth|login|logout|signin|signup|fonts|favicon/i.test(path)) {
|
||||
return next();
|
||||
} else if (/\/stories\/comments\/\w+/i.test(req.path)) {
|
||||
return next();
|
||||
}
|
||||
req.session.returnTo = req.path;
|
||||
next();
|
||||
});
|
||||
|
||||
/**
|
||||
@ -222,24 +223,47 @@ app.use(function (req, res, next) {
|
||||
app.get('/', homeController.index);
|
||||
|
||||
app.get('/nonprofit-project-instructions', function(req, res) {
|
||||
res.redirect(301, '/field-guide/how-do-free-code-camp\'s-nonprofit-projects-work');
|
||||
res.redirect(301, '/field-guide/how-do-free-code-camp\'s-nonprofit-projects-work');
|
||||
});
|
||||
|
||||
app.post('/get-help', resourcesController.getHelp);
|
||||
|
||||
app.post('/get-pair', resourcesController.getPair);
|
||||
|
||||
app.get('/chat', resourcesController.chat);
|
||||
|
||||
app.get('/twitch', resourcesController.twitch);
|
||||
|
||||
app.get('/cats.json', function(req, res) {
|
||||
res.send(
|
||||
[
|
||||
{
|
||||
"name": "cute",
|
||||
"imageLink": "https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcRaP1ecF2jerISkdhjr4R9yM9-8ClUy-TA36MnDiFBukd5IvEME0g"
|
||||
},
|
||||
{
|
||||
"name": "grumpy",
|
||||
"imageLink": "http://cdn.grumpycats.com/wp-content/uploads/2012/09/GC-Gravatar-copy.png"
|
||||
},
|
||||
{
|
||||
"name": "mischievous",
|
||||
"imageLink": "http://www.kittenspet.com/wp-content/uploads/2012/08/cat_with_funny_face_3-200x200.jpg"
|
||||
}
|
||||
]
|
||||
)
|
||||
});
|
||||
|
||||
// Agile Project Manager Onboarding
|
||||
|
||||
app.get('/pmi-acp-agile-project-managers',
|
||||
resourcesController.agileProjectManagers);
|
||||
resourcesController.agileProjectManagers);
|
||||
|
||||
app.get('/agile', function(req, res) {
|
||||
res.redirect(301, '/pmi-acp-agile-project-managers');
|
||||
});
|
||||
|
||||
app.get('/pmi-acp-agile-project-managers-form',
|
||||
resourcesController.agileProjectManagersForm);
|
||||
resourcesController.agileProjectManagersForm);
|
||||
|
||||
// Nonprofit Onboarding
|
||||
|
||||
@ -252,31 +276,31 @@ app.get('/nonprofits-form', resourcesController.nonprofitsForm);
|
||||
app.get('/map', challengeMapController.challengeMap);
|
||||
|
||||
app.get('/live-pair-programming', function(req, res) {
|
||||
res.redirect(301, '/field-guide/live-stream-pair-programming-on-twitch.tv');
|
||||
res.redirect(301, '/field-guide/live-stream-pair-programming-on-twitch.tv');
|
||||
});
|
||||
|
||||
app.get('/install-screenhero', function(req, res) {
|
||||
res.redirect(301, '/field-guide/install-screenhero');
|
||||
res.redirect(301, '/field-guide/install-screenhero');
|
||||
});
|
||||
|
||||
app.get('/guide-to-our-nonprofit-projects', function(req, res) {
|
||||
res.redirect(301, '/field-guide/a-guide-to-our-nonprofit-projects');
|
||||
res.redirect(301, '/field-guide/a-guide-to-our-nonprofit-projects');
|
||||
});
|
||||
|
||||
app.get('/chromebook', function(req, res) {
|
||||
res.redirect(301, '/field-guide/chromebook');
|
||||
res.redirect(301, '/field-guide/chromebook');
|
||||
});
|
||||
|
||||
app.get('/deploy-a-website', function(req, res) {
|
||||
res.redirect(301, '/field-guide/deploy-a-website');
|
||||
res.redirect(301, '/field-guide/deploy-a-website');
|
||||
});
|
||||
|
||||
app.get('/gmail-shortcuts', function(req, res) {
|
||||
res.redirect(301, '/field-guide/gmail-shortcuts');
|
||||
res.redirect(301, '/field-guide/gmail-shortcuts');
|
||||
});
|
||||
|
||||
app.get('/nodeschool-challenges', function(req, res) {
|
||||
res.redirect(301, '/field-guide/nodeschool-challenges');
|
||||
res.redirect(301, '/field-guide/nodeschool-challenges');
|
||||
});
|
||||
|
||||
|
||||
@ -321,20 +345,26 @@ app.post('/email-signin', userController.postSignin);
|
||||
app.get('/nonprofits/directory', nonprofitController.nonprofitsDirectory);
|
||||
|
||||
app.get(
|
||||
'/nonprofits/:nonprofitName',
|
||||
nonprofitController.returnIndividualNonprofit
|
||||
'/nonprofits/:nonprofitName',
|
||||
nonprofitController.returnIndividualNonprofit
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/update-progress',
|
||||
passportConf.isAuthenticated,
|
||||
userController.updateProgress
|
||||
app.get(
|
||||
'/jobs',
|
||||
resourcesController.jobs
|
||||
);
|
||||
|
||||
app.get(
|
||||
'/jobs-form',
|
||||
resourcesController.jobsForm
|
||||
);
|
||||
|
||||
app.get('/privacy', function(req, res) {
|
||||
res.redirect(301, '/field-guide/what-is-the-free-code-camp-privacy-policy?');
|
||||
});
|
||||
|
||||
app.get('/submit-cat-photo', resourcesController.catPhotoSubmit);
|
||||
|
||||
app.get('/api/slack', function(req, res) {
|
||||
if (req.user) {
|
||||
if (req.user.email) {
|
||||
@ -488,43 +518,14 @@ app.get('/api/trello', resourcesController.trelloCalls);
|
||||
|
||||
app.get('/api/codepen/twitter/:screenName', resourcesController.codepenResources.twitter);
|
||||
|
||||
/**
|
||||
* Bonfire related routes
|
||||
*/
|
||||
|
||||
app.get('/field-guide/getFieldGuideList', fieldGuideController.showAllFieldGuides);
|
||||
|
||||
app.get('/playground', bonfireController.index);
|
||||
|
||||
app.get('/bonfires', bonfireController.returnNextBonfire);
|
||||
|
||||
app.get('/bonfire-json-generator', bonfireController.returnGenerator);
|
||||
|
||||
app.post('/bonfire-json-generator', bonfireController.generateChallenge);
|
||||
|
||||
app.get('/bonfire-challenge-generator', bonfireController.publicGenerator);
|
||||
|
||||
app.post('/bonfire-challenge-generator', bonfireController.testBonfire);
|
||||
|
||||
app.get(
|
||||
'/bonfires/:bonfireName',
|
||||
bonfireController.returnIndividualBonfire
|
||||
);
|
||||
|
||||
app.get('/bonfire', function(req, res) {
|
||||
res.redirect(301, '/playground');
|
||||
});
|
||||
|
||||
app.post('/completed-bonfire/', bonfireController.completedBonfire);
|
||||
|
||||
/**
|
||||
* Field Guide related routes
|
||||
*/
|
||||
|
||||
app.get('/field-guide/all-articles', fieldGuideController.showAllFieldGuides);
|
||||
|
||||
app.get('/field-guide/:fieldGuideName',
|
||||
fieldGuideController.returnIndividualFieldGuide
|
||||
);
|
||||
fieldGuideController.returnIndividualFieldGuide
|
||||
);
|
||||
|
||||
app.get('/field-guide/', fieldGuideController.returnNextFieldGuide);
|
||||
|
||||
@ -532,29 +533,39 @@ app.post('/completed-field-guide/', fieldGuideController.completedFieldGuide);
|
||||
|
||||
|
||||
/**
|
||||
* Courseware related routes
|
||||
* Challenge related routes
|
||||
*/
|
||||
|
||||
app.get('/challenges/', coursewareController.returnNextCourseware);
|
||||
|
||||
app.get(
|
||||
'/challenges/:coursewareName',
|
||||
coursewareController.returnIndividualCourseware
|
||||
app.get('/challenges/next-challenge',
|
||||
userController.userMigration,
|
||||
challengeController.returnNextChallenge
|
||||
);
|
||||
|
||||
app.post('/completed-courseware/', coursewareController.completedCourseware);
|
||||
app.get(
|
||||
'/challenges/:challengeName',
|
||||
userController.userMigration,
|
||||
challengeController.returnIndividualChallenge
|
||||
);
|
||||
|
||||
app.get('/challenges/',
|
||||
userController.userMigration,
|
||||
challengeController.returnCurrentChallenge);
|
||||
// todo refactor these routes
|
||||
app.post('/completed-challenge/', challengeController.completedChallenge);
|
||||
|
||||
app.post('/completed-zipline-or-basejump',
|
||||
coursewareController.completedZiplineOrBasejump);
|
||||
challengeController.completedZiplineOrBasejump);
|
||||
|
||||
app.post('/completed-bonfire', challengeController.completedBonfire);
|
||||
|
||||
// Unique Check API route
|
||||
app.get('/api/checkUniqueUsername/:username',
|
||||
userController.checkUniqueUsername
|
||||
);
|
||||
userController.checkUniqueUsername
|
||||
);
|
||||
|
||||
app.get('/api/checkExistingUsername/:username',
|
||||
userController.checkExistingUsername
|
||||
);
|
||||
userController.checkExistingUsername
|
||||
);
|
||||
|
||||
app.get('/api/checkUniqueEmail/:email', userController.checkUniqueEmail);
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
"font-awesome": "~4.3.0",
|
||||
"moment": "~2.10.2",
|
||||
"angular-bootstrap": "~0.13.0",
|
||||
"ramda": "~0.13.0"
|
||||
"ramda": "~0.13.0",
|
||||
"jshint": "~2.7.0"
|
||||
}
|
||||
}
|
||||
|
29
config/bootstrap.js
vendored
29
config/bootstrap.js
vendored
@ -1,29 +0,0 @@
|
||||
var mongoose = require('mongoose'),
|
||||
debug = require('debug')('freecc:config:boot'),
|
||||
secrets = require('./secrets'),
|
||||
courses = require('../seed_data/courses.json'),
|
||||
Course = require('./../models/Course'),
|
||||
challenges = require('../seed_data/challenges.json'),
|
||||
Challenge = require('./../models/Challenge');
|
||||
|
||||
mongoose.connect(secrets.db);
|
||||
mongoose.connection.on('error', function() {
|
||||
console.error('MongoDB Connection Error. Make sure MongoDB is running.');
|
||||
});
|
||||
|
||||
|
||||
Course.create(courses, function(err, data) {
|
||||
if (err) {
|
||||
debug(err);
|
||||
} else {
|
||||
debug('Saved ', data);
|
||||
}
|
||||
});
|
||||
|
||||
Challenge.create(challenges, function(err, data) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
} else {
|
||||
console.log('Saved ', data);
|
||||
}
|
||||
});
|
@ -58,5 +58,6 @@ module.exports = {
|
||||
callbackURL: '/auth/linkedin/callback',
|
||||
scope: ['r_basicprofile', 'r_emailaddress'],
|
||||
passReqToCallback: true
|
||||
}
|
||||
},
|
||||
slackHook: process.env.SLACK_WEBHOOK,
|
||||
};
|
||||
|
@ -1,333 +0,0 @@
|
||||
var _ = require('lodash'),
|
||||
debug = require('debug')('freecc:cntr:bonfires'),
|
||||
Bonfire = require('./../models/Bonfire'),
|
||||
User = require('./../models/User'),
|
||||
resources = require('./resources'),
|
||||
R = require('ramda');
|
||||
MDNlinks = require('./../seed_data/bonfireMDNlinks');
|
||||
|
||||
/**
|
||||
* Bonfire controller
|
||||
*/
|
||||
|
||||
exports.showAllBonfires = function(req, res) {
|
||||
var completedBonfires = [];
|
||||
if(req.user) {
|
||||
completedBonfires = req.user.completedBonfires.map(function (elem) {
|
||||
return elem._id;
|
||||
});
|
||||
}
|
||||
var noDuplicateBonfires = R.uniq(completedBonfires);
|
||||
var data = {};
|
||||
data.bonfireList = resources.allBonfireNames();
|
||||
data.completedList = noDuplicateBonfires;
|
||||
res.send(data);
|
||||
};
|
||||
|
||||
exports.index = function(req, res) {
|
||||
res.render('bonfire/show.jade', {
|
||||
completedWith: null,
|
||||
title: 'Bonfire Playground',
|
||||
name: 'Bonfire Playground',
|
||||
difficulty: 0,
|
||||
brief: 'Feel free to play around!',
|
||||
details: '',
|
||||
tests: [],
|
||||
challengeSeed: '',
|
||||
cc: req.user ? req.user.bonfiresHash : undefined,
|
||||
progressTimestamps: req.user ? req.user.progressTimestamps : undefined,
|
||||
verb: resources.randomVerb(),
|
||||
phrase: resources.randomPhrase(),
|
||||
compliments: resources.randomCompliment(),
|
||||
bonfires: [],
|
||||
bonfireHash: 'test'
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
exports.returnNextBonfire = function(req, res, next) {
|
||||
if (!req.user) {
|
||||
return res.redirect('../bonfires/meet-bonfire');
|
||||
}
|
||||
var completed = req.user.completedBonfires.map(function (elem) {
|
||||
return elem._id;
|
||||
});
|
||||
|
||||
req.user.uncompletedBonfires = resources.allBonfireIds().filter(function (elem) {
|
||||
if (completed.indexOf(elem) === -1) {
|
||||
return elem;
|
||||
}
|
||||
});
|
||||
req.user.save();
|
||||
|
||||
var uncompletedBonfires = req.user.uncompletedBonfires;
|
||||
|
||||
var displayedBonfires = Bonfire.find({'_id': uncompletedBonfires[0]});
|
||||
displayedBonfires.exec(function(err, bonfireFromMongo) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
var bonfire = bonfireFromMongo.pop();
|
||||
if (typeof bonfire === 'undefined') {
|
||||
req.flash('errors', {
|
||||
msg: "It looks like you've completed all the bonfires we have available. Good job!"
|
||||
});
|
||||
return res.redirect('../bonfires/meet-bonfire');
|
||||
}
|
||||
var nameString = bonfire.name.toLowerCase().replace(/\s/g, '-');
|
||||
return res.redirect('../bonfires/' + nameString);
|
||||
});
|
||||
};
|
||||
|
||||
exports.returnIndividualBonfire = function(req, res, next) {
|
||||
var dashedName = req.params.bonfireName;
|
||||
|
||||
var bonfireName = dashedName.replace(/\-/g, ' ');
|
||||
|
||||
Bonfire.find({'name': new RegExp(bonfireName, 'i')}, function(err, bonfireFromMongo) {
|
||||
if (err) {
|
||||
next(err);
|
||||
}
|
||||
|
||||
|
||||
if (bonfireFromMongo.length < 1) {
|
||||
req.flash('errors', {
|
||||
msg: "404: We couldn't find a bonfire with that name. Please double check the name."
|
||||
});
|
||||
|
||||
return res.redirect('/bonfires');
|
||||
}
|
||||
|
||||
var bonfire = bonfireFromMongo.pop();
|
||||
var dashedNameFull = bonfire.name.toLowerCase().replace(/\s/g, '-');
|
||||
if (dashedNameFull !== dashedName) {
|
||||
return res.redirect('../bonfires/' + dashedNameFull);
|
||||
}
|
||||
res.render('bonfire/show', {
|
||||
completedWith: null,
|
||||
title: bonfire.name,
|
||||
dashedName: dashedName,
|
||||
name: bonfire.name,
|
||||
difficulty: Math.floor(+bonfire.difficulty),
|
||||
brief: bonfire.description.shift(),
|
||||
details: bonfire.description,
|
||||
tests: bonfire.tests,
|
||||
challengeSeed: bonfire.challengeSeed,
|
||||
points: req.user ? req.user.points : undefined,
|
||||
verb: resources.randomVerb(),
|
||||
phrase: resources.randomPhrase(),
|
||||
compliment: resources.randomCompliment(),
|
||||
bonfires: bonfire,
|
||||
bonfireHash: bonfire._id,
|
||||
MDNkeys: bonfire.MDNlinks,
|
||||
MDNlinks: getMDNlinks(bonfire.MDNlinks)
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Bonfire Generator
|
||||
* @param req Request Object
|
||||
* @param res Response Object
|
||||
* @returns void
|
||||
*/
|
||||
|
||||
exports.returnGenerator = function(req, res) {
|
||||
res.render('bonfire/generator', {
|
||||
title: null,
|
||||
name: null,
|
||||
difficulty: null,
|
||||
brief: null,
|
||||
details: null,
|
||||
tests: null,
|
||||
challengeSeed: null,
|
||||
bonfireHash: randomString()
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Post for bonfire generation
|
||||
*/
|
||||
|
||||
function randomString() {
|
||||
var chars = '0123456789abcdef';
|
||||
var string_length = 23;
|
||||
var randomstring = 'a';
|
||||
for (var i = 0; i < string_length; i++) {
|
||||
var rnum = Math.floor(Math.random() * chars.length);
|
||||
randomstring += chars.substring(rnum, rnum + 1);
|
||||
}
|
||||
return randomstring;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to populate the MDN links array.
|
||||
*/
|
||||
|
||||
function getMDNlinks(links) {
|
||||
// takes in an array of links, which are strings
|
||||
var populatedLinks = [];
|
||||
|
||||
// for each key value, push the corresponding link from the MDNlinks object into a new array
|
||||
links.forEach(function(value, index) {
|
||||
populatedLinks.push(MDNlinks[value]);
|
||||
});
|
||||
|
||||
return populatedLinks;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
exports.testBonfire = function(req, res) {
|
||||
var bonfireName = req.body.name,
|
||||
bonfireTests = req.body.tests,
|
||||
bonfireDifficulty = req.body.difficulty,
|
||||
bonfireDescription = req.body.description,
|
||||
bonfireChallengeSeed = req.body.challengeSeed;
|
||||
bonfireTests = bonfireTests.split('\r\n');
|
||||
bonfireDescription = bonfireDescription.split('\r\n');
|
||||
bonfireTests.filter(getRidOfEmpties);
|
||||
bonfireDescription.filter(getRidOfEmpties);
|
||||
bonfireChallengeSeed = bonfireChallengeSeed.replace('\r', '');
|
||||
|
||||
res.render('bonfire/show', {
|
||||
completedWith: null,
|
||||
title: bonfireName,
|
||||
name: bonfireName,
|
||||
difficulty: +bonfireDifficulty,
|
||||
brief: bonfireDescription[0],
|
||||
details: bonfireDescription.slice(1),
|
||||
tests: bonfireTests,
|
||||
challengeSeed: bonfireChallengeSeed,
|
||||
cc: req.user ? req.user.bonfiresHash : undefined,
|
||||
progressTimestamps: req.user ? req.user.progressTimestamps : undefined,
|
||||
verb: resources.randomVerb(),
|
||||
phrase: resources.randomPhrase(),
|
||||
compliment: resources.randomCompliment(),
|
||||
bonfires: [],
|
||||
bonfireHash: 'test'
|
||||
});
|
||||
};
|
||||
|
||||
function getRidOfEmpties(elem) {
|
||||
if (elem.length > 0) {
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
|
||||
exports.publicGenerator = function(req, res) {
|
||||
res.render('bonfire/public-generator');
|
||||
};
|
||||
|
||||
exports.generateChallenge = function(req, res) {
|
||||
var bonfireName = req.body.name,
|
||||
bonfireTests = req.body.tests,
|
||||
bonfireDifficulty = req.body.difficulty,
|
||||
bonfireDescription = req.body.description,
|
||||
bonfireChallengeSeed = req.body.challengeSeed;
|
||||
bonfireTests = bonfireTests.split('\r\n');
|
||||
bonfireDescription = bonfireDescription.split('\r\n');
|
||||
bonfireTests.filter(getRidOfEmpties);
|
||||
bonfireDescription.filter(getRidOfEmpties);
|
||||
bonfireChallengeSeed = bonfireChallengeSeed.replace('\r', '');
|
||||
|
||||
|
||||
var response = {
|
||||
_id: randomString(),
|
||||
name: bonfireName,
|
||||
difficulty: bonfireDifficulty,
|
||||
description: bonfireDescription,
|
||||
challengeSeed: bonfireChallengeSeed,
|
||||
tests: bonfireTests
|
||||
};
|
||||
res.send(response);
|
||||
};
|
||||
|
||||
exports.completedBonfire = function (req, res, next) {
|
||||
var isCompletedWith = req.body.bonfireInfo.completedWith || '';
|
||||
var isCompletedDate = Math.round(+new Date());
|
||||
var bonfireHash = req.body.bonfireInfo.bonfireHash;
|
||||
var isSolution = req.body.bonfireInfo.solution;
|
||||
var bonfireName = req.body.bonfireInfo.bonfireName;
|
||||
|
||||
if (isCompletedWith) {
|
||||
var paired = User.find({'profile.username': isCompletedWith
|
||||
.toLowerCase()}).limit(1);
|
||||
paired.exec(function (err, pairedWith) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
} else {
|
||||
var index = req.user.uncompletedBonfires.indexOf(bonfireHash);
|
||||
if (index > -1) {
|
||||
req.user.progressTimestamps.push(Date.now() || 0);
|
||||
req.user.uncompletedBonfires.splice(index, 1);
|
||||
}
|
||||
pairedWith = pairedWith.pop();
|
||||
|
||||
index = pairedWith.uncompletedBonfires.indexOf(bonfireHash);
|
||||
if (index > -1) {
|
||||
pairedWith.progressTimestamps.push(Date.now() || 0);
|
||||
pairedWith.uncompletedBonfires.splice(index, 1);
|
||||
|
||||
}
|
||||
|
||||
pairedWith.completedBonfires.push({
|
||||
_id: bonfireHash,
|
||||
name: bonfireName,
|
||||
completedWith: req.user._id,
|
||||
completedDate: isCompletedDate,
|
||||
solution: isSolution
|
||||
});
|
||||
|
||||
req.user.completedBonfires.push({
|
||||
_id: bonfireHash,
|
||||
name: bonfireName,
|
||||
completedWith: pairedWith._id,
|
||||
completedDate: isCompletedDate,
|
||||
solution: isSolution
|
||||
});
|
||||
|
||||
req.user.save(function (err, user) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
pairedWith.save(function (err, paired) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
if (user && paired) {
|
||||
res.send(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
req.user.completedBonfires.push({
|
||||
_id: bonfireHash,
|
||||
name: bonfireName,
|
||||
completedWith: null,
|
||||
completedDate: isCompletedDate,
|
||||
solution: isSolution
|
||||
});
|
||||
|
||||
var index = req.user.uncompletedBonfires.indexOf(bonfireHash);
|
||||
if (index > -1) {
|
||||
|
||||
req.user.progressTimestamps.push(Date.now() || 0);
|
||||
req.user.uncompletedBonfires.splice(index, 1);
|
||||
}
|
||||
|
||||
req.user.save(function (err, user) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
if (user) {
|
||||
res.send(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
555
controllers/challenge.js
Normal file
555
controllers/challenge.js
Normal file
@ -0,0 +1,555 @@
|
||||
/**
|
||||
* Created by nathanleniz on 5/15/15.
|
||||
* Copyright (c) 2015, Free Code Camp
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
|
||||
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
var R = require('ramda'),
|
||||
Challenge = require('./../models/Challenge'),
|
||||
User = require('./../models/User'),
|
||||
resources = require('./resources'),
|
||||
MDNlinks = require('./../seed_data/bonfireMDNlinks');
|
||||
|
||||
var challengeMapWithNames = resources.getChallengeMapWithNames();
|
||||
var challengeMapWithIds = resources.getChallengeMapWithIds();
|
||||
|
||||
function getMDNlinks(links) {
|
||||
// takes in an array of links, which are strings
|
||||
var populatedLinks = [];
|
||||
|
||||
// for each key value, push the corresponding link
|
||||
// from the MDNlinks object into a new array
|
||||
if (links) {
|
||||
links.forEach(function (value) {
|
||||
populatedLinks.push(MDNlinks[value]);
|
||||
});
|
||||
}
|
||||
return populatedLinks;
|
||||
}
|
||||
|
||||
exports.returnNextChallenge = function(req, res, next) {
|
||||
if (!req.user) {
|
||||
return res.redirect('../challenges/learn-how-free-code-camp-works');
|
||||
}
|
||||
var completed = req.user.completedChallenges.map(function (elem) {
|
||||
return elem._id;
|
||||
});
|
||||
|
||||
req.user.uncompletedChallenges = resources.allChallengeIds()
|
||||
.filter(function (elem) {
|
||||
if (completed.indexOf(elem) === -1) {
|
||||
return elem;
|
||||
}
|
||||
});
|
||||
|
||||
// find the user's current challenge and block
|
||||
// look in that block and find the index of their current challenge
|
||||
// if index + 1 < block.challenges.length
|
||||
// serve index + 1 challenge
|
||||
// otherwise increment block key and serve the first challenge in that block
|
||||
// unless the next block is undefined, which means no next block
|
||||
var nextChallengeName;
|
||||
|
||||
var challengeId = String(req.user.currentChallenge.challengeId);
|
||||
var challengeBlock = req.user.currentChallenge.challengeBlock;
|
||||
var indexOfChallenge = challengeMapWithIds[challengeBlock]
|
||||
.indexOf(challengeId);
|
||||
|
||||
if (indexOfChallenge + 1
|
||||
< challengeMapWithIds[challengeBlock].length) {
|
||||
nextChallengeName =
|
||||
challengeMapWithNames[challengeBlock][++indexOfChallenge];
|
||||
} else if (typeof challengeMapWithIds[++challengeBlock] !== 'undefined') {
|
||||
nextChallengeName = R.head(challengeMapWithNames[challengeBlock]);
|
||||
} else {
|
||||
req.flash('errors', {
|
||||
msg: 'It looks like you have finished all of our challenges.' +
|
||||
' Great job! Now on to helping nonprofits!'
|
||||
});
|
||||
nextChallengeName = R.head(challengeMapWithNames[0].challenges);
|
||||
}
|
||||
|
||||
var nameString = nextChallengeName.trim()
|
||||
.toLowerCase()
|
||||
.replace(/\s/g, '-');
|
||||
|
||||
req.user.save(function(err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
return res.redirect('../challenges/' + nameString);
|
||||
});
|
||||
};
|
||||
|
||||
exports.returnCurrentChallenge = function(req, res, next) {
|
||||
if (!req.user) {
|
||||
return res.redirect('../challenges/learn-how-free-code-camp-works');
|
||||
}
|
||||
var completed = req.user.completedChallenges.map(function (elem) {
|
||||
return elem._id;
|
||||
});
|
||||
|
||||
req.user.uncompletedChallenges = resources.allChallengeIds()
|
||||
.filter(function (elem) {
|
||||
if (completed.indexOf(elem) === -1) {
|
||||
return elem;
|
||||
}
|
||||
});
|
||||
if (!req.user.currentChallenge) {
|
||||
req.user.currentChallenge = {};
|
||||
req.user.currentChallenge.challengeId = challengeMapWithIds['0'][0];
|
||||
req.user.currentChallenge.challengeName = challengeMapWithNames['0'][0];
|
||||
req.user.currentChallenge.challengeBlock = '0';
|
||||
req.user.save(function(err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
return res.redirect('../challenges/learn-how-free-code-camp-works');
|
||||
});
|
||||
}
|
||||
var nameString = req.user.currentChallenge.challengeName.trim()
|
||||
.toLowerCase()
|
||||
.replace(/\s/g, '-')
|
||||
.replace(/[^a-z0-9\-\/.]/gi, '');
|
||||
req.user.save(function(err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
return res.redirect('../challenges/' + nameString);
|
||||
});
|
||||
};
|
||||
|
||||
exports.returnIndividualChallenge = function(req, res, next) {
|
||||
var dashedName = req.params.challengeName;
|
||||
|
||||
var challengeName = dashedName.replace(/\-/g, ' ')
|
||||
.split(' ')
|
||||
.slice(1)
|
||||
.join(' ');
|
||||
|
||||
Challenge.find({'name': new RegExp(challengeName, 'i')},
|
||||
function(err, challengeFromMongo) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
// Handle not found
|
||||
if (challengeFromMongo.length < 1) {
|
||||
req.flash('errors', {
|
||||
msg: '404: We couldn\'t find a challenge with that name. ' +
|
||||
'Please double check the name.'
|
||||
});
|
||||
return res.redirect('/challenges');
|
||||
}
|
||||
var challenge = challengeFromMongo.pop();
|
||||
// Redirect to full name if the user only entered a partial
|
||||
var dashedNameFull = challenge.name
|
||||
.toLowerCase()
|
||||
.replace(/\s/g, '-')
|
||||
.replace(/[^a-z0-9\-\.]/gi, '');
|
||||
if (dashedNameFull !== dashedName) {
|
||||
return res.redirect('../challenges/' + dashedNameFull);
|
||||
} else {
|
||||
if (req.user) {
|
||||
req.user.currentChallenge = {
|
||||
challengeId: challenge._id,
|
||||
challengeName: challenge.name,
|
||||
challengeBlock: R.head(R.flatten(Object.keys(challengeMapWithIds).
|
||||
map(function (key) {
|
||||
return challengeMapWithIds[key]
|
||||
.filter(function (elem) {
|
||||
return String(elem) === String(challenge._id);
|
||||
}).map(function () {
|
||||
return key;
|
||||
});
|
||||
})
|
||||
))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var challengeType = {
|
||||
0: function() {
|
||||
res.render('coursewares/showHTML', {
|
||||
title: challenge.name,
|
||||
dashedName: dashedName,
|
||||
name: challenge.name,
|
||||
brief: challenge.description[0],
|
||||
details: challenge.description.slice(1),
|
||||
tests: challenge.tests,
|
||||
challengeSeed: challenge.challengeSeed,
|
||||
verb: resources.randomVerb(),
|
||||
phrase: resources.randomPhrase(),
|
||||
compliment: resources.randomCompliment(),
|
||||
challengeId: challenge._id,
|
||||
environment: resources.whichEnvironment(),
|
||||
challengeType: challenge.challengeType
|
||||
});
|
||||
},
|
||||
|
||||
1: function() {
|
||||
res.render('coursewares/showJS', {
|
||||
title: challenge.name,
|
||||
dashedName: dashedName,
|
||||
name: challenge.name,
|
||||
brief: challenge.description[0],
|
||||
details: challenge.description.slice(1),
|
||||
tests: challenge.tests,
|
||||
challengeSeed: challenge.challengeSeed,
|
||||
verb: resources.randomVerb(),
|
||||
phrase: resources.randomPhrase(),
|
||||
compliment: resources.randomCompliment(),
|
||||
challengeId: challenge._id,
|
||||
challengeType: challenge.challengeType
|
||||
});
|
||||
},
|
||||
|
||||
2: function() {
|
||||
res.render('coursewares/showVideo', {
|
||||
title: challenge.name,
|
||||
dashedName: dashedName,
|
||||
name: challenge.name,
|
||||
details: challenge.description,
|
||||
tests: challenge.tests,
|
||||
video: challenge.challengeSeed[0],
|
||||
verb: resources.randomVerb(),
|
||||
phrase: resources.randomPhrase(),
|
||||
compliment: resources.randomCompliment(),
|
||||
challengeId: challenge._id,
|
||||
challengeType: challenge.challengeType
|
||||
});
|
||||
},
|
||||
|
||||
3: function() {
|
||||
res.render('coursewares/showZiplineOrBasejump', {
|
||||
title: challenge.name,
|
||||
dashedName: dashedName,
|
||||
name: challenge.name,
|
||||
details: challenge.description,
|
||||
video: challenge.challengeSeed[0],
|
||||
verb: resources.randomVerb(),
|
||||
phrase: resources.randomPhrase(),
|
||||
compliment: resources.randomCompliment(),
|
||||
challengeId: challenge._id,
|
||||
challengeType: challenge.challengeType
|
||||
});
|
||||
},
|
||||
|
||||
4: function() {
|
||||
res.render('coursewares/showZiplineOrBasejump', {
|
||||
title: challenge.name,
|
||||
dashedName: dashedName,
|
||||
name: challenge.name,
|
||||
details: challenge.description,
|
||||
video: challenge.challengeSeed[0],
|
||||
verb: resources.randomVerb(),
|
||||
phrase: resources.randomPhrase(),
|
||||
compliment: resources.randomCompliment(),
|
||||
challengeId: challenge._id,
|
||||
challengeType: challenge.challengeType
|
||||
});
|
||||
},
|
||||
|
||||
5: function() {
|
||||
res.render('coursewares/showBonfire', {
|
||||
completedWith: null,
|
||||
title: challenge.name,
|
||||
dashedName: dashedName,
|
||||
name: challenge.name,
|
||||
difficulty: Math.floor(+challenge.difficulty),
|
||||
brief: challenge.description.shift(),
|
||||
details: challenge.description,
|
||||
tests: challenge.tests,
|
||||
challengeSeed: challenge.challengeSeed,
|
||||
verb: resources.randomVerb(),
|
||||
phrase: resources.randomPhrase(),
|
||||
compliment: resources.randomCompliment(),
|
||||
bonfires: challenge,
|
||||
challengeId: challenge._id,
|
||||
MDNkeys: challenge.MDNlinks,
|
||||
MDNlinks: getMDNlinks(challenge.MDNlinks),
|
||||
challengeType: challenge.challengeType
|
||||
});
|
||||
}
|
||||
};
|
||||
if (req.user) {
|
||||
req.user.save(function (err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
return challengeType[challenge.challengeType]();
|
||||
});
|
||||
} else {
|
||||
return challengeType[challenge.challengeType]();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.completedBonfire = function (req, res, next) {
|
||||
var isCompletedWith = req.body.challengeInfo.completedWith || '';
|
||||
var isCompletedDate = Math.round(+new Date());
|
||||
var challengeId = req.body.challengeInfo.challengeId;
|
||||
var isSolution = req.body.challengeInfo.solution;
|
||||
var challengeName = req.body.challengeInfo.challengeName;
|
||||
|
||||
if (isCompletedWith) {
|
||||
var paired = User.find({'profile.username': isCompletedWith.toLowerCase()})
|
||||
.limit(1);
|
||||
paired.exec(function (err, pairedWith) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
} else {
|
||||
var index = req.user.uncompletedChallenges.indexOf(challengeId);
|
||||
if (index > -1) {
|
||||
req.user.progressTimestamps.push(Date.now() || 0);
|
||||
req.user.uncompletedChallenges.splice(index, 1);
|
||||
}
|
||||
pairedWith = pairedWith.pop();
|
||||
if (pairedWith) {
|
||||
|
||||
index = pairedWith.uncompletedChallenges.indexOf(challengeId);
|
||||
if (index > -1) {
|
||||
pairedWith.progressTimestamps.push(Date.now() || 0);
|
||||
pairedWith.uncompletedChallenges.splice(index, 1);
|
||||
|
||||
}
|
||||
|
||||
pairedWith.completedChallenges.push({
|
||||
_id: challengeId,
|
||||
name: challengeName,
|
||||
completedWith: req.user._id,
|
||||
completedDate: isCompletedDate,
|
||||
solution: isSolution,
|
||||
challengeType: 5
|
||||
});
|
||||
|
||||
req.user.completedChallenges.push({
|
||||
_id: challengeId,
|
||||
name: challengeName,
|
||||
completedWith: pairedWith._id,
|
||||
completedDate: isCompletedDate,
|
||||
solution: isSolution,
|
||||
challengeType: 5
|
||||
});
|
||||
}
|
||||
// User said they paired, but pair wasn't found
|
||||
req.user.completedChallenges.push({
|
||||
_id: challengeId,
|
||||
name: challengeName,
|
||||
completedWith: null,
|
||||
completedDate: isCompletedDate,
|
||||
solution: isSolution,
|
||||
challengeType: 5
|
||||
});
|
||||
|
||||
|
||||
req.user.save(function (err, user) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
if (pairedWith) {
|
||||
pairedWith.save(function (err, paired) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
if (user && paired) {
|
||||
res.send(true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (user) {
|
||||
res.send(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
req.user.completedChallenges.push({
|
||||
_id: challengeId,
|
||||
name: challengeName,
|
||||
completedWith: null,
|
||||
completedDate: isCompletedDate,
|
||||
solution: isSolution,
|
||||
challengeType: 5
|
||||
});
|
||||
|
||||
var index = req.user.uncompletedChallenges.indexOf(challengeId);
|
||||
if (index > -1) {
|
||||
|
||||
req.user.progressTimestamps.push(Date.now() || 0);
|
||||
req.user.uncompletedChallenges.splice(index, 1);
|
||||
}
|
||||
|
||||
req.user.save(function (err, user) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
// NOTE(berks): Under certain conditions the res is never ended
|
||||
if (user) {
|
||||
res.send(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.completedChallenge = function (req, res, next) {
|
||||
|
||||
var isCompletedDate = Math.round(+new Date());
|
||||
var challengeId = req.body.challengeInfo.challengeId;
|
||||
|
||||
req.user.completedChallenges.push({
|
||||
_id: challengeId,
|
||||
completedDate: isCompletedDate,
|
||||
name: req.body.challengeInfo.challengeName,
|
||||
solution: null,
|
||||
githubLink: null,
|
||||
verified: true
|
||||
});
|
||||
var index = req.user.uncompletedChallenges.indexOf(challengeId);
|
||||
|
||||
if (index > -1) {
|
||||
req.user.progressTimestamps.push(Date.now() || 0);
|
||||
req.user.uncompletedChallenges.splice(index, 1);
|
||||
}
|
||||
|
||||
req.user.save(function (err, user) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
if (user) {
|
||||
res.sendStatus(200);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.completedZiplineOrBasejump = function (req, res, next) {
|
||||
|
||||
var isCompletedWith = req.body.challengeInfo.completedWith || false;
|
||||
var isCompletedDate = Math.round(+new Date());
|
||||
var challengeId = req.body.challengeInfo.challengeId;
|
||||
var solutionLink = req.body.challengeInfo.publicURL;
|
||||
var githubLink = req.body.challengeInfo.challengeType === '4'
|
||||
? req.body.challengeInfo.githubURL : true;
|
||||
if (!solutionLink || !githubLink) {
|
||||
req.flash('errors', {
|
||||
msg: 'You haven\'t supplied the necessary URLs for us to inspect ' +
|
||||
'your work.'
|
||||
});
|
||||
return res.sendStatus(403);
|
||||
}
|
||||
|
||||
if (isCompletedWith) {
|
||||
var paired = User.find({'profile.username': isCompletedWith.toLowerCase()})
|
||||
.limit(1);
|
||||
|
||||
paired.exec(function (err, pairedWithFromMongo) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
} else {
|
||||
var index = req.user.uncompletedChallenges.indexOf(challengeId);
|
||||
if (index > -1) {
|
||||
req.user.progressTimestamps.push(Date.now() || 0);
|
||||
req.user.uncompletedChallenges.splice(index, 1);
|
||||
}
|
||||
var pairedWith = pairedWithFromMongo.pop();
|
||||
|
||||
req.user.completedChallenges.push({
|
||||
_id: challengeId,
|
||||
name: req.body.challengeInfo.challengeName,
|
||||
completedWith: pairedWith._id,
|
||||
completedDate: isCompletedDate,
|
||||
solution: solutionLink,
|
||||
githubLink: githubLink,
|
||||
verified: false
|
||||
});
|
||||
|
||||
req.user.save(function (err, user) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
if (req.user._id.toString() === pairedWith._id.toString()) {
|
||||
return res.sendStatus(200);
|
||||
}
|
||||
index = pairedWith.uncompletedChallenges.indexOf(challengeId);
|
||||
if (index > -1) {
|
||||
pairedWith.progressTimestamps.push(Date.now() || 0);
|
||||
pairedWith.uncompletedChallenges.splice(index, 1);
|
||||
|
||||
}
|
||||
|
||||
pairedWith.completedChallenges.push({
|
||||
_id: challengeId,
|
||||
name: req.body.challengeInfo.coursewareName,
|
||||
completedWith: req.user._id,
|
||||
completedDate: isCompletedDate,
|
||||
solution: solutionLink,
|
||||
githubLink: githubLink,
|
||||
verified: false
|
||||
});
|
||||
pairedWith.save(function (err, paired) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
if (user && paired) {
|
||||
return res.sendStatus(200);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
||||
req.user.completedChallenges.push({
|
||||
_id: challengeId,
|
||||
name: req.body.challengeInfo.challengeName,
|
||||
completedWith: null,
|
||||
completedDate: isCompletedDate,
|
||||
solution: solutionLink,
|
||||
githubLink: githubLink,
|
||||
verified: false
|
||||
});
|
||||
|
||||
var index = req.user.uncompletedChallenges.indexOf(challengeId);
|
||||
if (index > -1) {
|
||||
req.user.progressTimestamps.push(Date.now() || 0);
|
||||
req.user.uncompletedChallenges.splice(index, 1);
|
||||
}
|
||||
|
||||
req.user.save(function (err, user) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
// NOTE(berks): under certain conditions this will not close the response.
|
||||
if (user) {
|
||||
return res.sendStatus(200);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
@ -1,81 +1,53 @@
|
||||
var async = require('async'),
|
||||
User = require('../models/User'),
|
||||
Bonfire = require('./../models/Bonfire'),
|
||||
Story = require('./../models/Story'),
|
||||
Nonprofit = require('./../models/Nonprofit'),
|
||||
Comment = require('./../models/Comment'),
|
||||
Courseware = require('./../models/Courseware'),
|
||||
resources = require('./resources'),
|
||||
steps = resources.steps,
|
||||
secrets = require('./../config/secrets'),
|
||||
bonfires = require('../seed_data/bonfires.json'),
|
||||
nonprofits = require('../seed_data/nonprofits.json'),
|
||||
coursewares = require('../seed_data/coursewares.json'),
|
||||
moment = require('moment'),
|
||||
https = require('https'),
|
||||
debug = require('debug')('freecc:cntr:resources'),
|
||||
cheerio = require('cheerio'),
|
||||
request = require('request'),
|
||||
R = require('ramda');
|
||||
var R = require('ramda'),
|
||||
debug = require('debug')('freecc:cntr:challengeMap'),
|
||||
User = require('../models/User'),
|
||||
resources = require('./resources');
|
||||
|
||||
var challengeTypes = {
|
||||
'HTML_CSS_JQ': 0,
|
||||
'JAVASCRIPT': 1,
|
||||
'VIDEO': 2,
|
||||
'ZIPLINE': 3,
|
||||
'BASEJUMP': 4,
|
||||
'BONFIRE': 5
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
challengeMap: function challengeMap(req, res) {
|
||||
var completedBonfires = [];
|
||||
challengeMap: function challengeMap(req, res, next) {
|
||||
var completedList = [];
|
||||
|
||||
if (req.user) {
|
||||
completedBonfires = req.user.completedBonfires.map(function (elem) {
|
||||
return elem._id;
|
||||
});
|
||||
completedList = req.user.completedChallenges;
|
||||
}
|
||||
|
||||
if (req.user) {
|
||||
completedList = req.user.completedCoursewares.map(function (elem) {
|
||||
return elem._id;
|
||||
var noDuplicatedChallenges = R.uniq(completedList);
|
||||
|
||||
|
||||
var challengeList = resources.getChallengeMapForDisplay();
|
||||
var completedChallengeList = noDuplicatedChallenges
|
||||
.map(function(challenge) {
|
||||
return challenge._id;
|
||||
});
|
||||
}
|
||||
|
||||
var noDuplicateBonfires = R.uniq(completedBonfires);
|
||||
var noDuplicatedCoursewares = R.uniq(completedList);
|
||||
|
||||
bonfireList = resources.allBonfireNames();
|
||||
completedBonfireList = noDuplicateBonfires;
|
||||
coursewareList = resources.allCoursewareNames();
|
||||
completedCoursewareList = noDuplicatedCoursewares;
|
||||
waypoints = coursewareList.filter(function(challenge) {
|
||||
if (challenge.challengeType === 2) { return challenge }
|
||||
});
|
||||
ziplines = coursewareList.filter(function(challenge) {
|
||||
if (challenge.challengeType === 3) { return challenge }
|
||||
});
|
||||
basejumps = coursewareList.filter(function(challenge) {
|
||||
if (challenge.challengeType === 4) { return challenge }
|
||||
});
|
||||
|
||||
function numberWithCommas(x) {
|
||||
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
}
|
||||
|
||||
var date1 = new Date("10/15/2014");
|
||||
var date1 = new Date('10/15/2014');
|
||||
var date2 = new Date();
|
||||
var timeDiff = Math.abs(date2.getTime() - date1.getTime());
|
||||
var daysRunning = Math.ceil(timeDiff / (1000 * 3600 * 24));
|
||||
|
||||
User.count({}, function (err, camperCount) {
|
||||
if (err) {
|
||||
debug('User err: ', err);
|
||||
return next(err);
|
||||
}
|
||||
res.render('challengeMap/show', {
|
||||
daysRunning: daysRunning,
|
||||
camperCount: numberWithCommas(camperCount),
|
||||
title: "A map of all Free Code Camp's Challenges",
|
||||
bonfires: bonfireList,
|
||||
waypoints: waypoints,
|
||||
ziplines: ziplines,
|
||||
basejumps: basejumps,
|
||||
completedBonfireList: completedBonfireList,
|
||||
completedCoursewareList: completedCoursewareList
|
||||
challengeList: challengeList,
|
||||
completedChallengeList: completedChallengeList
|
||||
});
|
||||
});
|
||||
}
|
||||
|
3
controllers/constantStrings.json
Normal file
3
controllers/constantStrings.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"gitHubUserAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1521.3 Safari/537.36"
|
||||
}
|
@ -1,388 +0,0 @@
|
||||
var _ = require('lodash'),
|
||||
debug = require('debug')('freecc:cntr:courseware'),
|
||||
Courseware = require('./../models/Courseware'),
|
||||
User = require('./../models/User'),
|
||||
resources = require('./resources'),
|
||||
R = require('ramda'),
|
||||
moment = require('moment');
|
||||
|
||||
/**
|
||||
* Courseware controller
|
||||
*/
|
||||
|
||||
exports.showAllCoursewares = function(req, res) {
|
||||
var completedList = [];
|
||||
if(req.user) {
|
||||
completedList = req.user.completedCoursewares.map(function (elem) {
|
||||
return elem._id;
|
||||
});
|
||||
}
|
||||
var noDuplicatedCoursewares = R.uniq(completedList);
|
||||
var data = {};
|
||||
data.coursewareList = resources.allCoursewareNames();
|
||||
data.completedList = noDuplicatedCoursewares;
|
||||
res.send(data);
|
||||
};
|
||||
|
||||
exports.returnNextCourseware = function(req, res, next) {
|
||||
if (!req.user) {
|
||||
return res.redirect('../challenges/learn-how-free-code-camp-works');
|
||||
}
|
||||
if (req.user.finishedWaypoints && req.user.uncompletedBonfires.length > 0) {
|
||||
return res.redirect('../bonfires')
|
||||
}
|
||||
|
||||
var completed = req.user.completedCoursewares.map(function (elem) {
|
||||
return elem._id;
|
||||
});
|
||||
|
||||
req.user.uncompletedCoursewares = resources.allCoursewareIds()
|
||||
.filter(function (elem) {
|
||||
if (completed.indexOf(elem) === -1) {
|
||||
return elem;
|
||||
}
|
||||
});
|
||||
req.user.save();
|
||||
|
||||
var uncompletedCoursewares = req.user.uncompletedCoursewares[0];
|
||||
|
||||
|
||||
var displayedCoursewares = Courseware.find({'_id': uncompletedCoursewares});
|
||||
displayedCoursewares.exec(function(err, courseware) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
courseware = courseware.pop();
|
||||
if (typeof courseware === 'undefined') {
|
||||
req.flash('errors', {
|
||||
msg: "It looks like you've completed all the courses we have " +
|
||||
"available. Good job!"
|
||||
});
|
||||
return res.redirect('../challenges/learn-how-free-code-camp-works');
|
||||
}
|
||||
var nameString = courseware.name.toLowerCase().replace(/\s/g, '-');
|
||||
return res.redirect('../challenges/' + nameString);
|
||||
});
|
||||
};
|
||||
|
||||
exports.returnIndividualCourseware = function(req, res, next) {
|
||||
var dashedName = req.params.coursewareName;
|
||||
|
||||
var coursewareName = dashedName.replace(/\-/g, ' ');
|
||||
|
||||
Courseware.find({'name': new RegExp(coursewareName, 'i')},
|
||||
function(err, coursewareFromMongo) {
|
||||
if (err) {
|
||||
next(err);
|
||||
}
|
||||
// Handle not found
|
||||
if (coursewareFromMongo.length < 1) {
|
||||
req.flash('errors', {
|
||||
msg: "404: We couldn't find a challenge with that name. " +
|
||||
"Please double check the name."
|
||||
});
|
||||
return res.redirect('/challenges');
|
||||
}
|
||||
var courseware = coursewareFromMongo.pop();
|
||||
|
||||
// Redirect to full name if the user only entered a partial
|
||||
var dashedNameFull = courseware.name.toLowerCase().replace(/\s/g, '-');
|
||||
if (dashedNameFull !== dashedName) {
|
||||
return res.redirect('../challenges/' + dashedNameFull);
|
||||
}
|
||||
|
||||
var challengeType = {
|
||||
0: function() {
|
||||
res.render('coursewares/showHTML', {
|
||||
title: courseware.name,
|
||||
dashedName: dashedName,
|
||||
name: courseware.name,
|
||||
brief: courseware.description[0],
|
||||
details: courseware.description.slice(1),
|
||||
tests: courseware.tests,
|
||||
challengeSeed: courseware.challengeSeed,
|
||||
verb: resources.randomVerb(),
|
||||
phrase: resources.randomPhrase(),
|
||||
compliment: resources.randomCompliment(),
|
||||
coursewareHash: courseware._id,
|
||||
environment: resources.whichEnvironment(),
|
||||
challengeType: courseware.challengeType
|
||||
});
|
||||
},
|
||||
|
||||
1: function() {
|
||||
res.render('coursewares/showJS', {
|
||||
title: courseware.name,
|
||||
dashedName: dashedName,
|
||||
name: courseware.name,
|
||||
brief: courseware.description[0],
|
||||
details: courseware.description.slice(1),
|
||||
tests: courseware.tests,
|
||||
challengeSeed: courseware.challengeSeed,
|
||||
verb: resources.randomVerb(),
|
||||
phrase: resources.randomPhrase(),
|
||||
compliment: resources.randomCompliment(),
|
||||
coursewareHash: courseware._id,
|
||||
challengeType: courseware.challengeType
|
||||
});
|
||||
},
|
||||
|
||||
2: function() {
|
||||
res.render('coursewares/showVideo', {
|
||||
title: courseware.name,
|
||||
dashedName: dashedName,
|
||||
name: courseware.name,
|
||||
details: courseware.description,
|
||||
tests: courseware.tests,
|
||||
video: courseware.challengeSeed[0],
|
||||
verb: resources.randomVerb(),
|
||||
phrase: resources.randomPhrase(),
|
||||
compliment: resources.randomCompliment(),
|
||||
coursewareHash: courseware._id,
|
||||
challengeType: courseware.challengeType
|
||||
});
|
||||
},
|
||||
|
||||
3: function() {
|
||||
res.render('coursewares/showZiplineOrBasejump', {
|
||||
title: courseware.name,
|
||||
dashedName: dashedName,
|
||||
name: courseware.name,
|
||||
details: courseware.description,
|
||||
video: courseware.challengeSeed[0],
|
||||
verb: resources.randomVerb(),
|
||||
phrase: resources.randomPhrase(),
|
||||
compliment: resources.randomCompliment(),
|
||||
coursewareHash: courseware._id,
|
||||
challengeType: courseware.challengeType
|
||||
});
|
||||
},
|
||||
|
||||
4: function() {
|
||||
res.render('coursewares/showZiplineOrBasejump', {
|
||||
title: courseware.name,
|
||||
dashedName: dashedName,
|
||||
name: courseware.name,
|
||||
details: courseware.description,
|
||||
video: courseware.challengeSeed[0],
|
||||
verb: resources.randomVerb(),
|
||||
phrase: resources.randomPhrase(),
|
||||
compliment: resources.randomCompliment(),
|
||||
coursewareHash: courseware._id,
|
||||
challengeType: courseware.challengeType
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return challengeType[courseware.challengeType]();
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
exports.testCourseware = function(req, res) {
|
||||
var coursewareName = req.body.name,
|
||||
coursewareTests = req.body.tests,
|
||||
coursewareDifficulty = req.body.difficulty,
|
||||
coursewareDescription = req.body.description,
|
||||
coursewareEntryPoint = req.body.challengeEntryPoint,
|
||||
coursewareChallengeSeed = req.body.challengeSeed;
|
||||
coursewareTests = coursewareTests.split('\r\n');
|
||||
coursewareDescription = coursewareDescription.split('\r\n');
|
||||
coursewareTests.filter(getRidOfEmpties);
|
||||
coursewareDescription.filter(getRidOfEmpties);
|
||||
coursewareChallengeSeed = coursewareChallengeSeed.replace('\r', '');
|
||||
res.render('courseware/show', {
|
||||
completedWith: null,
|
||||
title: coursewareName,
|
||||
name: coursewareName,
|
||||
difficulty: +coursewareDifficulty,
|
||||
brief: coursewareDescription[0],
|
||||
details: coursewareDescription.slice(1),
|
||||
tests: coursewareTests,
|
||||
challengeSeed: coursewareChallengeSeed,
|
||||
challengeEntryPoint: coursewareEntryPoint,
|
||||
cc: req.user ? req.user.coursewaresHash : undefined,
|
||||
progressTimestamps: req.user ? req.user.progressTimestamps : undefined,
|
||||
verb: resources.randomVerb(),
|
||||
phrase: resources.randomPhrase(),
|
||||
compliment: resources.randomCompliment(),
|
||||
coursewares: [],
|
||||
coursewareHash: 'test'
|
||||
});
|
||||
};
|
||||
|
||||
function getRidOfEmpties(elem) {
|
||||
if (elem.length > 0) {
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
|
||||
exports.publicGenerator = function(req, res) {
|
||||
res.render('courseware/public-generator');
|
||||
};
|
||||
|
||||
exports.generateChallenge = function(req, res) {
|
||||
var coursewareName = req.body.name,
|
||||
coursewareTests = req.body.tests,
|
||||
coursewareDifficulty = req.body.difficulty,
|
||||
coursewareDescription = req.body.description,
|
||||
coursewareEntryPoint = req.body.challengeEntryPoint,
|
||||
coursewareChallengeSeed = req.body.challengeSeed;
|
||||
coursewareTests = coursewareTests.split('\r\n');
|
||||
coursewareDescription = coursewareDescription.split('\r\n');
|
||||
coursewareTests.filter(getRidOfEmpties);
|
||||
coursewareDescription.filter(getRidOfEmpties);
|
||||
coursewareChallengeSeed = coursewareChallengeSeed.replace('\r', '');
|
||||
|
||||
var response = {
|
||||
_id: randomString(),
|
||||
name: coursewareName,
|
||||
difficulty: coursewareDifficulty,
|
||||
description: coursewareDescription,
|
||||
challengeEntryPoint: coursewareEntryPoint,
|
||||
challengeSeed: coursewareChallengeSeed,
|
||||
tests: coursewareTests
|
||||
};
|
||||
res.send(response);
|
||||
};
|
||||
|
||||
exports.completedCourseware = function (req, res, next) {
|
||||
|
||||
var isCompletedDate = Math.round(+new Date());
|
||||
var coursewareHash = req.body.coursewareInfo.coursewareHash;
|
||||
if (coursewareHash === "bd7139d8c441eddfaeb5bdef") {
|
||||
req.user.finishedWaypoints = true;
|
||||
}
|
||||
|
||||
req.user.completedCoursewares.push({
|
||||
_id: coursewareHash,
|
||||
completedDate: isCompletedDate,
|
||||
name: req.body.coursewareInfo.coursewareName,
|
||||
solution: null,
|
||||
githubLink: null,
|
||||
verified: true
|
||||
});
|
||||
var index = req.user.uncompletedCoursewares.indexOf(coursewareHash);
|
||||
|
||||
if (index > -1) {
|
||||
req.user.progressTimestamps.push(Date.now() || 0);
|
||||
req.user.uncompletedCoursewares.splice(index, 1);
|
||||
}
|
||||
|
||||
req.user.save(function (err, user) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
if (user) {
|
||||
res.sendStatus(200);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.completedZiplineOrBasejump = function (req, res, next) {
|
||||
debug('Inside controller for completed zipline or basejump with data %s',
|
||||
req.body.coursewareInfo);
|
||||
var isCompletedWith = req.body.coursewareInfo.completedWith || false;
|
||||
var isCompletedDate = Math.round(+new Date());
|
||||
var coursewareHash = req.body.coursewareInfo.coursewareHash;
|
||||
var solutionLink = req.body.coursewareInfo.publicURL;
|
||||
var githubLink = req.body.coursewareInfo.challengeType === '4'
|
||||
? req.body.coursewareInfo.githubURL : true;
|
||||
if (!solutionLink || !githubLink) {
|
||||
req.flash('errors', {
|
||||
msg: 'You haven\'t supplied the necessary URLs for us to inspect ' +
|
||||
'your work.'
|
||||
});
|
||||
return res.sendStatus(403);
|
||||
}
|
||||
|
||||
if (isCompletedWith) {
|
||||
var paired = User.find({'profile.username': isCompletedWith.toLowerCase()}).limit(1);
|
||||
paired.exec(function (err, pairedWithFromMongo) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
} else {
|
||||
var index = req.user.uncompletedCoursewares.indexOf(coursewareHash);
|
||||
if (index > -1) {
|
||||
req.user.progressTimestamps.push(Date.now() || 0);
|
||||
req.user.uncompletedCoursewares.splice(index, 1);
|
||||
}
|
||||
var pairedWith = pairedWithFromMongo.pop();
|
||||
|
||||
req.user.completedCoursewares.push({
|
||||
_id: coursewareHash,
|
||||
name: req.body.coursewareInfo.coursewareName,
|
||||
completedWith: pairedWith._id,
|
||||
completedDate: isCompletedDate,
|
||||
solution: solutionLink,
|
||||
githubLink: githubLink,
|
||||
verified: false
|
||||
});
|
||||
|
||||
req.user.save(function (err, user) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
debug('this is the user object returned %s,' +
|
||||
' this is the req.user._id %s, ' +
|
||||
'this is the pairedWith._id %s', user, req.user._id, pairedWith._id);
|
||||
debug(req.user._id.toString() === pairedWith._id.toString());
|
||||
if (req.user._id.toString() === pairedWith._id.toString()) {
|
||||
return res.sendStatus(200);
|
||||
}
|
||||
index = pairedWith.uncompletedCoursewares.indexOf(coursewareHash);
|
||||
if (index > -1) {
|
||||
pairedWith.progressTimestamps.push(Date.now() || 0);
|
||||
pairedWith.uncompletedCoursewares.splice(index, 1);
|
||||
|
||||
}
|
||||
|
||||
pairedWith.completedCoursewares.push({
|
||||
_id: coursewareHash,
|
||||
name: req.body.coursewareInfo.coursewareName,
|
||||
completedWith: req.user._id,
|
||||
completedDate: isCompletedDate,
|
||||
solution: solutionLink,
|
||||
githubLink: githubLink,
|
||||
verified: false
|
||||
});
|
||||
pairedWith.save(function (err, paired) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
if (user && paired) {
|
||||
return res.sendStatus(200);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
||||
req.user.completedCoursewares.push({
|
||||
_id: coursewareHash,
|
||||
name: req.body.coursewareInfo.coursewareName,
|
||||
completedWith: null,
|
||||
completedDate: isCompletedDate,
|
||||
solution: solutionLink,
|
||||
githubLink: githubLink,
|
||||
verified: false
|
||||
});
|
||||
|
||||
var index = req.user.uncompletedCoursewares.indexOf(coursewareHash);
|
||||
if (index > -1) {
|
||||
req.user.progressTimestamps.push(Date.now() || 0);
|
||||
req.user.uncompletedCoursewares.splice(index, 1);
|
||||
}
|
||||
|
||||
req.user.save(function (err, user) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
if (user) {
|
||||
return res.sendStatus(200);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
@ -1,84 +1,102 @@
|
||||
var _ = require('lodash'),
|
||||
debug = require('debug')('freecc:cntr:fieldGuide'),
|
||||
var R = require('ramda'),
|
||||
FieldGuide = require('./../models/FieldGuide'),
|
||||
resources = require('./resources'),
|
||||
R = require('ramda');
|
||||
resources = require('./resources');
|
||||
|
||||
exports.returnIndividualFieldGuide = function(req, res, next) {
|
||||
var dashedName = req.params.fieldGuideName;
|
||||
var dashedName = req.params.fieldGuideName;
|
||||
|
||||
var fieldGuideName = dashedName.replace(/\-/g, ' ');
|
||||
var fieldGuideName = dashedName.replace(/\-/g, ' ')
|
||||
.replace(/[^a-z0-9\s]/gi, '');
|
||||
|
||||
if (req.user) {
|
||||
var completed = req.user.completedFieldGuides;
|
||||
if (req.user) {
|
||||
var completed = req.user.completedFieldGuides;
|
||||
|
||||
var uncompletedFieldGuides = resources.allFieldGuideIds().filter(function (elem) {
|
||||
var uncompletedFieldGuides = resources.allFieldGuideIds()
|
||||
.filter(function (elem) {
|
||||
if (completed.indexOf(elem) === -1) {
|
||||
return elem;
|
||||
}
|
||||
});
|
||||
req.user.uncompletedFieldGuides = uncompletedFieldGuides;
|
||||
req.user.save();
|
||||
}
|
||||
req.user.uncompletedFieldGuides = uncompletedFieldGuides;
|
||||
// TODO(berks): handle callback properly
|
||||
req.user.save();
|
||||
}
|
||||
|
||||
FieldGuide.find({'name': new RegExp(fieldGuideName, 'i')}, function(err, fieldGuideFromMongo) {
|
||||
if (err) {
|
||||
next(err);
|
||||
}
|
||||
FieldGuide.find(
|
||||
{ name: new RegExp(fieldGuideName, 'i') },
|
||||
function(err, fieldGuideFromMongo) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
if (fieldGuideFromMongo.length < 1) {
|
||||
req.flash('errors', {
|
||||
msg: "404: We couldn't find a field guide entry with that name. Please double check the name."
|
||||
});
|
||||
|
||||
return res.redirect('/field-guide');
|
||||
}
|
||||
|
||||
var fieldGuide = R.head(fieldGuideFromMongo);
|
||||
var dashedNameFull = fieldGuide.name.toLowerCase().replace(/\s/g, '-').replace(/\?/g, '');
|
||||
if (dashedNameFull !== dashedName) {
|
||||
return res.redirect('../field-guide/' + dashedNameFull);
|
||||
}
|
||||
res.render('field-guide/show', {
|
||||
title: fieldGuide.name,
|
||||
fieldGuideId: fieldGuide._id,
|
||||
description: fieldGuide.description.join('')
|
||||
if (fieldGuideFromMongo.length < 1) {
|
||||
req.flash('errors', {
|
||||
msg: "404: We couldn't find a field guide entry with that name. " +
|
||||
'Please double check the name.'
|
||||
});
|
||||
});
|
||||
|
||||
return res.redirect('/field-guide');
|
||||
}
|
||||
|
||||
var fieldGuide = R.head(fieldGuideFromMongo);
|
||||
var dashedNameFull =
|
||||
fieldGuide.name.toLowerCase()
|
||||
.replace(/\s/g, '-')
|
||||
.replace(/[^a-z0-9\-]/gi, '');
|
||||
|
||||
if (dashedNameFull !== dashedName) {
|
||||
return res.redirect('../field-guide/' + dashedNameFull);
|
||||
}
|
||||
res.render('field-guide/show', {
|
||||
title: fieldGuide.name,
|
||||
fieldGuideId: fieldGuide._id,
|
||||
description: fieldGuide.description.join('')
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
exports.showAllFieldGuides = function(req, res) {
|
||||
var data = {};
|
||||
data.fieldGuideList = resources.allFieldGuideNames();
|
||||
data.fieldGuideIds = resources.allFieldGuideIds();
|
||||
if (req.user && req.user.completedFieldGuides) {
|
||||
data.completedFieldGuides = req.user.completedFieldGuides;
|
||||
} else {
|
||||
data.completedFieldGuides = [];
|
||||
}
|
||||
res.send(data);
|
||||
var allFieldGuideNamesAndIds = resources.allFieldGuideNamesAndIds();
|
||||
|
||||
var completedFieldGuides = [];
|
||||
if (req.user && req.user.completedFieldGuides) {
|
||||
completedFieldGuides = req.user.completedFieldGuides;
|
||||
}
|
||||
res.render('field-guide/all-articles', {
|
||||
allFieldGuideNamesAndIds: allFieldGuideNamesAndIds,
|
||||
completedFieldGuides: completedFieldGuides
|
||||
});
|
||||
};
|
||||
|
||||
exports.returnNextFieldGuide = function(req, res, next) {
|
||||
if (!req.user) {
|
||||
return res.redirect('/field-guide/how-do-i-use-this-guide?');
|
||||
return res.redirect('/field-guide/how-do-i-use-this-guide');
|
||||
}
|
||||
|
||||
var displayedFieldGuides = FieldGuide.find({'_id': req.user.uncompletedFieldGuides[0]});
|
||||
var displayedFieldGuides =
|
||||
FieldGuide.find({'_id': req.user.uncompletedFieldGuides[0]});
|
||||
|
||||
displayedFieldGuides.exec(function(err, fieldGuide) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
if (err) { return next(err); }
|
||||
fieldGuide = fieldGuide.pop();
|
||||
|
||||
if (typeof fieldGuide === 'undefined') {
|
||||
if (req.user.completedFieldGuides.length > 0) {
|
||||
req.flash('success', {
|
||||
msg: "You've read all our current Field Guide entries. You can contribute to our Field Guide <a href='https://github.com/FreeCodeCamp/freecodecamp/blob/master/seed_data/field-guides.json'>here</a>."
|
||||
msg: [
|
||||
"You've read all our current Field Guide entries. You can ",
|
||||
'contribute to our Field Guide ',
|
||||
"<a href='https://github.com/FreeCodeCamp/freecodecamp/blob/",
|
||||
"staging/seed_data/field-guides.json'>here</a>."
|
||||
].join('')
|
||||
});
|
||||
}
|
||||
return res.redirect('../field-guide/how-do-i-use-this-guide?');
|
||||
return res.redirect('../field-guide/how-do-i-use-this-guide');
|
||||
}
|
||||
var nameString = fieldGuide.name.toLowerCase().replace(/\s/g, '-');
|
||||
var nameString = fieldGuide.name.toLowerCase()
|
||||
.replace(/\s/g, '-')
|
||||
.replace(/[^a-z0-9\-]/gi, '');
|
||||
return res.redirect('../field-guide/' + nameString);
|
||||
});
|
||||
};
|
||||
@ -94,12 +112,10 @@ exports.completedFieldGuide = function (req, res, next) {
|
||||
req.user.uncompletedFieldGuides.splice(index, 1);
|
||||
}
|
||||
|
||||
req.user.save(function (err, user) {
|
||||
req.user.save(function (err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
if (user) {
|
||||
res.send(true);
|
||||
}
|
||||
res.send(true);
|
||||
});
|
||||
};
|
||||
|
@ -1,16 +1,16 @@
|
||||
/**
|
||||
* GET /
|
||||
* Home page.
|
||||
*/
|
||||
var message =
|
||||
'Learn to Code JavaScript and get a Coding Job by Helping Nonprofits';
|
||||
|
||||
exports.index = function(req, res, next) {
|
||||
if (req.user && !req.user.profile.picture) {
|
||||
req.user.profile.picture = 'https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png';
|
||||
req.user.profile.picture =
|
||||
'https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png';
|
||||
|
||||
req.user.save(function(err) {
|
||||
if (err) { return next(err); }
|
||||
res.render('home', { title: message });
|
||||
});
|
||||
} else {
|
||||
res.render('home', { title: message });
|
||||
}
|
||||
res.render('home', {
|
||||
title: 'Learn to Code JavaScript and get a Coding Job by Helping Nonprofits'
|
||||
});
|
||||
};
|
||||
|
@ -1,16 +1,11 @@
|
||||
var async = require('async'),
|
||||
var moment = require('moment'),
|
||||
Nonprofit = require('./../models/Nonprofit'),
|
||||
resources = require('./resources'),
|
||||
secrets = require('./../config/secrets'),
|
||||
moment = require('moment'),
|
||||
debug = require('debug')('freecc:cntr:nonprofits'),
|
||||
R = require('ramda');
|
||||
resources = require('./resources');
|
||||
|
||||
exports.nonprofitsDirectory = function(req, res) {
|
||||
exports.nonprofitsDirectory = function(req, res, next) {
|
||||
Nonprofit.find({estimatedHours: { $gt: 0 } }, function(err, nonprofits) {
|
||||
if (err) {
|
||||
next(err);
|
||||
}
|
||||
if (err) { return next(err); }
|
||||
|
||||
res.render('nonprofits/directory', {
|
||||
title: 'Nonprofits we help',
|
||||
nonprofits: nonprofits
|
||||
@ -19,163 +14,197 @@ exports.nonprofitsDirectory = function(req, res) {
|
||||
};
|
||||
|
||||
exports.areYouWithARegisteredNonprofit = function(req, res) {
|
||||
res.render('nonprofits/are-you-with-a-registered-nonprofit', {
|
||||
title: 'Are you with a with a registered nonprofit',
|
||||
step: 1
|
||||
});
|
||||
res.render('nonprofits/are-you-with-a-registered-nonprofit', {
|
||||
title: 'Are you with a with a registered nonprofit',
|
||||
step: 1
|
||||
});
|
||||
};
|
||||
|
||||
exports.areTherePeopleThatAreAlreadyBenefitingFromYourServices = function(req, res) {
|
||||
res.render('nonprofits/are-there-people-that-are-already-benefiting-from-your-services', {
|
||||
exports.areTherePeopleThatAreAlreadyBenefitingFromYourServices =
|
||||
function(req, res) {
|
||||
res.render(
|
||||
'nonprofits/' +
|
||||
'are-there-people-that-are-already-benefiting-from-your-services',
|
||||
{
|
||||
title: 'Are there people already benefiting from your services',
|
||||
step: 2
|
||||
});
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
exports.okWithJavaScript = function(req, res) {
|
||||
res.render('nonprofits/ok-with-javascript', {
|
||||
title: 'Are you OK with us using JavaScript',
|
||||
step: 3
|
||||
});
|
||||
res.render('nonprofits/ok-with-javascript', {
|
||||
title: 'Are you OK with us using JavaScript',
|
||||
step: 3
|
||||
});
|
||||
};
|
||||
|
||||
exports.inExchangeWeAsk = function(req, res) {
|
||||
res.render('nonprofits/in-exchange-we-ask', {
|
||||
title: 'In exchange we ask that you ...',
|
||||
step: 4
|
||||
});
|
||||
res.render('nonprofits/in-exchange-we-ask', {
|
||||
title: 'In exchange we ask that you ...',
|
||||
step: 4
|
||||
});
|
||||
};
|
||||
|
||||
exports.howCanFreeCodeCampHelpYou = function(req, res) {
|
||||
res.render('nonprofits/how-can-free-code-camp-help-you', {
|
||||
title: 'Are you with a with a registered nonprofit',
|
||||
step: 5
|
||||
});
|
||||
res.render('nonprofits/how-can-free-code-camp-help-you', {
|
||||
title: 'Are you with a with a registered nonprofit',
|
||||
step: 5
|
||||
});
|
||||
};
|
||||
|
||||
exports.whatDoesYourNonprofitDo = function(req, res) {
|
||||
res.render('nonprofits/what-does-your-nonprofit-do', {
|
||||
existingParams: req.params,
|
||||
title: 'What does your nonprofit do?',
|
||||
step: 6
|
||||
});
|
||||
res.render('nonprofits/what-does-your-nonprofit-do', {
|
||||
existingParams: req.params,
|
||||
title: 'What does your nonprofit do?',
|
||||
step: 6
|
||||
});
|
||||
};
|
||||
|
||||
exports.linkUsToYourWebsite = function(req, res) {
|
||||
res.render('nonprofits/link-us-to-your-website', {
|
||||
title: 'Link us to your website',
|
||||
step: 7
|
||||
});
|
||||
res.render('nonprofits/link-us-to-your-website', {
|
||||
title: 'Link us to your website',
|
||||
step: 7
|
||||
});
|
||||
};
|
||||
|
||||
exports.tellUsYourEmail = function(req, res) {
|
||||
res.render('nonprofits/tell-us-your-email', {
|
||||
title: 'Tell us your email',
|
||||
step: 8
|
||||
});
|
||||
res.render('nonprofits/tell-us-your-email', {
|
||||
title: 'Tell us your email',
|
||||
step: 8
|
||||
});
|
||||
};
|
||||
|
||||
exports.tellUsYourName = function(req, res) {
|
||||
res.render('nonprofits/tell-us-your-name', {
|
||||
title: 'Tell us your name',
|
||||
step: 9
|
||||
});
|
||||
res.render('nonprofits/tell-us-your-name', {
|
||||
title: 'Tell us your name',
|
||||
step: 9
|
||||
});
|
||||
};
|
||||
|
||||
exports.yourNonprofitProjectApplicationHasBeenSubmitted = function(req, res) {
|
||||
res.render('nonprofits/your-nonprofit-project-application-has-been-submitted', {
|
||||
title: 'Your Nonprofit Project application has been submitted!',
|
||||
step: 10,
|
||||
getBackDay: moment().weekday(5).format('dddd')
|
||||
});
|
||||
res.render(
|
||||
'nonprofits/your-nonprofit-project-application-has-been-submitted',
|
||||
{
|
||||
title: 'Your Nonprofit Project application has been submitted!',
|
||||
step: 10,
|
||||
getBackDay: moment().weekday(5).format('dddd')
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
exports.otherSolutions = function(req, res) {
|
||||
res.render('nonprofits/other-solutions', {
|
||||
title: 'Here are some other possible solutions for you'
|
||||
});
|
||||
res.render('nonprofits/other-solutions', {
|
||||
title: 'Here are some other possible solutions for you'
|
||||
});
|
||||
};
|
||||
|
||||
exports.returnIndividualNonprofit = function(req, res, next) {
|
||||
var dashedName = req.params.nonprofitName;
|
||||
var dashedName = req.params.nonprofitName;
|
||||
var nonprofitName = dashedName.replace(/\-/g, ' ');
|
||||
|
||||
var nonprofitName = dashedName.replace(/\-/g, ' ');
|
||||
Nonprofit.find(
|
||||
{ name: new RegExp(nonprofitName, 'i') },
|
||||
function(err, nonprofit) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
Nonprofit.find({'name': new RegExp(nonprofitName, 'i')}, function(err, nonprofit) {
|
||||
if (err) {
|
||||
next(err);
|
||||
}
|
||||
if (nonprofit.length < 1) {
|
||||
req.flash('errors', {
|
||||
msg: "404: We couldn't find a nonprofit with that name. " +
|
||||
'Please double check the name.'
|
||||
});
|
||||
|
||||
if (nonprofit.length < 1) {
|
||||
req.flash('errors', {
|
||||
msg: "404: We couldn't find a nonprofit with that name. Please double check the name."
|
||||
});
|
||||
return res.redirect('/nonprofits');
|
||||
}
|
||||
|
||||
return res.redirect('/nonprofits');
|
||||
}
|
||||
|
||||
nonprofit = nonprofit.pop();
|
||||
var dashedNameFull = nonprofit.name.toLowerCase().replace(/\s/g, '-');
|
||||
if (dashedNameFull != dashedName) {
|
||||
return res.redirect('../nonprofit/' + dashedNameFull);
|
||||
}
|
||||
var buttonActive = false;
|
||||
if (req.user) {
|
||||
if (req.user.uncompletedBonfires.length === 0) {
|
||||
if (req.user.completedCoursewares.length > 63) {
|
||||
var hasShownInterest = nonprofit.interestedCampers.filter(function ( obj ) {
|
||||
nonprofit = nonprofit.pop();
|
||||
var dashedNameFull = nonprofit.name.toLowerCase().replace(/\s/g, '-');
|
||||
if (dashedNameFull !== dashedName) {
|
||||
return res.redirect('../nonprofit/' + dashedNameFull);
|
||||
}
|
||||
var buttonActive = false;
|
||||
if (req.user) {
|
||||
if (req.user.uncompletedBonfires.length === 0) {
|
||||
if (req.user.completedCoursewares.length > 63) {
|
||||
var hasShownInterest =
|
||||
nonprofit.interestedCampers.filter(function ( obj ) {
|
||||
return obj.username === req.user.profile.username;
|
||||
});
|
||||
if (hasShownInterest.length === 0) {
|
||||
buttonActive = true;
|
||||
}
|
||||
|
||||
if (hasShownInterest.length === 0) {
|
||||
buttonActive = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
res.render('nonprofits/show', {
|
||||
dashedName: dashedNameFull,
|
||||
title: nonprofit.name,
|
||||
logoUrl: nonprofit.logoUrl,
|
||||
estimatedHours: nonprofit.estimatedHours,
|
||||
projectDescription: nonprofit.projectDescription,
|
||||
approvedOther: nonprofit.approvedDeliverables.indexOf('other') > -1,
|
||||
approvedWebsite: nonprofit.approvedDeliverables.indexOf('website') > -1,
|
||||
approvedDonor: nonprofit.approvedDeliverables.indexOf('donor') > -1,
|
||||
approvedInventory: nonprofit.approvedDeliverables.indexOf('inventory') > -1,
|
||||
approvedVolunteer: nonprofit.approvedDeliverables.indexOf('volunteer') > -1,
|
||||
approvedForm: nonprofit.approvedDeliverables.indexOf('form') > -1,
|
||||
approvedCommunity: nonprofit.approvedDeliverables.indexOf('community') > -1,
|
||||
approvedELearning: nonprofit.approvedDeliverables.indexOf('eLearning') > -1,
|
||||
websiteLink: nonprofit.websiteLink,
|
||||
imageUrl: nonprofit.imageUrl,
|
||||
whatDoesNonprofitDo: nonprofit.whatDoesNonprofitDo,
|
||||
interestedCampers: nonprofit.interestedCampers,
|
||||
assignedCampers: nonprofit.assignedCampers,
|
||||
buttonActive: buttonActive,
|
||||
currentStatus: nonprofit.currentStatus
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
res.render('nonprofits/show', {
|
||||
dashedName: dashedNameFull,
|
||||
title: nonprofit.name,
|
||||
logoUrl: nonprofit.logoUrl,
|
||||
estimatedHours: nonprofit.estimatedHours,
|
||||
projectDescription: nonprofit.projectDescription,
|
||||
|
||||
approvedOther:
|
||||
nonprofit.approvedDeliverables.indexOf('other') > -1,
|
||||
approvedWebsite:
|
||||
nonprofit.approvedDeliverables.indexOf('website') > -1,
|
||||
|
||||
approvedDonor:
|
||||
nonprofit.approvedDeliverables.indexOf('donor') > -1,
|
||||
approvedInventory:
|
||||
nonprofit.approvedDeliverables.indexOf('inventory') > -1,
|
||||
|
||||
approvedVolunteer:
|
||||
nonprofit.approvedDeliverables.indexOf('volunteer') > -1,
|
||||
approvedForm:
|
||||
nonprofit.approvedDeliverables.indexOf('form') > -1,
|
||||
|
||||
approvedCommunity:
|
||||
nonprofit.approvedDeliverables.indexOf('community') > -1,
|
||||
approvedELearning:
|
||||
nonprofit.approvedDeliverables.indexOf('eLearning') > -1,
|
||||
|
||||
websiteLink: nonprofit.websiteLink,
|
||||
imageUrl: nonprofit.imageUrl,
|
||||
whatDoesNonprofitDo: nonprofit.whatDoesNonprofitDo,
|
||||
interestedCampers: nonprofit.interestedCampers,
|
||||
assignedCampers: nonprofit.assignedCampers,
|
||||
buttonActive: buttonActive,
|
||||
currentStatus: nonprofit.currentStatus
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
exports.showAllNonprofits = function(req, res) {
|
||||
var data = {};
|
||||
data.nonprofitsList = resources.allNonprofitNames();
|
||||
res.send(data);
|
||||
var data = {};
|
||||
data.nonprofitsList = resources.allNonprofitNames();
|
||||
res.send(data);
|
||||
};
|
||||
|
||||
exports.interestedInNonprofit = function(req, res) {
|
||||
exports.interestedInNonprofit = function(req, res, next) {
|
||||
if (req.user) {
|
||||
Nonprofit.findOne({name: new RegExp(req.params.nonprofitName.replace(/-/, ' '), 'i')}, function(err, nonprofit) {
|
||||
if (err) { return next(err); }
|
||||
nonprofit.interestedCampers.push({"username": req.user.profile.username,
|
||||
"picture": req.user.profile.picture,
|
||||
"timeOfInterest": Date.now()
|
||||
});
|
||||
nonprofit.save(function(err) {
|
||||
if (err) { return done(err); }
|
||||
req.flash('success', { msg: "Thanks for expressing interest in this nonprofit project! We've added you to this project as an interested camper!" });
|
||||
res.redirect('back');
|
||||
});
|
||||
});
|
||||
Nonprofit.findOne(
|
||||
{ name: new RegExp(req.params.nonprofitName.replace(/-/, ' '), 'i') },
|
||||
function(err, nonprofit) {
|
||||
if (err) { return next(err); }
|
||||
nonprofit.interestedCampers.push({
|
||||
username: req.user.profile.username,
|
||||
picture: req.user.profile.picture,
|
||||
timeOfInterest: Date.now()
|
||||
});
|
||||
nonprofit.save(function(err) {
|
||||
if (err) { return next(err); }
|
||||
req.flash('success', {
|
||||
msg: 'Thanks for expressing interest in this nonprofit project! ' +
|
||||
"We've added you to this project as an interested camper!"
|
||||
});
|
||||
res.redirect('back');
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
@ -1,32 +1,35 @@
|
||||
var async = require('async'),
|
||||
path = require('path'),
|
||||
moment = require('moment'),
|
||||
Twit = require('twit'),
|
||||
debug = require('debug')('freecc:cntr:resources'),
|
||||
cheerio = require('cheerio'),
|
||||
request = require('request'),
|
||||
R = require('ramda'),
|
||||
_ = require('lodash'),
|
||||
fs = require('fs'),
|
||||
|
||||
|
||||
constantStrings = require('./constantStrings.json'),
|
||||
User = require('../models/User'),
|
||||
Challenge = require('./../models/Challenge'),
|
||||
Courseware = require('./../models/Courseware'),
|
||||
Bonfire = require('./../models/Bonfire'),
|
||||
Story = require('./../models/Story'),
|
||||
FieldGuide = require('./../models/FieldGuide'),
|
||||
Nonprofit = require('./../models/Nonprofit'),
|
||||
Comment = require('./../models/Comment'),
|
||||
resources = require('./resources.json'),
|
||||
secrets = require('./../config/secrets'),
|
||||
bonfires = require('../seed_data/bonfires.json'),
|
||||
nonprofits = require('../seed_data/nonprofits.json'),
|
||||
coursewares = require('../seed_data/coursewares.json'),
|
||||
fieldGuides = require('../seed_data/field-guides.json'),
|
||||
moment = require('moment'),
|
||||
Twit = require('twit'),
|
||||
https = require('https'),
|
||||
debug = require('debug')('freecc:cntr:resources'),
|
||||
cheerio = require('cheerio'),
|
||||
request = require('request'),
|
||||
R = require('ramda');
|
||||
Slack = require('node-slack'),
|
||||
slack = new Slack(secrets.slackHook);
|
||||
|
||||
/**
|
||||
* Cached values
|
||||
*/
|
||||
var allBonfireIds, allBonfireNames, allCoursewareIds, allCoursewareNames,
|
||||
allFieldGuideIds, allFieldGuideNames, allNonprofitNames,
|
||||
allBonfireIndexesAndNames;
|
||||
var allFieldGuideIds, allFieldGuideNames, allNonprofitNames,
|
||||
challengeMap, challengeMapForDisplay, challengeMapWithIds,
|
||||
challengeMapWithNames, allChallengeIds, allChallenges;
|
||||
|
||||
/**
|
||||
* GET /
|
||||
@ -44,7 +47,94 @@ Array.zip = function(left, right, combinerFunction) {
|
||||
return results;
|
||||
};
|
||||
|
||||
(function() {
|
||||
if (!challengeMap) {
|
||||
var localChallengeMap = {};
|
||||
var files = fs.readdirSync(
|
||||
path.join(__dirname, '/../seed_data/challenges')
|
||||
);
|
||||
var keyCounter = 0;
|
||||
files = files.map(function (file) {
|
||||
return require(
|
||||
path.join(__dirname, '/../seed_data/challenges/' + file)
|
||||
);
|
||||
});
|
||||
files = files.sort(function (a, b) {
|
||||
return a.order - b.order;
|
||||
});
|
||||
files.forEach(function (file) {
|
||||
localChallengeMap[keyCounter++] = file;
|
||||
});
|
||||
challengeMap = _.cloneDeep(localChallengeMap);
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
module.exports = {
|
||||
|
||||
getChallengeMapForDisplay: function() {
|
||||
if (!challengeMapForDisplay) {
|
||||
challengeMapForDisplay = {};
|
||||
Object.keys(challengeMap).forEach(function(key) {
|
||||
challengeMapForDisplay[key] = {
|
||||
name: challengeMap[key].name,
|
||||
challenges: challengeMap[key].challenges
|
||||
}
|
||||
});
|
||||
}
|
||||
return challengeMapForDisplay;
|
||||
},
|
||||
|
||||
getChallengeMapWithIds: function() {
|
||||
if (!challengeMapWithIds) {
|
||||
challengeMapWithIds = {};
|
||||
Object.keys(challengeMap).forEach(function (key) {
|
||||
var onlyIds = challengeMap[key].challenges.map(function (elem) {
|
||||
return elem._id;
|
||||
});
|
||||
challengeMapWithIds[key] = onlyIds;
|
||||
});
|
||||
}
|
||||
return challengeMapWithIds;
|
||||
},
|
||||
|
||||
allChallengeIds: function() {
|
||||
|
||||
if (!allChallengeIds) {
|
||||
allChallengeIds = [];
|
||||
Object.keys(this.getChallengeMapWithIds()).forEach(function(key) {
|
||||
allChallengeIds.push(challengeMapWithIds[key]);
|
||||
});
|
||||
allChallengeIds = R.flatten(allChallengeIds);
|
||||
}
|
||||
return allChallengeIds;
|
||||
},
|
||||
|
||||
allChallenges: function() {
|
||||
if (!allChallenges) {
|
||||
allChallenges = [];
|
||||
Object.keys(this.getChallengeMapWithNames()).forEach(function(key) {
|
||||
allChallenges.push(challengeMap[key].challenges);
|
||||
});
|
||||
allChallenges = R.flatten(allChallenges);
|
||||
}
|
||||
return allChallenges;
|
||||
},
|
||||
|
||||
getChallengeMapWithNames: function() {
|
||||
if (!challengeMapWithNames) {
|
||||
challengeMapWithNames = {};
|
||||
Object.keys(challengeMap).
|
||||
forEach(function (key) {
|
||||
var onlyNames = challengeMap[key].challenges.map(function (elem) {
|
||||
return elem.name;
|
||||
});
|
||||
challengeMapWithNames[key] = onlyNames;
|
||||
});
|
||||
}
|
||||
return challengeMapWithNames;
|
||||
},
|
||||
|
||||
sitemap: function sitemap(req, res, next) {
|
||||
var appUrl = 'http://www.freecodecamp.com';
|
||||
var now = moment(new Date()).format('YYYY-MM-DD');
|
||||
@ -66,29 +156,17 @@ module.exports = {
|
||||
},
|
||||
|
||||
challenges: function (callback) {
|
||||
Courseware.aggregate()
|
||||
Challenge.aggregate()
|
||||
.group({_id: 1, names: { $addToSet: '$name'}})
|
||||
.exec(function (err, challenges) {
|
||||
if (err) {
|
||||
debug('Courseware err: ', err);
|
||||
debug('Challenge err: ', err);
|
||||
callback(err);
|
||||
} else {
|
||||
callback(null, challenges[0].names);
|
||||
}
|
||||
});
|
||||
},
|
||||
bonfires: function (callback) {
|
||||
Bonfire.aggregate()
|
||||
.group({_id: 1, names: { $addToSet: '$name'}})
|
||||
.exec(function (err, bonfires) {
|
||||
if (err) {
|
||||
debug('Bonfire err: ', err);
|
||||
callback(err);
|
||||
} else {
|
||||
callback(null, bonfires[0].names);
|
||||
}
|
||||
});
|
||||
},
|
||||
stories: function (callback) {
|
||||
Story.aggregate()
|
||||
.group({_id: 1, links: {$addToSet: '$link'}})
|
||||
@ -136,7 +214,6 @@ module.exports = {
|
||||
now: now,
|
||||
users: results.users,
|
||||
challenges: results.challenges,
|
||||
bonfires: results.bonfires,
|
||||
stories: results.stories,
|
||||
nonprofits: results.nonprofits,
|
||||
fieldGuides: results.fieldGuides
|
||||
@ -152,11 +229,30 @@ module.exports = {
|
||||
res.redirect('http://freecode.slack.com');
|
||||
} else {
|
||||
res.render('resources/chat', {
|
||||
title: "Watch us code live on Twitch.tv"
|
||||
title: 'Watch us code live on Twitch.tv'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
jobs: function jobs(req, res) {
|
||||
res.render('resources/jobs', {
|
||||
title: 'Job Board for Front End Developer and Full Stack JavaScript Developer Jobs'
|
||||
});
|
||||
},
|
||||
|
||||
jobsForm: function jobsForm(req, res) {
|
||||
res.render('resources/jobs-form', {
|
||||
title: 'Employer Partnership Form for Job Postings, Recruitment and Corporate Sponsorships'
|
||||
});
|
||||
},
|
||||
|
||||
catPhotoSubmit: 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.'
|
||||
);
|
||||
},
|
||||
|
||||
nonprofits: function nonprofits(req, res) {
|
||||
res.render('resources/nonprofits', {
|
||||
title: 'A guide to our Nonprofit Projects'
|
||||
@ -165,7 +261,7 @@ module.exports = {
|
||||
|
||||
nonprofitsForm: function nonprofitsForm(req, res) {
|
||||
res.render('resources/nonprofits-form', {
|
||||
title: 'A guide to our Nonprofit Projects'
|
||||
title: 'Nonprofit Projects Proposal Form'
|
||||
});
|
||||
},
|
||||
|
||||
@ -177,7 +273,7 @@ module.exports = {
|
||||
|
||||
agileProjectManagersForm: function agileProjectManagersForm(req, res) {
|
||||
res.render('resources/pmi-acp-agile-project-managers-form', {
|
||||
title: 'Get Agile Project Management Experience for the PMI-ACP'
|
||||
title: 'Agile Project Management Program Application Form'
|
||||
});
|
||||
},
|
||||
|
||||
@ -187,8 +283,8 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
unsubscribe: function unsubscribe(req, res) {
|
||||
User.findOne({email: req.params.email}, function(err, user) {
|
||||
unsubscribe: function unsubscribe(req, res, next) {
|
||||
User.findOne({ email: req.params.email }, function(err, user) {
|
||||
if (user) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
@ -208,52 +304,106 @@ module.exports = {
|
||||
|
||||
unsubscribed: function unsubscribed(req, res) {
|
||||
res.render('resources/unsubscribed', {
|
||||
title: "You have been unsubscribed"
|
||||
title: 'You have been unsubscribed'
|
||||
});
|
||||
},
|
||||
|
||||
githubCalls: function(req, res) {
|
||||
var githubHeaders = {headers: {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1521.3 Safari/537.36'}, port:80 };
|
||||
request('https://api.github.com/repos/freecodecamp/freecodecamp/pulls?client_id=' + secrets.github.clientID + '&client_secret=' + secrets.github.clientSecret, githubHeaders, function(err, status1, pulls) {
|
||||
pulls = pulls ? Object.keys(JSON.parse(pulls)).length : "Can't connect to github";
|
||||
request('https://api.github.com/repos/freecodecamp/freecodecamp/issues?client_id=' + secrets.github.clientID + '&client_secret=' + secrets.github.clientSecret, githubHeaders, function (err, status2, issues) {
|
||||
issues = ((pulls === parseInt(pulls)) && issues) ? Object.keys(JSON.parse(issues)).length - pulls : "Can't connect to GitHub";
|
||||
res.send({"issues": issues, "pulls" : pulls});
|
||||
});
|
||||
});
|
||||
githubCalls: function(req, res, next) {
|
||||
var githubHeaders = {
|
||||
headers: {
|
||||
'User-Agent': constantStrings.gitHubUserAgent
|
||||
},
|
||||
port: 80
|
||||
};
|
||||
request(
|
||||
[
|
||||
'https://api.github.com/repos/freecodecamp/',
|
||||
'freecodecamp/pulls?client_id=',
|
||||
secrets.github.clientID,
|
||||
'&client_secret=',
|
||||
secrets.github.clientSecret
|
||||
].join(''),
|
||||
githubHeaders,
|
||||
function(err, status1, pulls) {
|
||||
if (err) { return next(err); }
|
||||
pulls = pulls ?
|
||||
Object.keys(JSON.parse(pulls)).length :
|
||||
"Can't connect to github";
|
||||
|
||||
request(
|
||||
[
|
||||
'https://api.github.com/repos/freecodecamp/',
|
||||
'freecodecamp/issues?client_id=',
|
||||
secrets.github.clientID,
|
||||
'&client_secret=',
|
||||
secrets.github.clientSecret
|
||||
].join(''),
|
||||
githubHeaders,
|
||||
function (err, status2, issues) {
|
||||
if (err) { return next(err); }
|
||||
issues = ((pulls === parseInt(pulls, 10)) && issues) ?
|
||||
Object.keys(JSON.parse(issues)).length - pulls :
|
||||
"Can't connect to GitHub";
|
||||
res.send({
|
||||
issues: issues,
|
||||
pulls: pulls
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
trelloCalls: function(req, res, next) {
|
||||
request('https://trello.com/1/boards/BA3xVpz9/cards?key=' + secrets.trello.key, function(err, status, trello) {
|
||||
if (err) { return next(err); }
|
||||
trello = (status && status.statusCode === 200) ? (JSON.parse(trello)) : "Can't connect to to Trello";
|
||||
res.end(JSON.stringify(trello));
|
||||
});
|
||||
request(
|
||||
'https://trello.com/1/boards/BA3xVpz9/cards?key=' +
|
||||
secrets.trello.key,
|
||||
function(err, status, trello) {
|
||||
if (err) { return next(err); }
|
||||
trello = (status && status.statusCode === 200) ?
|
||||
(JSON.parse(trello)) :
|
||||
"Can't connect to to Trello";
|
||||
|
||||
res.end(JSON.stringify(trello));
|
||||
});
|
||||
},
|
||||
|
||||
bloggerCalls: function(req, res, next) {
|
||||
request('https://www.googleapis.com/blogger/v3/blogs/2421288658305323950/posts?key=' + secrets.blogger.key, function (err, status, blog) {
|
||||
if (err) { return next(err); }
|
||||
blog = (status && status.statusCode === 200) ? JSON.parse(blog) : "Can't connect to Blogger";
|
||||
res.end(JSON.stringify(blog));
|
||||
});
|
||||
request(
|
||||
'https://www.googleapis.com/blogger/v3/blogs/2421288658305323950/' +
|
||||
'posts?key=' +
|
||||
secrets.blogger.key,
|
||||
function (err, status, blog) {
|
||||
if (err) { return next(err); }
|
||||
|
||||
blog = (status && status.statusCode === 200) ?
|
||||
JSON.parse(blog) :
|
||||
"Can't connect to Blogger";
|
||||
res.end(JSON.stringify(blog));
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
about: function(req, res, next) {
|
||||
if (req.user) {
|
||||
if (!req.user.profile.picture || req.user.profile.picture === "https://s3.amazonaws.com/freecodecamp/favicons/apple-touch-icon-180x180.png") {
|
||||
req.user.profile.picture = "https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png";
|
||||
if (
|
||||
!req.user.profile.picture ||
|
||||
req.user.profile.picture.indexOf('apple-touch-icon-180x180.png') !== -1
|
||||
) {
|
||||
req.user.profile.picture =
|
||||
'https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png';
|
||||
// TODO(berks): unhandled callback
|
||||
req.user.save();
|
||||
}
|
||||
}
|
||||
var date1 = new Date("10/15/2014");
|
||||
var date1 = new Date('10/15/2014');
|
||||
var date2 = new Date();
|
||||
|
||||
var timeDiff = Math.abs(date2.getTime() - date1.getTime());
|
||||
var daysRunning = Math.ceil(timeDiff / (1000 * 3600 * 24));
|
||||
var announcements = resources.announcements;
|
||||
function numberWithCommas(x) {
|
||||
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
}
|
||||
User.count({}, function (err, c3) {
|
||||
if (err) {
|
||||
@ -271,113 +421,41 @@ module.exports = {
|
||||
},
|
||||
|
||||
randomPhrase: function() {
|
||||
return resources.phrases[Math.floor(
|
||||
Math.random() * resources.phrases.length)];
|
||||
return resources.phrases[
|
||||
Math.floor(Math.random() * resources.phrases.length)
|
||||
];
|
||||
},
|
||||
|
||||
randomVerb: function() {
|
||||
return resources.verbs[Math.floor(
|
||||
Math.random() * resources.verbs.length)];
|
||||
return resources.verbs[
|
||||
Math.floor(Math.random() * resources.verbs.length)
|
||||
];
|
||||
},
|
||||
|
||||
randomCompliment: function() {
|
||||
return resources.compliments[Math.floor(
|
||||
Math.random() * resources.compliments.length)];
|
||||
},
|
||||
|
||||
allBonfireIds: function() {
|
||||
if (allBonfireIds) {
|
||||
return allBonfireIds;
|
||||
} else {
|
||||
allBonfireIds = bonfires.
|
||||
map(function (elem) {
|
||||
return {
|
||||
_id: elem._id,
|
||||
difficulty: elem.difficulty
|
||||
};
|
||||
}).
|
||||
sort(function (a, b) {
|
||||
return a.difficulty - b.difficulty;
|
||||
}).
|
||||
map(function (elem) {
|
||||
return elem._id;
|
||||
});
|
||||
return allBonfireIds;
|
||||
}
|
||||
},
|
||||
|
||||
bonfiresIndexesAndNames: function() {
|
||||
if (allBonfireIndexesAndNames) {
|
||||
return allBonfireIndexesAndNames
|
||||
} else {
|
||||
var obj = {};
|
||||
bonfires.forEach(function(elem) {
|
||||
obj[elem._id] = elem.name;
|
||||
});
|
||||
allBonfireIndexesAndNames = obj;
|
||||
return allBonfireIndexesAndNames;
|
||||
}
|
||||
},
|
||||
|
||||
ensureBonfireNames: function(completedBonfires) {
|
||||
return completedBonfires.map(function(elem) {
|
||||
return ({
|
||||
name: this.bonfiresIndexesAndNames()[elem._id],
|
||||
_id: elem.id,
|
||||
completedDate: elem.completedDate,
|
||||
completedWith: elem.completedWith,
|
||||
solution: elem.solution
|
||||
});
|
||||
}.bind(this));
|
||||
return resources.compliments[
|
||||
Math.floor(Math.random() * resources.compliments.length)
|
||||
];
|
||||
},
|
||||
|
||||
allFieldGuideIds: function() {
|
||||
if (allFieldGuideIds) {
|
||||
return allFieldGuideIds;
|
||||
} else {
|
||||
allFieldGuideIds = fieldGuides.
|
||||
map(function (elem) {
|
||||
return elem._id;
|
||||
});
|
||||
allFieldGuideIds = fieldGuides.map(function (elem) {
|
||||
return elem._id;
|
||||
});
|
||||
return allFieldGuideIds;
|
||||
}
|
||||
},
|
||||
|
||||
allBonfireNames: function() {
|
||||
if (allBonfireNames) {
|
||||
return allBonfireNames;
|
||||
} else {
|
||||
allBonfireNames = bonfires.
|
||||
map(function (elem) {
|
||||
return {
|
||||
name: elem.name,
|
||||
difficulty: elem.difficulty,
|
||||
_id: elem._id
|
||||
};
|
||||
}).
|
||||
sort(function (a, b) {
|
||||
return a.difficulty - b.difficulty;
|
||||
}).
|
||||
map(function (elem) {
|
||||
return {
|
||||
name: elem.name,
|
||||
_id: elem._id
|
||||
};
|
||||
});
|
||||
return allBonfireNames;
|
||||
}
|
||||
},
|
||||
|
||||
allFieldGuideNames: function() {
|
||||
allFieldGuideNamesAndIds: function() {
|
||||
if (allFieldGuideNames) {
|
||||
return allFieldGuideNames;
|
||||
} else {
|
||||
allFieldGuideNames = fieldGuides.
|
||||
map(function (elem) {
|
||||
return {
|
||||
name: elem.name
|
||||
};
|
||||
});
|
||||
allFieldGuideNames = fieldGuides.map(function (elem) {
|
||||
return { name: elem.name, id: elem._id };
|
||||
});
|
||||
return allFieldGuideNames;
|
||||
}
|
||||
},
|
||||
@ -386,61 +464,10 @@ module.exports = {
|
||||
if (allNonprofitNames) {
|
||||
return allNonprofitNames;
|
||||
} else {
|
||||
allNonprofitNames = nonprofits.
|
||||
map(function (elem) {
|
||||
return {
|
||||
name: elem.name
|
||||
};
|
||||
});
|
||||
return allNonprofitNames;
|
||||
}
|
||||
},
|
||||
|
||||
allCoursewareIds: function() {
|
||||
if (allCoursewareIds) {
|
||||
return allCoursewareIds;
|
||||
} else {
|
||||
allCoursewareIds = coursewares.
|
||||
map(function (elem) {
|
||||
return {
|
||||
_id: elem._id,
|
||||
difficulty: elem.difficulty
|
||||
};
|
||||
}).
|
||||
sort(function (a, b) {
|
||||
return a.difficulty - b.difficulty;
|
||||
}).
|
||||
map(function (elem) {
|
||||
return elem._id;
|
||||
});
|
||||
return allCoursewareIds;
|
||||
}
|
||||
},
|
||||
|
||||
allCoursewareNames: function() {
|
||||
if (allCoursewareNames) {
|
||||
return allCoursewareNames;
|
||||
} else {
|
||||
allCoursewareNames = coursewares.
|
||||
map(function (elem) {
|
||||
return {
|
||||
name: elem.name,
|
||||
difficulty: elem.difficulty,
|
||||
challengeType: elem.challengeType,
|
||||
_id: elem._id
|
||||
};
|
||||
}).
|
||||
sort(function (a, b) {
|
||||
return a.difficulty - b.difficulty;
|
||||
}).
|
||||
map(function (elem) {
|
||||
return {
|
||||
name: elem.name,
|
||||
challengeType: elem.challengeType,
|
||||
_id: elem._id
|
||||
};
|
||||
allNonprofitNames = nonprofits.map(function (elem) {
|
||||
return { name: elem.name };
|
||||
});
|
||||
return allCoursewareNames;
|
||||
return allNonprofitNames;
|
||||
}
|
||||
},
|
||||
|
||||
@ -455,16 +482,25 @@ module.exports = {
|
||||
if (!error && response.statusCode === 200) {
|
||||
var $ = cheerio.load(body);
|
||||
var metaDescription = $("meta[name='description']");
|
||||
var metaImage = $("meta[property='og:image']");
|
||||
var urlImage = metaImage.attr('content') ? metaImage.attr('content') : '';
|
||||
var metaImage = $("meta[property='og:image']");
|
||||
var urlImage = metaImage.attr('content') ?
|
||||
metaImage.attr('content') :
|
||||
'';
|
||||
|
||||
var metaTitle = $('title');
|
||||
var description = metaDescription.attr('content') ? metaDescription.attr('content') : '';
|
||||
result.title = metaTitle.text().length < 90 ? metaTitle.text() : metaTitle.text().slice(0, 87) + "...";
|
||||
var description = metaDescription.attr('content') ?
|
||||
metaDescription.attr('content') :
|
||||
'';
|
||||
|
||||
result.title = metaTitle.text().length < 90 ?
|
||||
metaTitle.text() :
|
||||
metaTitle.text().slice(0, 87) + '...';
|
||||
|
||||
result.image = urlImage;
|
||||
result.description = description;
|
||||
callback(null, result);
|
||||
} else {
|
||||
callback('failed');
|
||||
callback(new Error('failed'));
|
||||
}
|
||||
});
|
||||
})();
|
||||
@ -524,24 +560,33 @@ module.exports = {
|
||||
}
|
||||
},
|
||||
codepenResources: {
|
||||
twitter: function(req, res) {
|
||||
twitter: function(req, res, next) {
|
||||
// sends out random tweets about javascript
|
||||
var T = new Twit({
|
||||
consumer_key: secrets.twitter.consumerKey,
|
||||
consumer_secret: secrets.twitter.consumerSecret,
|
||||
access_token: secrets.twitter.token,
|
||||
access_token_secret: secrets.twitter.tokenSecret
|
||||
'consumer_key': secrets.twitter.consumerKey,
|
||||
'consumer_secret': secrets.twitter.consumerSecret,
|
||||
'access_token': secrets.twitter.token,
|
||||
'access_token_secret': secrets.twitter.tokenSecret
|
||||
});
|
||||
|
||||
var screenName;
|
||||
if (req.params.screenName) {
|
||||
screenName = req.params.screenName;
|
||||
} else {
|
||||
screenName = 'freecodecamp';
|
||||
}
|
||||
|
||||
T.get('statuses/user_timeline', {screen_name: screenName, count:10}, function(err, data, response) {
|
||||
return res.json(data);
|
||||
});
|
||||
T.get(
|
||||
'statuses/user_timeline',
|
||||
{
|
||||
'screen_name': screenName,
|
||||
count: 10
|
||||
},
|
||||
function(err, data) {
|
||||
if (err) { return next(err); }
|
||||
return res.json(data);
|
||||
}
|
||||
);
|
||||
},
|
||||
twitterFCCStream: function() {
|
||||
// sends out a tweet stream from FCC's account
|
||||
@ -552,5 +597,42 @@ module.exports = {
|
||||
slack: function() {
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
getHelp: function(req, res, next) {
|
||||
var userName = req.user.profile.username;
|
||||
var code = req.body.payload.code ? '\n```\n' +
|
||||
req.body.payload.code + '\n```\n'
|
||||
: '';
|
||||
var challenge = req.body.payload.challenge;
|
||||
|
||||
slack.send({
|
||||
text: "*" + userName + "* wants help with " + challenge + ". " +
|
||||
code + "Hey, *" + userName + "*, if no one helps you right " +
|
||||
"away, try typing out your problem in detail to me. Like this: " +
|
||||
"http://en.wikipedia.org/wiki/Rubber_duck_debugging",
|
||||
channel: '#help',
|
||||
username: "Debuggy the Rubber Duck",
|
||||
icon_url: "https://pbs.twimg.com/profile_images/3609875545/569237541c920fa78d78902069615caf.jpeg"
|
||||
});
|
||||
return res.sendStatus(200);
|
||||
},
|
||||
|
||||
getPair: function(req, res, next) {
|
||||
var userName = req.user.profile.username;
|
||||
var challenge = req.body.payload.challenge;
|
||||
slack.send({
|
||||
text: "Anyone want to pair with *" + userName + "* on " + challenge +
|
||||
"?\nMake sure you install Screen Hero here:" +
|
||||
"http://freecodecamp.com/field-guide/how-do-i-install-screenhero\n" +
|
||||
"Then start your pair program session with *" + userName +
|
||||
"* by typing \"/hero @" + userName + "\" into Slack.\n* And"+ userName +
|
||||
"*, be sure to launch Screen Hero, then keep coding." +
|
||||
"Another camper may pair with you soon.",
|
||||
channel: '#letspair',
|
||||
username: "Companion Cube",
|
||||
icon_url: "https://lh3.googleusercontent.com/-f6xDPDV2rPE/AAAAAAAAAAI/AAAAAAAAAAA/mdlESXQu11Q/photo.jpg"
|
||||
});
|
||||
return res.sendStatus(200);
|
||||
}
|
||||
};
|
||||
|
@ -19,9 +19,10 @@ function hotRank(timeValue, rank) {
|
||||
* Ranking...
|
||||
* f(ts, 1, rank) = log(10)z + (ts)/45000;
|
||||
*/
|
||||
var time48Hours = 172800000;
|
||||
var hotness;
|
||||
var z = Math.log(rank) / Math.log(10);
|
||||
hotness = z + (timeValue / 115200000);
|
||||
hotness = z + (timeValue / time48Hours);
|
||||
return hotness;
|
||||
|
||||
}
|
||||
@ -128,14 +129,17 @@ exports.returnIndividualStory = function(req, res, next) {
|
||||
|
||||
if (story.length < 1) {
|
||||
req.flash('errors', {
|
||||
msg: "404: We couldn't find a story with that name. Please double check the name."
|
||||
msg: "404: We couldn't find a story with that name. " +
|
||||
'Please double check the name.'
|
||||
});
|
||||
|
||||
return res.redirect('/news/');
|
||||
}
|
||||
|
||||
story = story.pop();
|
||||
var dashedNameFull = story.storyLink.toLowerCase().replace(/\s/g, '-');
|
||||
var dashedNameFull = story.storyLink.toLowerCase()
|
||||
.replace(/\s+/g, ' ')
|
||||
.replace(/\s/g, '-');
|
||||
if (dashedNameFull !== dashedName) {
|
||||
return res.redirect('../news/' + dashedNameFull);
|
||||
}
|
||||
@ -148,7 +152,7 @@ exports.returnIndividualStory = function(req, res, next) {
|
||||
if (votedObj.length > 0) {
|
||||
userVoted = true;
|
||||
}
|
||||
} catch(err) {
|
||||
} catch(e) {
|
||||
userVoted = false;
|
||||
}
|
||||
res.render('stories/index', {
|
||||
@ -229,12 +233,10 @@ exports.upvote = function(req, res, next) {
|
||||
);
|
||||
story.markModified('rank');
|
||||
story.save();
|
||||
User.find({'_id': story.author.userId}, function(err, user) {
|
||||
'use strict';
|
||||
User.findOne({'_id': story.author.userId}, function(err, user) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
user = user.pop();
|
||||
user.progressTimestamps.push(Date.now() || 0);
|
||||
user.save(function (err, user) {
|
||||
req.user.save(function (err, user) {
|
||||
@ -328,9 +330,6 @@ exports.storySubmission = function(req, res, next) {
|
||||
return next(new Error('Not authorized'));
|
||||
}
|
||||
var storyLink = data.headline
|
||||
.replace(/\'/g, '')
|
||||
.replace(/\"/g, '')
|
||||
.replace(/,/g, '')
|
||||
.replace(/\s+/g, ' ')
|
||||
.replace(/[^a-z0-9\s]/gi, '')
|
||||
.toLowerCase()
|
||||
@ -339,7 +338,7 @@ exports.storySubmission = function(req, res, next) {
|
||||
if (link.search(/^https?:\/\//g) === -1) {
|
||||
link = 'http://' + link;
|
||||
}
|
||||
Story.count({'storyLink': new RegExp('^' + storyLink + '(?: [0-9]+)?$', 'i')}, function (err, storyCount) {
|
||||
Story.count({ storyLink: new RegExp('^' + storyLink + '(?: [0-9]+)?$', 'i')}, function (err, storyCount) {
|
||||
if (err) {
|
||||
return res.status(500);
|
||||
}
|
||||
@ -513,7 +512,8 @@ exports.storySubmission = function(req, res, next) {
|
||||
return next(err);
|
||||
}
|
||||
try {
|
||||
// Based on the context retrieve the parent object of the comment (Story/Comment)
|
||||
// Based on the context retrieve the parent
|
||||
// object of the comment (Story/Comment)
|
||||
Context.find({'_id': data.associatedPost}, function (err, associatedContext) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
@ -533,8 +533,15 @@ exports.storySubmission = function(req, res, next) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
// If the emails of both authors differ, only then proceed with email notification
|
||||
if (typeof data.author !== 'undefined' && data.author.email && typeof recipient !== 'undefined' && recipient.email && (data.author.email !== recipient.email)) {
|
||||
// If the emails of both authors differ,
|
||||
// only then proceed with email notification
|
||||
if (
|
||||
typeof data.author !== 'undefined' &&
|
||||
data.author.email &&
|
||||
typeof recipient !== 'undefined' &&
|
||||
recipient.email &&
|
||||
(data.author.email !== recipient.email)
|
||||
) {
|
||||
var transporter = nodemailer.createTransport({
|
||||
service: 'Mandrill',
|
||||
auth: {
|
||||
@ -546,11 +553,14 @@ exports.storySubmission = function(req, res, next) {
|
||||
var mailOptions = {
|
||||
to: recipient.email,
|
||||
from: 'Team@freecodecamp.com',
|
||||
subject: data.author.username + ' replied to your post on Camper News',
|
||||
subject: data.author.username +
|
||||
' replied to your post on Camper News',
|
||||
text: [
|
||||
'Just a quick heads-up: ' + data.author.username + ' replied to you on Camper News.',
|
||||
'Just a quick heads-up: ',
|
||||
data.author.username + ' replied to you on Camper News.',
|
||||
'You can keep this conversation going.',
|
||||
'Just head back to the discussion here: http://freecodecamp.com/news/' + data.originalStoryLink,
|
||||
'Just head back to the discussion here: ',
|
||||
'http://freecodecamp.com/news/' + data.originalStoryLink,
|
||||
'- the Free Code Camp Volunteer Team'
|
||||
].join('\n')
|
||||
};
|
||||
|
@ -6,10 +6,45 @@ var _ = require('lodash'),
|
||||
User = require('../models/User'),
|
||||
secrets = require('../config/secrets'),
|
||||
moment = require('moment'),
|
||||
debug = require('debug')('freecc:cntr:challenges'),
|
||||
debug = require('debug')('freecc:cntr:userController'),
|
||||
resources = require('./resources'),
|
||||
R = require('ramda');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param req
|
||||
* @param res
|
||||
* @returns null
|
||||
* Middleware to migrate users from fragmented challenge structure to unified
|
||||
* challenge structure
|
||||
*/
|
||||
exports.userMigration = function(req, res, next) {
|
||||
if (req.user && req.user.completedChallenges.length === 0) {
|
||||
req.user.completedChallenges = R.filter(function (elem) {
|
||||
return elem; // getting rid of undefined
|
||||
}, R.concat(
|
||||
req.user.completedCoursewares,
|
||||
req.user.completedBonfires.map(function (bonfire) {
|
||||
return ({
|
||||
completedDate: bonfire.completedDate,
|
||||
_id: bonfire._id,
|
||||
name: bonfire.name,
|
||||
completedWith: bonfire.completedWith,
|
||||
solution: bonfire.solution,
|
||||
githubLink: '',
|
||||
verified: false,
|
||||
challengeType: 5
|
||||
});
|
||||
})
|
||||
));
|
||||
next();
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* GET /signin
|
||||
* Siginin page.
|
||||
@ -53,6 +88,12 @@ exports.postSignin = function(req, res, next) {
|
||||
return next(err);
|
||||
}
|
||||
req.flash('success', { msg: 'Success! You are logged in.' });
|
||||
if (/hotStories/.test(req.session.returnTo)) {
|
||||
return res.redirect('../news');
|
||||
}
|
||||
if (/field-guide/.test(req.session.returnTo)) {
|
||||
return res.redirect('../field-guide');
|
||||
}
|
||||
return res.redirect(req.session.returnTo || '/');
|
||||
});
|
||||
})(req, res, next);
|
||||
@ -73,7 +114,8 @@ exports.signout = function(req, res) {
|
||||
* Signup page.
|
||||
*/
|
||||
|
||||
exports.getEmailSignin = function(req, res) {
|
||||
exports.getEmailSignin = function(req, res) //noinspection Eslint
|
||||
{
|
||||
if (req.user) {
|
||||
return res.redirect('/');
|
||||
}
|
||||
@ -102,15 +144,13 @@ exports.getEmailSignup = function(req, res) {
|
||||
*/
|
||||
|
||||
exports.postEmailSignup = function(req, res, next) {
|
||||
req.assert('email', 'valid email required').isEmail();
|
||||
var errors = req.validationErrors();
|
||||
|
||||
|
||||
req.assert('email', 'valid email required').isEmail();
|
||||
var errors = req.validationErrors();
|
||||
|
||||
if (errors) {
|
||||
req.flash('errors', errors);
|
||||
return res.redirect('/email-signup');
|
||||
}
|
||||
if (errors) {
|
||||
req.flash('errors', errors);
|
||||
return res.redirect('/email-signup');
|
||||
}
|
||||
|
||||
var possibleUserData = req.body;
|
||||
|
||||
@ -134,7 +174,8 @@ exports.postEmailSignup = function(req, res, next) {
|
||||
password: req.body.password,
|
||||
profile: {
|
||||
username: req.body.username.trim(),
|
||||
picture: 'https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png'
|
||||
picture:
|
||||
'https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png'
|
||||
}
|
||||
});
|
||||
|
||||
@ -149,7 +190,9 @@ exports.postEmailSignup = function(req, res, next) {
|
||||
});
|
||||
return res.redirect('/email-signup');
|
||||
}
|
||||
User.findOne({'profile.username': req.body.username }, function(err, existingUsername) {
|
||||
User.findOne(
|
||||
{ 'profile.username': req.body.username },
|
||||
function(err, existingUsername) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
@ -181,8 +224,10 @@ exports.postEmailSignup = function(req, res, next) {
|
||||
text: [
|
||||
'Greetings from San Francisco!\n\n',
|
||||
'Thank you for joining our community.\n',
|
||||
'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',
|
||||
'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',
|
||||
'Good luck with the challenges!\n\n',
|
||||
'- the Volunteer Camp Counselor Team'
|
||||
].join('')
|
||||
@ -220,28 +265,33 @@ exports.getAccountAngular = function(req, res) {
|
||||
*/
|
||||
|
||||
exports.checkUniqueUsername = function(req, res, next) {
|
||||
User.count({'profile.username': req.params.username.toLowerCase()}, function (err, data) {
|
||||
if (err) { return next(err); }
|
||||
if (data == 1) {
|
||||
return res.send(true);
|
||||
} else {
|
||||
return res.send(false);
|
||||
}
|
||||
});
|
||||
User.count(
|
||||
{ 'profile.username': req.params.username.toLowerCase() },
|
||||
function (err, data) {
|
||||
if (err) { return next(err); }
|
||||
if (data === 1) {
|
||||
return res.send(true);
|
||||
} else {
|
||||
return res.send(false);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Existing username check
|
||||
*/
|
||||
exports.checkExistingUsername = function(req, res, next) {
|
||||
User.count({'profile.username': req.params.username.toLowerCase()}, function (err, data) {
|
||||
if (err) { return next(err); }
|
||||
if (data === 1) {
|
||||
return res.send(true);
|
||||
} else {
|
||||
return res.send(false);
|
||||
}
|
||||
});
|
||||
User.count(
|
||||
{ 'profile.username': req.params.username.toLowerCase() },
|
||||
function (err, data) {
|
||||
if (err) { return next(err); }
|
||||
if (data === 1) {
|
||||
return res.send(true);
|
||||
} else {
|
||||
return res.send(false);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -249,14 +299,17 @@ exports.checkExistingUsername = function(req, res, next) {
|
||||
*/
|
||||
|
||||
exports.checkUniqueEmail = function(req, res, next) {
|
||||
User.count({'email': decodeURIComponent(req.params.email).toLowerCase()}, function (err, data) {
|
||||
if (err) { return next(err); }
|
||||
if (data === 1) {
|
||||
return res.send(true);
|
||||
} else {
|
||||
return res.send(false);
|
||||
}
|
||||
});
|
||||
User.count(
|
||||
{ email: decodeURIComponent(req.params.email).toLowerCase() },
|
||||
function (err, data) {
|
||||
if (err) { return next(err); }
|
||||
if (data === 1) {
|
||||
return res.send(true);
|
||||
} else {
|
||||
return res.send(false);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -266,127 +319,132 @@ exports.checkUniqueEmail = function(req, res, next) {
|
||||
*/
|
||||
|
||||
exports.returnUser = function(req, res, next) {
|
||||
User.find({'profile.username': req.params.username.toLowerCase()}, function(err, user) {
|
||||
if (err) { debug('Username err: ', err); next(err); }
|
||||
if (user[0]) {
|
||||
user = user[0];
|
||||
|
||||
user.progressTimestamps = user.progressTimestamps.sort(function(a, b) {
|
||||
return a - b;
|
||||
});
|
||||
|
||||
var timeObject = Object.create(null);
|
||||
R.forEach(function(time) {
|
||||
timeObject[moment(time).format('YYYY-MM-DD')] = time;
|
||||
}, user.progressTimestamps);
|
||||
|
||||
var tmpLongest = 1;
|
||||
var timeKeys = R.keys(timeObject);
|
||||
|
||||
user.longestStreak = 0;
|
||||
for (var i = 1; i <= timeKeys.length; i++) {
|
||||
if (moment(timeKeys[i - 1]).add(1, 'd').toString()
|
||||
=== moment(timeKeys[i]).toString()) {
|
||||
tmpLongest++;
|
||||
if (tmpLongest > user.longestStreak) {
|
||||
user.longestStreak = tmpLongest;
|
||||
}
|
||||
} else {
|
||||
tmpLongest = 1;
|
||||
}
|
||||
User.find(
|
||||
{ 'profile.username': req.params.username.toLowerCase() },
|
||||
function(err, user) {
|
||||
if (err) {
|
||||
debug('Username err: ', err);
|
||||
return next(err);
|
||||
}
|
||||
if (user[0]) {
|
||||
user = user[0];
|
||||
|
||||
timeKeys = timeKeys.reverse();
|
||||
tmpLongest = 1;
|
||||
user.progressTimestamps = user.progressTimestamps.sort(function(a, b) {
|
||||
return a - b;
|
||||
});
|
||||
|
||||
user.currentStreak = 1;
|
||||
var today = moment(Date.now()).format('YYYY-MM-DD');
|
||||
var timeObject = Object.create(null);
|
||||
R.forEach(function(time) {
|
||||
timeObject[moment(time).format('YYYY-MM-DD')] = time;
|
||||
}, user.progressTimestamps);
|
||||
|
||||
if (moment(today).toString() === moment(timeKeys[0]).toString() ||
|
||||
moment(today).subtract(1, 'd').toString() ===
|
||||
moment(timeKeys[0]).toString()) {
|
||||
var tmpLongest = 1;
|
||||
var timeKeys = R.keys(timeObject);
|
||||
|
||||
user.longestStreak = 0;
|
||||
for (var i = 1; i <= timeKeys.length; i++) {
|
||||
if (moment(timeKeys[i - 1]).subtract(1, 'd').toString()
|
||||
if (moment(timeKeys[i - 1]).add(1, 'd').toString()
|
||||
=== moment(timeKeys[i]).toString()) {
|
||||
debug(timeKeys[i - 1], timeKeys[i]);
|
||||
tmpLongest++;
|
||||
if (tmpLongest > user.currentStreak) {
|
||||
user.currentStreak = tmpLongest;
|
||||
if (tmpLongest > user.longestStreak) {
|
||||
user.longestStreak = tmpLongest;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
tmpLongest = 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
timeKeys = timeKeys.reverse();
|
||||
tmpLongest = 1;
|
||||
|
||||
user.currentStreak = 1;
|
||||
}
|
||||
var today = moment(Date.now()).format('YYYY-MM-DD');
|
||||
|
||||
user.save(function(err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
if (
|
||||
moment(today).toString() === moment(timeKeys[0]).toString() ||
|
||||
moment(today).subtract(1, 'd').toString() ===
|
||||
moment(timeKeys[0]).toString()
|
||||
) {
|
||||
for (var _i = 1; _i <= timeKeys.length; _i++) {
|
||||
|
||||
if (
|
||||
moment(timeKeys[_i - 1]).subtract(1, 'd').toString() ===
|
||||
moment(timeKeys[_i]).toString()
|
||||
) {
|
||||
|
||||
tmpLongest++;
|
||||
|
||||
if (tmpLongest > user.currentStreak) {
|
||||
user.currentStreak = tmpLongest;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
user.currentStreak = 1;
|
||||
}
|
||||
});
|
||||
|
||||
var data = {};
|
||||
var progressTimestamps = user.progressTimestamps;
|
||||
progressTimestamps.forEach(function(timeStamp) {
|
||||
data[(timeStamp / 1000)] = 1;
|
||||
});
|
||||
|
||||
if (!user.needsMigration) {
|
||||
var currentlySolvedBonfires = user.completedBonfires;
|
||||
user.completedBonfires =
|
||||
resources.ensureBonfireNames(currentlySolvedBonfires);
|
||||
user.needsMigration = true;
|
||||
user.save(function(err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
var data = {};
|
||||
var progressTimestamps = user.progressTimestamps;
|
||||
progressTimestamps.forEach(function(timeStamp) {
|
||||
data[(timeStamp / 1000)] = 1;
|
||||
});
|
||||
|
||||
user.currentStreak = user.currentStreak || 1;
|
||||
user.longestStreak = user.longestStreak || 1;
|
||||
var challenges = user.completedCoursewares.filter(function ( obj ) {
|
||||
return !!obj.solution;
|
||||
});
|
||||
|
||||
res.render('account/show', {
|
||||
title: 'Camper ' + user.profile.username + '\'s portfolio',
|
||||
username: user.profile.username,
|
||||
name: user.profile.name,
|
||||
location: user.profile.location,
|
||||
githubProfile: user.profile.githubProfile,
|
||||
linkedinProfile: user.profile.linkedinProfile,
|
||||
codepenProfile: user.profile.codepenProfile,
|
||||
facebookProfile: user.profile.facebookProfile,
|
||||
twitterHandle: user.profile.twitterHandle,
|
||||
bio: user.profile.bio,
|
||||
picture: user.profile.picture,
|
||||
progressTimestamps: user.progressTimestamps,
|
||||
website1Link: user.portfolio.website1Link,
|
||||
website1Title: user.portfolio.website1Title,
|
||||
website1Image: user.portfolio.website1Image,
|
||||
website2Link: user.portfolio.website2Link,
|
||||
website2Title: user.portfolio.website2Title,
|
||||
website2Image: user.portfolio.website2Image,
|
||||
website3Link: user.portfolio.website3Link,
|
||||
website3Title: user.portfolio.website3Title,
|
||||
website3Image: user.portfolio.website3Image,
|
||||
challenges: challenges,
|
||||
bonfires: user.completedChallenges.filter(function(challenge) {
|
||||
return challenge.challengeType === 5;
|
||||
}),
|
||||
calender: data,
|
||||
moment: moment,
|
||||
longestStreak: user.longestStreak +
|
||||
(user.longestStreak === 1 ? ' day' : ' days'),
|
||||
currentStreak: user.currentStreak +
|
||||
(user.currentStreak === 1 ? ' day' : ' days')
|
||||
});
|
||||
});
|
||||
} else {
|
||||
req.flash('errors', {
|
||||
msg: "404: We couldn't find a page with that url. " +
|
||||
'Please double check the link.'
|
||||
});
|
||||
return res.redirect('/');
|
||||
}
|
||||
|
||||
user.currentStreak = user.currentStreak || 1;
|
||||
user.longestStreak = user.longestStreak || 1;
|
||||
var challenges = user.completedCoursewares.filter(function ( obj ) {
|
||||
return !!obj.solution;
|
||||
});
|
||||
res.render('account/show', {
|
||||
title: 'Camper ' + user.profile.username + '\'s portfolio',
|
||||
username: user.profile.username,
|
||||
name: user.profile.name,
|
||||
location: user.profile.location,
|
||||
githubProfile: user.profile.githubProfile,
|
||||
linkedinProfile: user.profile.linkedinProfile,
|
||||
codepenProfile: user.profile.codepenProfile,
|
||||
facebookProfile: user.profile.facebookProfile,
|
||||
twitterHandle: user.profile.twitterHandle,
|
||||
bio: user.profile.bio,
|
||||
picture: user.profile.picture,
|
||||
progressTimestamps: user.progressTimestamps,
|
||||
website1Link: user.portfolio.website1Link,
|
||||
website1Title: user.portfolio.website1Title,
|
||||
website1Image: user.portfolio.website1Image,
|
||||
website2Link: user.portfolio.website2Link,
|
||||
website2Title: user.portfolio.website2Title,
|
||||
website2Image: user.portfolio.website2Image,
|
||||
website3Link: user.portfolio.website3Link,
|
||||
website3Title: user.portfolio.website3Title,
|
||||
website3Image: user.portfolio.website3Image,
|
||||
challenges: challenges,
|
||||
bonfires: user.completedBonfires,
|
||||
calender: data,
|
||||
moment: moment,
|
||||
longestStreak: user.longestStreak + (user.longestStreak === 1 ? " day" : " days"),
|
||||
currentStreak: user.currentStreak + (user.currentStreak === 1 ? " day" : " days")
|
||||
});
|
||||
|
||||
} else {
|
||||
req.flash('errors', {
|
||||
msg: "404: We couldn't find a page with that url. Please double check the link."
|
||||
});
|
||||
return res.redirect('/');
|
||||
}
|
||||
});
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -395,9 +453,9 @@ exports.returnUser = function(req, res, next) {
|
||||
* Update profile information.
|
||||
*/
|
||||
|
||||
exports.updateProgress = function(req, res) {
|
||||
exports.updateProgress = function(req, res, next) {
|
||||
User.findById(req.user.id, function(err, user) {
|
||||
if (err) return next(err);
|
||||
if (err) { return next(err); }
|
||||
user.email = req.body.email || '';
|
||||
user.profile.name = req.body.name || '';
|
||||
user.profile.gender = req.body.gender || '';
|
||||
@ -405,7 +463,7 @@ exports.updateProgress = function(req, res) {
|
||||
user.profile.website = req.body.website || '';
|
||||
|
||||
user.save(function(err) {
|
||||
if (err) return next(err);
|
||||
if (err) { return next(err); }
|
||||
req.flash('success', { msg: 'Profile information updated.' });
|
||||
res.redirect('/account');
|
||||
});
|
||||
@ -419,8 +477,8 @@ exports.updateProgress = function(req, res) {
|
||||
|
||||
exports.postUpdateProfile = function(req, res, next) {
|
||||
|
||||
User.findById(req.user.id, function(err, user) {
|
||||
if (err) return next(err);
|
||||
User.findById(req.user.id, function(err) {
|
||||
if (err) { return next(err); }
|
||||
var errors = req.validationErrors();
|
||||
if (errors) {
|
||||
req.flash('errors', errors);
|
||||
@ -432,63 +490,72 @@ exports.postUpdateProfile = function(req, res, next) {
|
||||
return next(err);
|
||||
}
|
||||
var user = req.user;
|
||||
if (existingEmail && existingEmail.email != user.email) {
|
||||
if (existingEmail && existingEmail.email !== user.email) {
|
||||
req.flash('errors', {
|
||||
msg: "An account with that email address already exists."
|
||||
msg: 'An account with that email address already exists.'
|
||||
});
|
||||
return res.redirect('/account');
|
||||
}
|
||||
User.findOne({ 'profile.username': req.body.username }, function(err, existingUsername) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
var user = req.user;
|
||||
if (existingUsername && existingUsername.profile.username !== user.profile.username) {
|
||||
req.flash('errors', {
|
||||
msg: 'An account with that username already exists.'
|
||||
});
|
||||
return res.redirect('/account');
|
||||
}
|
||||
user.email = req.body.email.trim() || '';
|
||||
user.profile.name = req.body.name.trim() || '';
|
||||
user.profile.username = req.body.username.trim() || '';
|
||||
user.profile.location = req.body.location.trim() || '';
|
||||
user.profile.githubProfile = req.body.githubProfile.trim() || '';
|
||||
user.profile.facebookProfile = req.body.facebookProfile.trim() || '';
|
||||
user.profile.linkedinProfile = req.body.linkedinProfile.trim() || '';
|
||||
user.profile.codepenProfile = req.body.codepenProfile.trim() || '';
|
||||
user.profile.twitterHandle = req.body.twitterHandle.trim() || '';
|
||||
user.profile.bio = req.body.bio.trim() || '';
|
||||
user.profile.picture = req.body.picture.trim() || 'https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png';
|
||||
user.portfolio.website1Title = req.body.website1Title.trim() || '';
|
||||
user.portfolio.website1Link = req.body.website1Link.trim() || '';
|
||||
user.portfolio.website1Image = req.body.website1Image.trim() || '';
|
||||
user.portfolio.website2Title = req.body.website2Title.trim() || '';
|
||||
user.portfolio.website2Link = req.body.website2Link.trim() || '';
|
||||
user.portfolio.website2Image = req.body.website2Image.trim() || '';
|
||||
user.portfolio.website3Title = req.body.website3Title.trim() || '';
|
||||
user.portfolio.website3Link = req.body.website3Link.trim() || '';
|
||||
user.portfolio.website3Image = req.body.website3Image.trim() || '';
|
||||
|
||||
|
||||
user.save(function (err) {
|
||||
User.findOne(
|
||||
{ 'profile.username': req.body.username },
|
||||
function(err, existingUsername) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
resources.updateUserStoryPictures(
|
||||
user._id.toString(),
|
||||
user.profile.picture,
|
||||
user.profile.username,
|
||||
function(err) {
|
||||
if (err) { return next(err); }
|
||||
req.flash('success', {
|
||||
msg: 'Profile information updated.'
|
||||
});
|
||||
res.redirect('/account');
|
||||
var user = req.user;
|
||||
if (
|
||||
existingUsername &&
|
||||
existingUsername.profile.username !== user.profile.username
|
||||
) {
|
||||
req.flash('errors', {
|
||||
msg: 'An account with that username already exists.'
|
||||
});
|
||||
return res.redirect('/account');
|
||||
}
|
||||
user.email = req.body.email.trim() || '';
|
||||
user.profile.name = req.body.name.trim() || '';
|
||||
user.profile.username = req.body.username.trim() || '';
|
||||
user.profile.location = req.body.location.trim() || '';
|
||||
user.profile.githubProfile = req.body.githubProfile.trim() || '';
|
||||
user.profile.facebookProfile = req.body.facebookProfile.trim() || '';
|
||||
user.profile.linkedinProfile = req.body.linkedinProfile.trim() || '';
|
||||
user.profile.codepenProfile = req.body.codepenProfile.trim() || '';
|
||||
user.profile.twitterHandle = req.body.twitterHandle.trim() || '';
|
||||
user.profile.bio = req.body.bio.trim() || '';
|
||||
|
||||
user.profile.picture = req.body.picture.trim() ||
|
||||
'https://s3.amazonaws.com/freecodecamp/' +
|
||||
'camper-image-placeholder.png';
|
||||
user.portfolio.website1Title = req.body.website1Title.trim() || '';
|
||||
user.portfolio.website1Link = req.body.website1Link.trim() || '';
|
||||
user.portfolio.website1Image = req.body.website1Image.trim() || '';
|
||||
user.portfolio.website2Title = req.body.website2Title.trim() || '';
|
||||
user.portfolio.website2Link = req.body.website2Link.trim() || '';
|
||||
user.portfolio.website2Image = req.body.website2Image.trim() || '';
|
||||
user.portfolio.website3Title = req.body.website3Title.trim() || '';
|
||||
user.portfolio.website3Link = req.body.website3Link.trim() || '';
|
||||
user.portfolio.website3Image = req.body.website3Image.trim() || '';
|
||||
|
||||
|
||||
user.save(function (err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
resources.updateUserStoryPictures(
|
||||
user._id.toString(),
|
||||
user.profile.picture,
|
||||
user.profile.username,
|
||||
function(err) {
|
||||
if (err) { return next(err); }
|
||||
req.flash('success', {
|
||||
msg: 'Profile information updated.'
|
||||
});
|
||||
res.redirect('/account');
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
@ -548,7 +615,7 @@ exports.getOauthUnlink = function(req, res, next) {
|
||||
User.findById(req.user.id, function(err, user) {
|
||||
if (err) { return next(err); }
|
||||
|
||||
user[provider] = undefined;
|
||||
user[provider] = null;
|
||||
user.tokens =
|
||||
_.reject(user.tokens, function(token) {
|
||||
return token.kind === provider;
|
||||
@ -567,7 +634,7 @@ exports.getOauthUnlink = function(req, res, next) {
|
||||
* Reset Password page.
|
||||
*/
|
||||
|
||||
exports.getReset = function(req, res) {
|
||||
exports.getReset = function(req, res, next) {
|
||||
if (req.isAuthenticated()) {
|
||||
return res.redirect('/');
|
||||
}
|
||||
@ -617,8 +684,8 @@ exports.postReset = function(req, res, next) {
|
||||
}
|
||||
|
||||
user.password = req.body.password;
|
||||
user.resetPasswordToken = undefined;
|
||||
user.resetPasswordExpires = undefined;
|
||||
user.resetPasswordToken = null;
|
||||
user.resetPasswordExpires = null;
|
||||
|
||||
user.save(function(err) {
|
||||
if (err) { return done(err); }
|
||||
|
@ -15,7 +15,7 @@ var bonfireSchema = new mongoose.Schema({
|
||||
difficulty: String,
|
||||
description: Array,
|
||||
tests: Array,
|
||||
challengeSeed: String,
|
||||
challengeSeed: Array,
|
||||
MDNlinks: [String]
|
||||
});
|
||||
|
||||
|
@ -1,16 +1,22 @@
|
||||
var mongoose = require('mongoose');
|
||||
var secrets = require('../config/secrets');
|
||||
|
||||
/**
|
||||
*
|
||||
* @type {exports.Schema}
|
||||
*/
|
||||
|
||||
var challengeSchema = new mongoose.Schema({
|
||||
name: {
|
||||
type: String,
|
||||
unique: true
|
||||
},
|
||||
link: String,
|
||||
time: String,
|
||||
challengeNumber: Number,
|
||||
video: String,
|
||||
steps: Array
|
||||
difficulty: String,
|
||||
description: Array,
|
||||
tests: Array,
|
||||
challengeSeed: Array,
|
||||
challengeType: Number, // 0 = html, 1 = javascript only, 2 = video, 3 = zipline, 4 = basejump
|
||||
MDNlinks: Array
|
||||
});
|
||||
|
||||
module.exports = mongoose.model('Challenge', challengeSchema);
|
||||
|
@ -15,7 +15,6 @@ var coursewareSchema = new mongoose.Schema({
|
||||
description: Array,
|
||||
tests: Array,
|
||||
challengeSeed: Array,
|
||||
completionMessage: String, // Congratulations! You've finished our HTML and CSS track!
|
||||
challengeType: Number // 0 = html, 1 = javascript only, 2 = video, 3 = zipline, 4 = basejump
|
||||
});
|
||||
|
||||
|
@ -124,7 +124,10 @@ var userSchema = new mongoose.Schema({
|
||||
uncompletedCoursewares: Array,
|
||||
completedCoursewares: [
|
||||
{
|
||||
completedDate: Long,
|
||||
completedDate: {
|
||||
type: Long,
|
||||
default: Date.now()
|
||||
},
|
||||
_id: String,
|
||||
name: String,
|
||||
completedWith: String,
|
||||
@ -147,9 +150,25 @@ var userSchema = new mongoose.Schema({
|
||||
|
||||
// needsMigration has been deprecated, use needsSomeDataModeled
|
||||
needsMigration: { type: Boolean, default: true },
|
||||
finishedWaypoints: { type: Boolean, default: false },
|
||||
sendMonthlyEmail: { type: Boolean, default: true },
|
||||
challengesHash: {}
|
||||
challengesHash: {},
|
||||
currentChallenge: {},
|
||||
completedChallenges: [
|
||||
{
|
||||
completedDate: Long,
|
||||
_id: String,
|
||||
name: String,
|
||||
completedWith: String,
|
||||
solution: String,
|
||||
githubLink: String,
|
||||
verified: Boolean,
|
||||
challengeType: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
}
|
||||
],
|
||||
uncompletedChallenges: Array,
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -11,13 +11,14 @@
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node app.js",
|
||||
"lint": "eslint --ext=.js,.jsx .",
|
||||
"test": "mocha"
|
||||
},
|
||||
"license": "BSD-3-Clause",
|
||||
"contributors" : [
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Quincy Larson",
|
||||
"url" : "https://github.com/QuincyLarson"
|
||||
"url": "https://github.com/QuincyLarson"
|
||||
},
|
||||
{
|
||||
"name": "Nathan Leniz",
|
||||
@ -63,6 +64,7 @@
|
||||
"mongoose": "~4.0.1",
|
||||
"mongoose-long": "0.0.2",
|
||||
"morgan": "~1.5.0",
|
||||
"node-slack": "0.0.7",
|
||||
"nodemailer": "~1.3.0",
|
||||
"passport": "~0.2.1",
|
||||
"passport-facebook": "~1.0.3",
|
||||
@ -82,10 +84,13 @@
|
||||
"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",
|
||||
"chai": "~1.10.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",
|
||||
|
@ -20,6 +20,16 @@ li, .wrappable {
|
||||
word-wrap: break-word; /* IE 5+ */
|
||||
}
|
||||
|
||||
pre.wrappable {
|
||||
white-space: pre; /* CSS 2.0 */
|
||||
white-space: pre-wrap; /* CSS 2.1 */
|
||||
white-space: -pre-wrap; /* Opera 4-6 */
|
||||
white-space: -o-pre-wrap; /* Opera 7 */
|
||||
white-space: -moz-pre-wrap; /* Mozilla */
|
||||
white-space: -hp-pre-wrap; /* HP Printers */
|
||||
word-wrap: break-word; /* IE 5+ */
|
||||
}
|
||||
|
||||
html {
|
||||
position: relative;
|
||||
min-height: 100%;
|
||||
@ -236,8 +246,8 @@ ul {
|
||||
margin-top: -20px;
|
||||
}
|
||||
|
||||
.landing-p {
|
||||
font-size: 18px !important;
|
||||
.large-p {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.text-success {
|
||||
|
@ -1,262 +0,0 @@
|
||||
var widgets = [];
|
||||
var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("codeEditor"), {
|
||||
lineNumbers: true,
|
||||
mode: "javascript",
|
||||
theme: 'monokai',
|
||||
runnable: true,
|
||||
lint: true,
|
||||
matchBrackets: true,
|
||||
autoCloseBrackets: true,
|
||||
scrollbarStyle: 'null',
|
||||
lineWrapping: true,
|
||||
gutters: ["CodeMirror-lint-markers"],
|
||||
onKeyEvent: doLinting
|
||||
});
|
||||
var editor = myCodeMirror;
|
||||
editor.setSize("100%", "auto");
|
||||
|
||||
// Hijack tab key to enter two spaces intead
|
||||
editor.setOption("extraKeys", {
|
||||
Tab: function(cm) {
|
||||
if (cm.somethingSelected()){
|
||||
cm.indentSelection("add");
|
||||
} else {
|
||||
var spaces = Array(cm.getOption("indentUnit") + 1).join(" ");
|
||||
cm.replaceSelection(spaces);
|
||||
}
|
||||
},
|
||||
"Shift-Tab": function(cm) {
|
||||
if (cm.somethingSelected()){
|
||||
cm.indentSelection("subtract");
|
||||
} else {
|
||||
var spaces = Array(cm.getOption("indentUnit") + 1).join(" ");
|
||||
cm.replaceSelection(spaces);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
"Ctrl-Enter": function() {
|
||||
bonfireExecute();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
var attempts = 0;
|
||||
if (attempts) {
|
||||
attempts = 0;
|
||||
}
|
||||
|
||||
// Default value for editor if one isn't provided in (i.e. a challenge)
|
||||
var nonChallengeValue = '/*Welcome to Bonfire, Free Code Camp\'s future CoderByte replacement.\n' +
|
||||
'Please feel free to use Bonfire as an in-browser playground and linting tool.\n' +
|
||||
'Note that you can also write tests using Chai.js by using the keywords assert and expect */\n\n' +
|
||||
'function test() {\n' +
|
||||
' assert(2 !== 3, "2 is not equal to 3");\n' +
|
||||
' return [1,2,3].map(function(elem) {\n' +
|
||||
' return elem * elem;\n' +
|
||||
' });\n' +
|
||||
'}\n' +
|
||||
'expect(test()).to.be.a("array");\n\n' +
|
||||
'assert.deepEqual(test(), [1,4,9]);\n\n' +
|
||||
'var foo = test();\n' +
|
||||
'foo.should.be.a("array");\n\n' +
|
||||
'test();\n';
|
||||
|
||||
var codeOutput = CodeMirror.fromTextArea(document.getElementById("codeOutput"), {
|
||||
lineNumbers: false,
|
||||
mode: "text",
|
||||
theme: 'monokai',
|
||||
readOnly: 'nocursor',
|
||||
lineWrapping: true
|
||||
});
|
||||
|
||||
codeOutput.setValue('/**\n' +
|
||||
' * Your output will go here.\n' + ' * Console.log() -type statements\n' +
|
||||
' * will appear in your browser\'s\n' + ' * DevTools JavaScript console.\n' +
|
||||
' */');
|
||||
codeOutput.setSize("100%", "100%");
|
||||
var info = editor.getScrollInfo();
|
||||
var after = editor.charCoords({line: editor.getCursor().line + 1, ch: 0}, "local").top;
|
||||
if (info.top + info.clientHeight < after)
|
||||
editor.scrollTo(null, after - info.clientHeight + 3);
|
||||
|
||||
var editorValue;
|
||||
|
||||
|
||||
var challengeSeed = challengeSeed || null;
|
||||
var tests = tests || [];
|
||||
|
||||
|
||||
if (challengeSeed !== null) {
|
||||
editorValue = challengeSeed;
|
||||
} else {
|
||||
editorValue = nonChallengeValue;
|
||||
}
|
||||
|
||||
|
||||
myCodeMirror.setValue(editorValue);
|
||||
|
||||
function doLinting () {
|
||||
editor.operation(function () {
|
||||
for (var i = 0; i < widgets.length; ++i)
|
||||
editor.removeLineWidget(widgets[i]);
|
||||
widgets.length = 0;
|
||||
JSHINT(editor.getValue());
|
||||
for (var i = 0; i < JSHINT.errors.length; ++i) {
|
||||
var err = JSHINT.errors[i];
|
||||
if (!err) continue;
|
||||
var msg = document.createElement("div");
|
||||
var icon = msg.appendChild(document.createElement("span"));
|
||||
icon.innerHTML = "!!";
|
||||
icon.className = "lint-error-icon";
|
||||
msg.appendChild(document.createTextNode(err.reason));
|
||||
msg.className = "lint-error";
|
||||
widgets.push(editor.addLineWidget(err.line - 1, msg, {
|
||||
coverGutter: false,
|
||||
noHScroll: true
|
||||
}));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$('#submitButton').on('click', function () {
|
||||
bonfireExecute();
|
||||
});
|
||||
|
||||
function bonfireExecute() {
|
||||
attempts++;
|
||||
ga('send', 'event', 'Bonfire', 'ran-code', challengeName);
|
||||
userTests= null;
|
||||
$('#codeOutput').empty();
|
||||
var userJavaScript = myCodeMirror.getValue();
|
||||
userJavaScript = removeComments(userJavaScript);
|
||||
userJavaScript = scrapeTests(userJavaScript);
|
||||
// simple fix in case the user forgets to invoke their function
|
||||
|
||||
submit(userJavaScript, function(cls, message) {
|
||||
if (cls) {
|
||||
codeOutput.setValue(message.error);
|
||||
runTests('Error', null);
|
||||
} else {
|
||||
codeOutput.setValue(message.output);
|
||||
message.input = removeLogs(message.input);
|
||||
runTests(null, message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
var userTests;
|
||||
var testSalt = Math.random();
|
||||
|
||||
|
||||
var scrapeTests = function(userJavaScript) {
|
||||
|
||||
// insert tests from mongo
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
userJavaScript += '\n' + tests[i];
|
||||
}
|
||||
|
||||
var counter = 0;
|
||||
var regex = new RegExp(/(expect(\s+)?\(.*\;)|(assert(\s+)?\(.*\;)|(assert\.\w.*\;)|(.*\.should\..*\;)/);
|
||||
var match = regex.exec(userJavaScript);
|
||||
while (match != null) {
|
||||
var replacement = '//' + counter + testSalt;
|
||||
userJavaScript = userJavaScript.substring(0, match.index) + replacement + userJavaScript.substring(match.index + match[0].length);
|
||||
|
||||
if (!userTests) {
|
||||
userTests= [];
|
||||
}
|
||||
userTests.push({"text": match[0], "line": counter, "err": null});
|
||||
counter++;
|
||||
match = regex.exec(userJavaScript);
|
||||
}
|
||||
|
||||
return userJavaScript;
|
||||
};
|
||||
|
||||
function removeComments(userJavaScript) {
|
||||
var regex = new RegExp(/(\/\*[^(\*\/)]*\*\/)|\/\/[^\n]*/g);
|
||||
return userJavaScript.replace(regex, '');
|
||||
}
|
||||
|
||||
function removeLogs(userJavaScript) {
|
||||
return userJavaScript.replace(/(console\.[\w]+\s*\(.*\;)/g, '');
|
||||
}
|
||||
|
||||
var pushed = false;
|
||||
var createTestDisplay = function() {
|
||||
if (pushed) {
|
||||
userTests.pop();
|
||||
}
|
||||
for (var i = 0; i < userTests.length;i++) {
|
||||
var test = userTests[i];
|
||||
var testDoc = document.createElement("div");
|
||||
if (test.err != null) {
|
||||
$(testDoc)
|
||||
.html("<div class='row'><div class='col-xs-1 text-center'><i class='ion-close-circled big-error-icon'></i></div><div class='col-xs-11 test-output wrappable grayed-out-test-output'>" + test.text + "</div><div class='col-xs-11 test-output wrappable'>" + test.err + "</div></div><div class='ten-pixel-break'/>")
|
||||
.prependTo($('#testSuite'))
|
||||
} else {
|
||||
$(testDoc)
|
||||
.html("<div class='row'><div class='col-xs-1 text-center'><i class='ion-checkmark-circled big-success-icon'></i></div><div class='col-xs-11 test-output test-vertical-center wrappable '>" + test.text + "</div></div><div class='ten-pixel-break'/>")
|
||||
.appendTo($('#testSuite'));
|
||||
}
|
||||
};
|
||||
};
|
||||
var assert = chai.assert;
|
||||
var expect = chai.expect;
|
||||
var should = chai.should();
|
||||
chai.config.showDiff = true;
|
||||
|
||||
var reassembleTest = function(test, data) {
|
||||
var lineNum = test.line;
|
||||
var regexp = new RegExp("\/\/" + lineNum + testSalt);
|
||||
return data.input.replace(regexp, test.text);
|
||||
};
|
||||
|
||||
var runTests = function(err, data) {
|
||||
var allTestsPassed = true;
|
||||
pushed = false;
|
||||
$('#testSuite').children().remove();
|
||||
if (err && userTests.length > 0) {
|
||||
userTests= [{text:"Program Execution Failure", err: "No user tests were run."}];
|
||||
createTestDisplay();
|
||||
} else if (userTests) {
|
||||
userTests.push(false);
|
||||
pushed = true;
|
||||
userTests.forEach(function(test, ix, arr){
|
||||
try {
|
||||
if (test) {
|
||||
var output = eval(reassembleTest(test, data));
|
||||
}
|
||||
} catch(error) {
|
||||
allTestsPassed = false;
|
||||
arr[ix].err = error.message;
|
||||
} finally {
|
||||
if (!test) {
|
||||
createTestDisplay();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (allTestsPassed) {
|
||||
allTestsPassed = false;
|
||||
showCompletion();
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
function showCompletion() {
|
||||
var time = Math.floor(Date.now()) - started;
|
||||
ga('send', 'event', 'Challenge', 'solved', challengeName + ', Time: ' + time +', Attempts: ' + attempts);
|
||||
$('#complete-bonfire-dialog').modal('show');
|
||||
$('#complete-bonfire-dialog').keydown(function(e) {
|
||||
if (e.ctrlKey && e.keyCode == 13) {
|
||||
$('.next-bonfire-button').click();
|
||||
}
|
||||
});
|
||||
}
|
@ -723,7 +723,7 @@
|
||||
<li>Add support for <a href="manual.html#option_lineWrapping">line
|
||||
wrapping</a> and <a href="manual.html#hideLine">code
|
||||
folding</a>.</li>
|
||||
<li>Add <a href="../mode/gfm/index.html">Github-style Markdown</a> mode.</li>
|
||||
<li>Add <a href="../mode/gfm/index.html">GitHub-style Markdown</a> mode.</li>
|
||||
<li>Add <a href="../theme/monokai.css">Monokai</a>
|
||||
and <a href="../theme/rubyblue.css">Rubyblue</a> themes.</li>
|
||||
<li>Add <a href="manual.html#setBookmark"><code>setBookmark</code></a> method.</li>
|
||||
|
@ -107,11 +107,11 @@ var tests = tests || [];
|
||||
var allSeeds = '';
|
||||
(function() {
|
||||
challengeSeed.forEach(function(elem) {
|
||||
allSeeds += elem + '\n';
|
||||
allSeeds += elem.replace(/fccss/g, '<script>').replace(/fcces/g,'</script>') + '\n';
|
||||
});
|
||||
editor.setValue(allSeeds);
|
||||
})();
|
||||
|
||||
editor.setValue(allSeeds);
|
||||
|
||||
function doLinting () {
|
||||
editor.operation(function () {
|
||||
@ -139,7 +139,7 @@ function doLinting () {
|
||||
//$('#testSuite').empty();
|
||||
function showCompletion() {
|
||||
var time = Math.floor(Date.now()) - started;
|
||||
ga('send', 'event', 'Challenge', 'solved', challengeName + ', Time: ' + time);
|
||||
ga('send', 'event', 'Challenge', 'solved', challenge_Name + ', Time: ' + time);
|
||||
$('#next-courseware-button').removeAttr('disabled');
|
||||
$('#next-courseware-button').addClass('animated tada');
|
||||
if (!userLoggedIn) {
|
||||
|
@ -1,246 +0,0 @@
|
||||
var widgets = [];
|
||||
var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("codeEditor"), {
|
||||
lineNumbers: true,
|
||||
mode: "javascript",
|
||||
theme: 'monokai',
|
||||
runnable: true,
|
||||
lint: true,
|
||||
matchBrackets: true,
|
||||
autoCloseBrackets: true,
|
||||
scrollbarStyle: 'null',
|
||||
lineWrapping: true,
|
||||
gutters: ["CodeMirror-lint-markers"],
|
||||
onKeyEvent: doLinting
|
||||
});
|
||||
var editor = myCodeMirror;
|
||||
editor.setSize("100%", "auto");
|
||||
|
||||
// Hijack tab key to enter two spaces intead
|
||||
editor.setOption("extraKeys", {
|
||||
Tab: function(cm) {
|
||||
if (cm.somethingSelected()){
|
||||
cm.indentSelection("add");
|
||||
} else {
|
||||
var spaces = Array(cm.getOption("indentUnit") + 1).join(" ");
|
||||
cm.replaceSelection(spaces);
|
||||
}
|
||||
},
|
||||
"Shift-Tab": function(cm) {
|
||||
if (cm.somethingSelected()){
|
||||
cm.indentSelection("subtract");
|
||||
} else {
|
||||
var spaces = Array(cm.getOption("indentUnit") + 1).join(" ");
|
||||
cm.replaceSelection(spaces);
|
||||
}
|
||||
},
|
||||
"Ctrl-Enter": function() {
|
||||
bonfireExecute();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
var attempts = 0;
|
||||
if (attempts) {
|
||||
attempts = 0;
|
||||
}
|
||||
|
||||
|
||||
var codeOutput = CodeMirror.fromTextArea(document.getElementById("codeOutput"), {
|
||||
lineNumbers: false,
|
||||
mode: "text",
|
||||
theme: 'monokai',
|
||||
readOnly: 'nocursor',
|
||||
lineWrapping: true
|
||||
});
|
||||
|
||||
codeOutput.setValue('/**\n' +
|
||||
' * Your output will go here.\n' + ' * Console.log() -type statements\n' +
|
||||
' * will appear in your browser\'s\n' + ' * DevTools JavaScript console.\n' +
|
||||
' */');
|
||||
codeOutput.setSize("100%", "100%");
|
||||
var info = editor.getScrollInfo();
|
||||
var after = editor.charCoords({line: editor.getCursor().line + 1, ch: 0}, "local").top;
|
||||
if (info.top + info.clientHeight < after)
|
||||
editor.scrollTo(null, after - info.clientHeight + 3);
|
||||
|
||||
var editorValue;
|
||||
|
||||
|
||||
var challengeSeed = challengeSeed || null;
|
||||
var tests = tests || [];
|
||||
|
||||
var allSeeds = '';
|
||||
(function() {
|
||||
challengeSeed.forEach(function(elem) {
|
||||
allSeeds += elem + '\n';
|
||||
});
|
||||
})();
|
||||
|
||||
editorValue = allSeeds;
|
||||
|
||||
|
||||
myCodeMirror.setValue(editorValue);
|
||||
|
||||
function doLinting () {
|
||||
editor.operation(function () {
|
||||
for (var i = 0; i < widgets.length; ++i)
|
||||
editor.removeLineWidget(widgets[i]);
|
||||
widgets.length = 0;
|
||||
JSHINT(editor.getValue());
|
||||
for (var i = 0; i < JSHINT.errors.length; ++i) {
|
||||
var err = JSHINT.errors[i];
|
||||
if (!err) continue;
|
||||
var msg = document.createElement("div");
|
||||
var icon = msg.appendChild(document.createElement("span"));
|
||||
icon.innerHTML = "!!";
|
||||
icon.className = "lint-error-icon";
|
||||
msg.appendChild(document.createTextNode(err.reason));
|
||||
msg.className = "lint-error";
|
||||
widgets.push(editor.addLineWidget(err.line - 1, msg, {
|
||||
coverGutter: false,
|
||||
noHScroll: true
|
||||
}));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$('#submitButton').on('click', function () {
|
||||
bonfireExecute();
|
||||
});
|
||||
|
||||
function bonfireExecute() {
|
||||
attempts++;
|
||||
ga('send', 'event', 'Challenge', 'ran-code', challengeName);
|
||||
userTests= null;
|
||||
$('#codeOutput').empty();
|
||||
var userJavaScript = myCodeMirror.getValue();
|
||||
userJavaScript = removeComments(userJavaScript);
|
||||
userJavaScript = scrapeTests(userJavaScript);
|
||||
// simple fix in case the user forgets to invoke their function
|
||||
|
||||
submit(userJavaScript, function(cls, message) {
|
||||
if (cls) {
|
||||
codeOutput.setValue(message.error);
|
||||
runTests('Error', null);
|
||||
} else {
|
||||
codeOutput.setValue(message.output);
|
||||
message.input = removeLogs(message.input);
|
||||
runTests(null, message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
var userTests;
|
||||
var testSalt = Math.random();
|
||||
|
||||
|
||||
var scrapeTests = function(userJavaScript) {
|
||||
|
||||
// insert tests from mongo
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
userJavaScript += '\n' + tests[i];
|
||||
}
|
||||
|
||||
var counter = 0;
|
||||
var regex = new RegExp(/(expect(\s+)?\(.*\;)|(assert(\s+)?\(.*\;)|(assert\.\w.*\;)|(.*\.should\..*\;)/);
|
||||
var match = regex.exec(userJavaScript);
|
||||
while (match != null) {
|
||||
var replacement = '//' + counter + testSalt;
|
||||
userJavaScript = userJavaScript.substring(0, match.index) + replacement + userJavaScript.substring(match.index + match[0].length);
|
||||
|
||||
if (!userTests) {
|
||||
userTests= [];
|
||||
}
|
||||
userTests.push({"text": match[0], "line": counter, "err": null});
|
||||
counter++;
|
||||
match = regex.exec(userJavaScript);
|
||||
}
|
||||
|
||||
return userJavaScript;
|
||||
};
|
||||
|
||||
function removeComments(userJavaScript) {
|
||||
var regex = new RegExp(/(\/\*[^(\*\/)]*\*\/)|\/\/[^\n]*/g);
|
||||
return userJavaScript.replace(regex, '');
|
||||
}
|
||||
|
||||
function removeLogs(userJavaScript) {
|
||||
return userJavaScript.replace(/(console\.[\w]+\s*\(.*\;)/g, '');
|
||||
}
|
||||
|
||||
var pushed = false;
|
||||
var createTestDisplay = function() {
|
||||
if (pushed) {
|
||||
userTests.pop();
|
||||
}
|
||||
for (var i = 0; i < userTests.length;i++) {
|
||||
var test = userTests[i];
|
||||
var testDoc = document.createElement("div");
|
||||
if (test.err != null) {
|
||||
console.log('Should be displaying bad tests');
|
||||
$(testDoc)
|
||||
.html("<div class='row'><div class='col-xs-2 text-center'><i class='ion-close-circled big-error-icon'></i></div><div class='col-xs-10 test-output wrappable test-vertical-center grayed-out-test-output'>" + test.text + "</div><div class='col-xs-10 test-output wrappable'>" + test.err + "</div></div><div class='ten-pixel-break'/>")
|
||||
.prependTo($('#testSuite'))
|
||||
} else {
|
||||
$(testDoc)
|
||||
.html("<div class='row'><div class='col-xs-2 text-center'><i class='ion-checkmark-circled big-success-icon'></i></div><div class='col-xs-10 test-output test-vertical-center wrappable grayed-out-test-output'>" + test.text + "</div></div><div class='ten-pixel-break'/>")
|
||||
.appendTo($('#testSuite'));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var expect = chai.expect;
|
||||
|
||||
|
||||
var reassembleTest = function(test, data) {
|
||||
var lineNum = test.line;
|
||||
var regexp = new RegExp("\/\/" + lineNum + testSalt);
|
||||
return data.input.replace(regexp, test.text);
|
||||
};
|
||||
|
||||
var runTests = function(err, data) {
|
||||
var allTestsPassed = true;
|
||||
pushed = false;
|
||||
$('#testSuite').children().remove();
|
||||
if (err && userTests.length > 0) {
|
||||
userTests= [{text:"Program Execution Failure", err: "No user tests were run."}];
|
||||
createTestDisplay();
|
||||
} else if (userTests) {
|
||||
userTests.push(false);
|
||||
pushed = true;
|
||||
userTests.forEach(function(test, ix, arr){
|
||||
try {
|
||||
if (test) {
|
||||
var output = eval(reassembleTest(test, data));
|
||||
}
|
||||
} catch(error) {
|
||||
allTestsPassed = false;
|
||||
arr[ix].err = error.message;
|
||||
} finally {
|
||||
if (!test) {
|
||||
createTestDisplay();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (allTestsPassed) {
|
||||
allTestsPassed = false;
|
||||
showCompletion();
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
function showCompletion() {
|
||||
var time = Math.floor(Date.now()) - started;
|
||||
ga('send', 'event', 'Challenge', 'solved', challengeName + ', Time: ' + time +', Attempts: ' + attempts);
|
||||
$('#complete-courseware-dialog').modal('show');
|
||||
$('#complete-courseware-dialog').keydown(function(e) {
|
||||
if (e.ctrlKey && e.keyCode == 13) {
|
||||
$('#next-courseware-button').click();
|
||||
}
|
||||
});
|
||||
}
|
266
public/js/lib/coursewares/coursewaresJSFramework_0.0.2.js
Normal file
266
public/js/lib/coursewares/coursewaresJSFramework_0.0.2.js
Normal file
@ -0,0 +1,266 @@
|
||||
var widgets = [];
|
||||
var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("codeEditor"), {
|
||||
lineNumbers: true,
|
||||
mode: "javascript",
|
||||
theme: 'monokai',
|
||||
runnable: true,
|
||||
lint: true,
|
||||
matchBrackets: true,
|
||||
autoCloseBrackets: true,
|
||||
scrollbarStyle: 'null',
|
||||
lineWrapping: true,
|
||||
gutters: ["CodeMirror-lint-markers"],
|
||||
onKeyEvent: doLinting
|
||||
});
|
||||
var editor = myCodeMirror;
|
||||
editor.setSize("100%", "auto");
|
||||
|
||||
// Hijack tab key to enter two spaces intead
|
||||
editor.setOption("extraKeys", {
|
||||
Tab: function(cm) {
|
||||
if (cm.somethingSelected()){
|
||||
cm.indentSelection("add");
|
||||
} else {
|
||||
var spaces = Array(cm.getOption("indentUnit") + 1).join(" ");
|
||||
cm.replaceSelection(spaces);
|
||||
}
|
||||
},
|
||||
"Shift-Tab": function(cm) {
|
||||
if (cm.somethingSelected()){
|
||||
cm.indentSelection("subtract");
|
||||
} else {
|
||||
var spaces = Array(cm.getOption("indentUnit") + 1).join(" ");
|
||||
cm.replaceSelection(spaces);
|
||||
}
|
||||
},
|
||||
"Ctrl-Enter": function() {
|
||||
bonfireExecute();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
var attempts = 0;
|
||||
if (attempts) {
|
||||
attempts = 0;
|
||||
}
|
||||
|
||||
|
||||
var codeOutput = CodeMirror.fromTextArea(document.getElementById("codeOutput"), {
|
||||
lineNumbers: false,
|
||||
mode: "text",
|
||||
theme: 'monokai',
|
||||
readOnly: 'nocursor',
|
||||
lineWrapping: true
|
||||
});
|
||||
|
||||
codeOutput.setValue('/**\n' +
|
||||
' * Your output will go here.\n' + ' * Console.log() -type statements\n' +
|
||||
' * will appear in your browser\'s\n' + ' * DevTools JavaScript console.\n' +
|
||||
' */');
|
||||
codeOutput.setSize("100%", "100%");
|
||||
var info = editor.getScrollInfo();
|
||||
var after = editor.charCoords({line: editor.getCursor().line + 1, ch: 0}, "local").top;
|
||||
if (info.top + info.clientHeight < after)
|
||||
editor.scrollTo(null, after - info.clientHeight + 3);
|
||||
|
||||
var editorValue;
|
||||
|
||||
|
||||
var challengeSeed = challengeSeed || null;
|
||||
var tests = tests || [];
|
||||
|
||||
var allSeeds = '';
|
||||
(function() {
|
||||
challengeSeed.forEach(function(elem) {
|
||||
allSeeds += elem + '\n';
|
||||
});
|
||||
})();
|
||||
|
||||
editorValue = allSeeds;
|
||||
|
||||
|
||||
myCodeMirror.setValue(editorValue);
|
||||
|
||||
function doLinting () {
|
||||
editor.operation(function () {
|
||||
for (var i = 0; i < widgets.length; ++i)
|
||||
editor.removeLineWidget(widgets[i]);
|
||||
widgets.length = 0;
|
||||
JSHINT(editor.getValue());
|
||||
for (var i = 0; i < JSHINT.errors.length; ++i) {
|
||||
var err = JSHINT.errors[i];
|
||||
if (!err) continue;
|
||||
var msg = document.createElement("div");
|
||||
var icon = msg.appendChild(document.createElement("span"));
|
||||
icon.innerHTML = "!!";
|
||||
icon.className = "lint-error-icon";
|
||||
msg.appendChild(document.createTextNode(err.reason));
|
||||
msg.className = "lint-error";
|
||||
widgets.push(editor.addLineWidget(err.line - 1, msg, {
|
||||
coverGutter: false,
|
||||
noHScroll: true
|
||||
}));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$('#submitButton').on('click', function () {
|
||||
bonfireExecute();
|
||||
});
|
||||
|
||||
function bonfireExecute() {
|
||||
attempts++;
|
||||
ga('send', 'event', 'Challenge', 'ran-code', challenge_Name);
|
||||
userTests= null;
|
||||
$('#codeOutput').empty();
|
||||
var userJavaScript = myCodeMirror.getValue();
|
||||
userJavaScript = removeComments(userJavaScript);
|
||||
userJavaScript = scrapeTests(userJavaScript);
|
||||
// simple fix in case the user forgets to invoke their function
|
||||
|
||||
submit(userJavaScript, function(cls, message) {
|
||||
if (cls) {
|
||||
codeOutput.setValue(message.error);
|
||||
runTests('Error', null);
|
||||
} else {
|
||||
codeOutput.setValue(message.output);
|
||||
message.input = removeLogs(message.input);
|
||||
runTests(null, message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
var userTests;
|
||||
var testSalt = Math.random();
|
||||
|
||||
|
||||
var scrapeTests = function(userJavaScript) {
|
||||
|
||||
// insert tests from mongo
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
userJavaScript += '\n' + tests[i];
|
||||
}
|
||||
|
||||
var counter = 0;
|
||||
var regex = new RegExp(/(expect(\s+)?\(.*\;)|(assert(\s+)?\(.*\;)|(assert\.\w.*\;)|(.*\.should\..*\;)/);
|
||||
var match = regex.exec(userJavaScript);
|
||||
while (match != null) {
|
||||
var replacement = '//' + counter + testSalt;
|
||||
userJavaScript = userJavaScript.substring(0, match.index) + replacement + userJavaScript.substring(match.index + match[0].length);
|
||||
|
||||
if (!userTests) {
|
||||
userTests= [];
|
||||
}
|
||||
userTests.push({"text": match[0], "line": counter, "err": null});
|
||||
counter++;
|
||||
match = regex.exec(userJavaScript);
|
||||
}
|
||||
|
||||
return userJavaScript;
|
||||
};
|
||||
|
||||
function removeComments(userJavaScript) {
|
||||
var regex = new RegExp(/(\/\*[^(\*\/)]*\*\/)|\/\/[^\n]*/g);
|
||||
return userJavaScript.replace(regex, '');
|
||||
}
|
||||
|
||||
function removeLogs(userJavaScript) {
|
||||
return userJavaScript.replace(/(console\.[\w]+\s*\(.*\;)/g, '');
|
||||
}
|
||||
|
||||
var pushed = false;
|
||||
var createTestDisplay = function() {
|
||||
if (pushed) {
|
||||
userTests.pop();
|
||||
}
|
||||
for (var i = 0; i < userTests.length;i++) {
|
||||
var test = userTests[i];
|
||||
var testDoc = document.createElement("div");
|
||||
if (test.err != null) {
|
||||
console.log('Should be displaying bad tests');
|
||||
$(testDoc)
|
||||
.html("<div class='row'><div class='col-xs-2 text-center'><i class='ion-close-circled big-error-icon'></i></div><div class='col-xs-10 test-output wrappable test-vertical-center grayed-out-test-output'>" + test.text + "</div><div class='col-xs-10 test-output wrappable'>" + test.err + "</div></div><div class='ten-pixel-break'/>")
|
||||
.prependTo($('#testSuite'))
|
||||
} else {
|
||||
$(testDoc)
|
||||
.html("<div class='row'><div class='col-xs-2 text-center'><i class='ion-checkmark-circled big-success-icon'></i></div><div class='col-xs-10 test-output test-vertical-center wrappable grayed-out-test-output'>" + test.text + "</div></div><div class='ten-pixel-break'/>")
|
||||
.appendTo($('#testSuite'));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var expect = chai.expect;
|
||||
var assert = chai.assert;
|
||||
var should = chai.should;
|
||||
|
||||
|
||||
var reassembleTest = function(test, data) {
|
||||
var lineNum = test.line;
|
||||
var regexp = new RegExp("\/\/" + lineNum + testSalt);
|
||||
return data.input.replace(regexp, test.text);
|
||||
};
|
||||
|
||||
var runTests = function(err, data) {
|
||||
var allTestsPassed = true;
|
||||
pushed = false;
|
||||
$('#testSuite').children().remove();
|
||||
if (err && userTests.length > 0) {
|
||||
userTests= [{text:"Program Execution Failure", err: "No user tests were run."}];
|
||||
createTestDisplay();
|
||||
} else if (userTests) {
|
||||
userTests.push(false);
|
||||
pushed = true;
|
||||
userTests.forEach(function(test, ix, arr){
|
||||
try {
|
||||
if (test) {
|
||||
var output = eval(reassembleTest(test, data));
|
||||
}
|
||||
} catch(error) {
|
||||
allTestsPassed = false;
|
||||
arr[ix].err = error.message;
|
||||
} finally {
|
||||
if (!test) {
|
||||
createTestDisplay();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (allTestsPassed) {
|
||||
allTestsPassed = false;
|
||||
showCompletion();
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
function showCompletion() {
|
||||
var time = Math.floor(Date.now()) - started;
|
||||
ga('send', 'event', 'Challenge', 'solved', challenge_Name + ', Time: ' + time +', Attempts: ' + attempts);
|
||||
var bonfireSolution = myCodeMirror.getValue();
|
||||
var didCompleteWith = $('#completed-with').val() || null;
|
||||
$.post(
|
||||
'/completed-bonfire/',
|
||||
{
|
||||
challengeInfo: {
|
||||
challengeId: challenge_Id,
|
||||
challengeName: challenge_Name,
|
||||
completedWith: didCompleteWith,
|
||||
challengeType: challengeType,
|
||||
solution: bonfireSolution
|
||||
}
|
||||
}, function(res) {
|
||||
if (res) {
|
||||
$('#complete-courseware-dialog').modal('show');
|
||||
$('#complete-courseware-dialog').keydown(function (e) {
|
||||
if (e.ctrlKey && e.keyCode == 13) {
|
||||
$('#next-courseware-button').click();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}
|
@ -16,6 +16,63 @@ $(document).ready(function() {
|
||||
|
||||
setCSRFToken($('meta[name="csrf-token"]').attr('content'));
|
||||
|
||||
$('#i-want-help').on('click', function() {
|
||||
var editorValue = editor.getValue();
|
||||
var currentLocation = window.location.href;
|
||||
$.post(
|
||||
'/get-help',
|
||||
{
|
||||
payload: {
|
||||
code: editorValue,
|
||||
challenge: currentLocation
|
||||
}
|
||||
},
|
||||
function(res) {
|
||||
if (res) {
|
||||
window.open('https://freecode.slack.com/messages/help/', '_blank')
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
$('#i-want-help-editorless').on('click', function() {
|
||||
var currentLocation = window.location.href;
|
||||
$.post(
|
||||
'/get-help',
|
||||
{
|
||||
payload: {
|
||||
challenge: currentLocation
|
||||
}
|
||||
},
|
||||
function(res) {
|
||||
if (res) {
|
||||
window.open('https://freecode.slack.com/messages/help/', '_blank')
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
$('#report-issue').on('click', function() {
|
||||
window.open('https://github.com/freecodecamp/freecodecamp/issues/new?title=Challenge '+ window.location.href +' has an issue &body=Please%20tell%20us%20in%20detail%20here%20how%20we%20can%20make%20this%20challenge%20better.', '_blank')
|
||||
});
|
||||
|
||||
$('#i-want-to-pair').on('click', function() {
|
||||
var currentLocation = window.location.href;
|
||||
$.post(
|
||||
'/get-pair',
|
||||
{
|
||||
payload: {
|
||||
challenge: currentLocation
|
||||
}
|
||||
},
|
||||
function(res) {
|
||||
if (res) {
|
||||
window.open('https://freecode.slack.com/messages/letspair/', '_blank')
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
$('.checklist-element').each(function() {
|
||||
var checklistElementId = $(this).attr('id');
|
||||
if(!!localStorage[checklistElementId]) {
|
||||
@ -47,28 +104,6 @@ $(document).ready(function() {
|
||||
}
|
||||
});
|
||||
|
||||
function completedBonfire(didCompleteWith, bonfireSolution, thisBonfireHash, bonfireName) {
|
||||
$('#complete-bonfire-dialog').modal('show');
|
||||
// Only post to server if there is an authenticated user
|
||||
if ($('.signup-btn-nav').length < 1) {
|
||||
$.post(
|
||||
'/completed-bonfire',
|
||||
{
|
||||
bonfireInfo: {
|
||||
completedWith: didCompleteWith,
|
||||
solution: bonfireSolution,
|
||||
bonfireHash: thisBonfireHash,
|
||||
bonfireName: bonfireName
|
||||
}
|
||||
},
|
||||
function(res) {
|
||||
if (res) {
|
||||
window.location.href = '/bonfires'
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function completedFieldGuide(fieldGuideId) {
|
||||
if ($('.signup-btn-nav').length < 1) {
|
||||
$.post(
|
||||
@ -86,15 +121,6 @@ $(document).ready(function() {
|
||||
}
|
||||
}
|
||||
|
||||
$('.next-bonfire-button').on('click', function() {
|
||||
var bonfireSolution = myCodeMirror.getValue();
|
||||
var thisBonfireHash = passedBonfireHash || null;
|
||||
var bonfireName = $('#bonfire-name').text();
|
||||
var didCompleteWith = $('#completed-with').val() || null;
|
||||
completedBonfire(didCompleteWith, bonfireSolution, thisBonfireHash, bonfireName);
|
||||
|
||||
});
|
||||
|
||||
$('.next-field-guide-button').on('click', function() {
|
||||
var fieldGuideId = $('#fieldGuideId').text();
|
||||
completedFieldGuide(fieldGuideId);
|
||||
@ -112,66 +138,70 @@ $(document).ready(function() {
|
||||
$('#complete-zipline-or-basejump-dialog').modal('show');
|
||||
});
|
||||
|
||||
$('#complete-bonfire-dialog').on('hidden.bs.modal', function() {
|
||||
editor.focus();
|
||||
});
|
||||
|
||||
$('#complete-courseware-dialog').on('hidden.bs.modal', function() {
|
||||
editor.focus();
|
||||
});
|
||||
|
||||
var challengeTypes = {
|
||||
'HTML_CSS_JQ': 0,
|
||||
'JAVASCRIPT': 1,
|
||||
'VIDEO': 2,
|
||||
'ZIPLINE': 3,
|
||||
'BASEJUMP': 4,
|
||||
'BONFIRE': 5
|
||||
};
|
||||
$('#next-courseware-button').on('click', function() {
|
||||
if ($('.signup-btn-nav').length < 1) {
|
||||
switch (challengeType) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case challengeTypes.HTML_CSS_JQ:
|
||||
case challengeTypes.JAVASCRIPT:
|
||||
case challengeTypes.VIDEO:
|
||||
console.log(challenge_Id);
|
||||
$.post(
|
||||
'/completed-courseware/',
|
||||
'/completed-challenge/',
|
||||
{
|
||||
coursewareInfo: {
|
||||
coursewareHash: passedCoursewareHash,
|
||||
coursewareName: passedCoursewareName
|
||||
challengeInfo: {
|
||||
challengeId: challenge_Id,
|
||||
challengeName: challenge_Name
|
||||
}
|
||||
}).success(
|
||||
function(res) {
|
||||
if (res) {
|
||||
window.location.href = '/challenges';
|
||||
window.location.href = '/challenges/next-challenge';
|
||||
}
|
||||
}
|
||||
);
|
||||
break;
|
||||
case 3:
|
||||
case challengeTypes.ZIPLINE:
|
||||
var didCompleteWith = $('#completed-with').val() || null;
|
||||
var publicURL = $('#public-url').val() || null;
|
||||
$.post(
|
||||
'/completed-zipline-or-basejump/',
|
||||
{
|
||||
coursewareInfo: {
|
||||
coursewareHash: passedCoursewareHash,
|
||||
coursewareName: passedCoursewareName,
|
||||
challengeInfo: {
|
||||
challengeId: challenge_Id,
|
||||
challengeName: challenge_Name,
|
||||
completedWith: didCompleteWith,
|
||||
publicURL: publicURL,
|
||||
challengeType: challengeType
|
||||
}
|
||||
}).success(
|
||||
function() {
|
||||
window.location.href = '/challenges';
|
||||
window.location.href = '/challenges/next-challenge';
|
||||
}).fail(
|
||||
function() {
|
||||
window.location.href = '/challenges';
|
||||
});
|
||||
break;
|
||||
case 4:
|
||||
case challengeTypes.BASEJUMP:
|
||||
var didCompleteWith = $('#completed-with').val() || null;
|
||||
var publicURL = $('#public-url').val() || null;
|
||||
var githubURL = $('#github-url').val() || null;
|
||||
$.post(
|
||||
'/completed-zipline-or-basejump/',
|
||||
{
|
||||
coursewareInfo: {
|
||||
coursewareHash: passedCoursewareHash,
|
||||
coursewareName: passedCoursewareName,
|
||||
challengeInfo: {
|
||||
challengeId: challenge_Id,
|
||||
challengeName: challenge_Name,
|
||||
completedWith: didCompleteWith,
|
||||
publicURL: publicURL,
|
||||
githubURL: githubURL,
|
||||
@ -179,22 +209,19 @@ $(document).ready(function() {
|
||||
verified: false
|
||||
}
|
||||
}).success(function() {
|
||||
window.location.href = '/challenges';
|
||||
window.location.href = '/challenges/next-challenge';
|
||||
}).fail(function() {
|
||||
window.location.replace(window.location.href);
|
||||
});
|
||||
break;
|
||||
case challengeTypes.BONFIRE:
|
||||
window.location.href = '/challenges/next-challenge';
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
$('#showAllButton').on('click', function() {
|
||||
$('#show-all-dialog').modal('show');
|
||||
});
|
||||
|
||||
$('.next-challenge-button').on('click', function() {
|
||||
l = location.pathname.split('/');
|
||||
window.location = '/challenges/' + (parseInt(l[l.length - 1]) + 1);
|
||||
@ -379,28 +406,28 @@ profileValidation.directive('uniqueUsername', ['$http', function($http) {
|
||||
|
||||
profileValidation.directive('existingUsername',
|
||||
['$http', function($http) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: 'ngModel',
|
||||
link: function (scope, element, attrs, ngModel) {
|
||||
element.bind('keyup', function (event) {
|
||||
if (element.val().length > 0) {
|
||||
ngModel.$setValidity('exists', false);
|
||||
} else {
|
||||
element.removeClass('ng-dirty');
|
||||
ngModel.$setPristine();
|
||||
}
|
||||
if (element.val()) {
|
||||
$http
|
||||
.get('/api/checkExistingUsername/' + element.val())
|
||||
.success(function (data) {
|
||||
ngModel.$setValidity('exists', data);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}]);
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: 'ngModel',
|
||||
link: function (scope, element, attrs, ngModel) {
|
||||
element.bind('keyup', function (event) {
|
||||
if (element.val().length > 0) {
|
||||
ngModel.$setValidity('exists', false);
|
||||
} else {
|
||||
element.removeClass('ng-dirty');
|
||||
ngModel.$setPristine();
|
||||
}
|
||||
if (element.val()) {
|
||||
$http
|
||||
.get('/api/checkExistingUsername/' + element.val())
|
||||
.success(function (data) {
|
||||
ngModel.$setValidity('exists', data);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
profileValidation.directive('uniqueEmail', ['$http', function($http) {
|
||||
return {
|
||||
|
@ -1,830 +0,0 @@
|
||||
[
|
||||
{
|
||||
"_id": "ad7123c8c441eddfaeb5bdef",
|
||||
"name": "Meet Bonfire",
|
||||
"difficulty": "0",
|
||||
"description": [
|
||||
"Click the button below for further instructions.",
|
||||
"Your goal is to fix the failing test.",
|
||||
"First, run all the tests by clicking \"Run code\" 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;"
|
||||
],
|
||||
"challengeSeed": "function meetBonfire(argument) {\n // Good luck!\n console.log(\"you can read this function's argument in the developer tools\", argument);\n\n return false;\n}\n\n\n\nmeetBonfire(\"You can do this!\");"
|
||||
},
|
||||
{
|
||||
"_id": "a202eed8fc186c8434cb6d61",
|
||||
"name": "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');"
|
||||
],
|
||||
"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."
|
||||
],
|
||||
"challengeSeed": "function reverseString(str) {\n return str;\r\n}\n\nreverseString('hello');",
|
||||
"MDNlinks" : ["Global String Object", "String.split()", "Array.reverse()", "Array.join()"]
|
||||
},
|
||||
{
|
||||
"_id": "a302f7aae1aa3152a5b413bc",
|
||||
"name": "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);"
|
||||
],
|
||||
"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"
|
||||
],
|
||||
"challengeSeed": "function factorialize(num) {\n return num;\r\n}\n\nfactorialize(5);",
|
||||
"MDNlinks" : ["Arithmetic Operators"]
|
||||
},
|
||||
{
|
||||
"_id": "aaa48de84e1ecc7c742e1124",
|
||||
"name": "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."
|
||||
],
|
||||
"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);"
|
||||
],
|
||||
"challengeSeed": "function palindrome(str) {\n // Good luck!\n return true;\n}\n\n\n\npalindrome(\"eye\");",
|
||||
"MDNlinks" : ["String.replace()", "String.toLowerCase()"]
|
||||
},
|
||||
{
|
||||
"_id": "a26cbbe9ad8655a977e1ceb5",
|
||||
"name": "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."
|
||||
],
|
||||
"challengeSeed": "function findLongestWord(str) {\n return str.length;\r\n}\n\nfindLongestWord('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);"
|
||||
],
|
||||
"MDNlinks" : ["String.split()", "String.length"]
|
||||
},
|
||||
{
|
||||
"_id": "ab6137d4e35944e21037b769",
|
||||
"name": "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'."
|
||||
],
|
||||
"challengeSeed": "function titleCase(str) {\n return str;\r\n}\n\ntitleCase(\"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\");"
|
||||
],
|
||||
"MDNlinks" : ["String.charAt()"]
|
||||
},
|
||||
{
|
||||
"_id": "a789b3483989747d63b0e427",
|
||||
"name": "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."
|
||||
],
|
||||
"challengeSeed": "function largestOfFour(arr) {\n // You can do this!\r\n return arr;\r\n}\n\nlargestOfFour([[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([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]])).should.eql([5,27,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]));"
|
||||
],
|
||||
"MDNlinks" : ["Comparison Operators"]
|
||||
},
|
||||
{
|
||||
"_id": "acda2fb1324d9b0fa741e6b5",
|
||||
"name": "Confirm the Ending",
|
||||
"difficulty": "1.07",
|
||||
"description": [
|
||||
"Check if a string (first argument) ends with the given target string (second argument)."
|
||||
],
|
||||
|
||||
"challengeSeed": "function end(str, target) {\n // \"Never give up and good luck will find you.\"\r\n // -- Falcor\r\n return str;\r\n}\n\nend('Bastian', 'n');",
|
||||
"tests": [
|
||||
"assert.strictEqual(end('Bastian', 'n'), true, 'should equal true if target equals 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');"
|
||||
],
|
||||
"MDNlinks" : ["String.substr()"]
|
||||
},
|
||||
{
|
||||
"_id": "afcc8d540bea9ea2669306b6",
|
||||
"name": "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."
|
||||
],
|
||||
"challengeSeed": "function repeat(str, num) {\n // repeat after me\r\n return str;\r\n}\n\nrepeat('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');"
|
||||
],
|
||||
"MDNlinks" : ["Global String Object"]
|
||||
},
|
||||
{
|
||||
"_id": "ac6993d51946422351508a41",
|
||||
"name": "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.",
|
||||
"Note that the three dots at the end add to the string length."
|
||||
],
|
||||
"challengeSeed":"function truncate(str, num) {\n // Clear out that junk in your trunk\r\n return str;\r\n}\n\ntruncate('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...');",
|
||||
"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');"
|
||||
],
|
||||
"MDNlinks" : ["String.slice()"]
|
||||
},
|
||||
{
|
||||
"_id": "a9bd25c716030ec90084d8a1",
|
||||
"name": "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."
|
||||
],
|
||||
"challengeSeed": "function chunk(arr, size) {\n // Break it up.\r\n return arr;\r\n}\n\nchunk(['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], 4), [[0, 1, 2, 3], [4, 5]], 'should return the last chunk as remaining elements');"
|
||||
],
|
||||
"MDNlinks" : ["Array.push()"]
|
||||
},
|
||||
{
|
||||
"_id": "ab31c21b530c0dafa9e241ee",
|
||||
"name": "Slasher Flick",
|
||||
"difficulty": "1.11",
|
||||
"description": [
|
||||
"Return the remaining elements of an array after chopping off n elements from the head."
|
||||
],
|
||||
"challengeSeed": "function slasher(arr, howMany) {\n // it doesn't always pay to be first\r\n return arr;\r\n}\n\nslasher([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 when n < 1');",
|
||||
"assert.deepEqual(slasher([1, 2, 3], 9), [], 'should return an empty array when n >= array.length');"
|
||||
],
|
||||
"MDNlinks" : ["Array.slice()", "Array.splice()"]
|
||||
},
|
||||
{
|
||||
"_id": "af2170cad53daa0770fabdea",
|
||||
"name": "Mutations",
|
||||
"difficulty": "1.12",
|
||||
"description": [
|
||||
"Return true if the string in the first element of the array contains 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'.",
|
||||
"Another example, ['Alien', 'line'], should return true because all of the letters in 'line' are present in 'Alien'."
|
||||
],
|
||||
"challengeSeed": "function mutation(arr) {\n return arr;\n}\n\nmutation(['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(['Alien', 'line'])).to.be.true;"
|
||||
],
|
||||
"MDNlinks" : ["Array.sort()"]
|
||||
},
|
||||
{
|
||||
"_id": "adf08ec01beb4f99fc7a68f2",
|
||||
"name": "Falsey Bouncer",
|
||||
"difficulty": "1.50",
|
||||
"description": [
|
||||
"Remove all falsey values from an array.",
|
||||
"Falsey values in javascript are false, null, 0, \"\", undefined, and NaN."
|
||||
],
|
||||
"challengeSeed": "function bouncer(arr) {\n // Don't show a false ID to this bouncer.\r\n return arr;\r\n}\n\nbouncer([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');"
|
||||
],
|
||||
"MDNlinks" : ["Boolean Objects", "Array.filter()"]
|
||||
},
|
||||
{
|
||||
"_id":"a8e512fbe388ac2f9198f0fa",
|
||||
"name":"Where art thou",
|
||||
"difficulty":"1.55",
|
||||
"description":[
|
||||
"Make a function that looks through a list (first argument) and returns an array of all objects that have equivalent property values (second argument)."
|
||||
],
|
||||
"challengeSeed":"function where(collection, source) {\n var arr = [];\r\n // What's in a name?\r\n return arr;\r\n}\n\nwhere([{ 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');"
|
||||
],
|
||||
"MDNlinks" : ["Global Object", "Object.hasOwnProperty()", "Object.keys()"]
|
||||
},
|
||||
{
|
||||
"_id":"a39963a4c10bc8b4d4f06d7e",
|
||||
"name":"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."
|
||||
],
|
||||
"challengeSeed": "function destroyer(arr) {\n // Remove all the values\r\n return arr;\r\n}\n\ndestroyer([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');"
|
||||
],
|
||||
"MDNlinks" : ["Arguments object","Array.filter()"]
|
||||
},
|
||||
{
|
||||
"_id": "a24c1a4622e3c05097f71d67",
|
||||
"name": "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)."
|
||||
],
|
||||
"challengeSeed": "function where(arr, num) {\n // Find my place in this sorted array.\r\n return num;\r\n}\n\nwhere([40, 60], 50);",
|
||||
"tests": [
|
||||
"expect(where([10, 20, 30, 40, 50], 35)).to.equal(3);",
|
||||
"expect(where([10, 20, 30, 40, 50], 30)).to.equal(2);"
|
||||
],
|
||||
"MDNlinks" : ["Array.sort()"]
|
||||
},
|
||||
{
|
||||
"_id": "a3566b1109230028080c9345",
|
||||
"name": "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."
|
||||
],
|
||||
"challengeSeed": "function sumAll(arr) {\n return(1);\r\n}\n\nsumAll([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);"
|
||||
],
|
||||
"MDNlinks" : ["Math.max()", "Math.min()", "Array.reduce()"]
|
||||
},
|
||||
{
|
||||
"_id": "a5de63ebea8dbee56860f4f2",
|
||||
"name": "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."
|
||||
],
|
||||
"challengeSeed": "function diff(arr1, arr2) {\n var newArr = [];\r\n // Same, same; but different.\r\n return newArr;\r\n}\n\ndiff([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');"
|
||||
],
|
||||
"MDNlinks" : ["Comparison Operators"]
|
||||
},
|
||||
{
|
||||
"_id": "a7f4d8f2483413a6ce226cac",
|
||||
"name": "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\");"
|
||||
],
|
||||
"difficulty": "2.02",
|
||||
"description": [
|
||||
"Convert the given number into a roman numeral.",
|
||||
"All <a href=\"http://www.mathsisfun.com/roman-numerals.html\">roman numerals</a> answers should be provided in upper-case."
|
||||
],
|
||||
"challengeSeed": "function convert(num) {\n return num;\r\n}\n\nconvert(36);",
|
||||
"MDNlinks" : ["Array.splice()", "Array.indexOf()", "Array.join()"]
|
||||
},
|
||||
{
|
||||
"_id": "a0b5010f579e69b815e7c5d6",
|
||||
"name": "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\");"
|
||||
],
|
||||
"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 the 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'"
|
||||
],
|
||||
"challengeSeed": "function replace(str, before, after) {\n return str;\r\n}\n\nreplace(\"A quick brown fox jumped over the lazy dog\", \"jumped\", \"leaped\");",
|
||||
"MDNlinks" : ["Array.splice()", "String.replace()", "Array.join()"]
|
||||
},
|
||||
{
|
||||
"_id": "aa7697ea2477d1316795783b",
|
||||
"name": "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\");"
|
||||
],
|
||||
"difficulty": "2.04",
|
||||
"description": [
|
||||
"Translate the provided string to pig latin.",
|
||||
"<a href=\"http://en.wikipedia.org/wiki/Pig_Latin\">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\".",
|
||||
"If a word begins with a vowel you just add \"way\" to the end."
|
||||
],
|
||||
"challengeSeed": "function translate(str) {\n return str;\r\n}\n\ntranslate(\"consonant\");",
|
||||
"MDNlinks" : ["Array.indexOf()", "Array.push()", "Array.join()", "String.substr()", "String.split()"]
|
||||
},
|
||||
{
|
||||
"_id": "afd15382cdfb22c9efe8b7de",
|
||||
"name": "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');"
|
||||
],
|
||||
"difficulty": "2.05",
|
||||
"description": [
|
||||
"The DNA strand is missing the pairing element. Match each character with the missing element and return the results as a 2d array.",
|
||||
"<a href=\"http://en.wikipedia.org/wiki/Base_pair\">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."
|
||||
],
|
||||
"challengeSeed": "function pair(str) {\n return str;\r\n}\n\npair(\"GCG\");",
|
||||
"MDNlinks" : ["Array.push()", "String.split()"]
|
||||
},
|
||||
{
|
||||
"_id": "af7588ade1100bde429baf20",
|
||||
"name" : "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."
|
||||
],
|
||||
"challengeSeed": "function fearNotLetter(str) {\n return str;\n}\n\nfearNotLetter('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;"
|
||||
],
|
||||
"MDNlinks" : ["String.charCodeAt()"]
|
||||
},
|
||||
{
|
||||
"_id": "a77dbc43c33f39daa4429b4f",
|
||||
"name": "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."
|
||||
],
|
||||
"challengeSeed": "function boo(bool) {\n // What is the new fad diet for ghost developers? The Boolean.\r\n return bool;\r\n}\n\nboo(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);"
|
||||
],
|
||||
"MDNlinks" : ["Boolean Objects"]
|
||||
},
|
||||
{
|
||||
"_id": "a105e963526e7de52b219be9",
|
||||
"name": "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.",
|
||||
"The unique numbers should be sorted by their original order, but the final array should not be sorted in numerical order.",
|
||||
"Check the assertion tests for examples."
|
||||
],
|
||||
"challengeSeed": "function unite(arr1, arr2, arr3) {\n return arr1;\r\n}\n\nunite([1, 2, 3], [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');"
|
||||
],
|
||||
"MDNlinks" : ["Array.reduce()"]
|
||||
},
|
||||
{
|
||||
"_id": "a6b0bb188d873cb2c8729495",
|
||||
"name": "Convert HTML Entities",
|
||||
"difficulty": "2.07",
|
||||
"description": [
|
||||
"Convert the characters \"&\", \"<\", \">\", '\"', and \"'\", in a string to their corresponding HTML entities."
|
||||
],
|
||||
"challengeSeed": "function convert(str) {\n // :)\r\n return str;\r\n}\n\nconvert('Dolce & Gabbana');",
|
||||
"tests": [
|
||||
"assert.strictEqual(convert('Dolce & Gabbana'), 'Dolce & Gabbana', 'should escape characters');",
|
||||
"assert.strictEqual(convert('abc'), 'abc', 'should handle strings with nothing to escape');"
|
||||
],
|
||||
"MDNlinks" : ["RegExp"]
|
||||
},
|
||||
{
|
||||
"_id": "a103376db3ba46b2d50db289",
|
||||
"name": "Spinal Tap Case",
|
||||
"difficulty": "2.08",
|
||||
"description": [
|
||||
"Convert a string to spinal case. Spinal case is all-lowercase-words-joined-by-dashes."
|
||||
],
|
||||
"challengeSeed": "function spinalCase(str) {\n // \"It's such a fine line between stupid, and clever.\"\r\n // --David St. Hubbins\r\n return str;\r\n}\n\nspinalCase('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');"
|
||||
],
|
||||
"MDNlinks" : ["RegExp", "String.replace()"]
|
||||
},
|
||||
{
|
||||
"_id": "a5229172f011153519423690",
|
||||
"name": "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.",
|
||||
"As an example, passing 4 to the function should return 5 because all the odd Fibonacci numbers under 4 are 1, 1, and 3."
|
||||
],
|
||||
"challengeSeed": "function sumFibs(num) {\n return num;\r\n}\n\nsumFibs(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);"
|
||||
],
|
||||
"MDNlinks" : ["Remainder"]
|
||||
},
|
||||
{
|
||||
"_id": "a3bfc1673c0526e06d3ac698",
|
||||
"name": "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.",
|
||||
"The provided number may not be a prime."
|
||||
],
|
||||
"challengeSeed": "function sumPrimes(num) {\n return num;\r\n}\n\nsumPrimes(10);",
|
||||
"tests": [
|
||||
"expect(sumPrimes(10)).to.be.a('number');",
|
||||
"expect(sumPrimes(10)).to.equal(17);",
|
||||
"expect(sumPrimes(977)).to.equal(73156);"
|
||||
],
|
||||
"MDNlinks" : ["For Loops", "Array.push()"]
|
||||
},
|
||||
{
|
||||
"_id": "ae9defd7acaf69703ab432ea",
|
||||
"name": "Smallest Common Multiple",
|
||||
"difficulty": "2.11",
|
||||
"description": [
|
||||
"Find the smallest number that is evenly divisible by all numbers in the provided range.",
|
||||
"The range will be an array of two numbers that will not necessarily be in numerical order."
|
||||
],
|
||||
"challengeSeed": "function smallestCommons(arr) {\n return arr;\r\n}\r\n\n\nsmallestCommons([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);",
|
||||
"(smallestCommons([1,13])).should.equal(360360);"
|
||||
],
|
||||
"MDNlinks" : ["Smallest Common Multiple"]
|
||||
},
|
||||
{
|
||||
"_id": "a6e40f1041b06c996f7b2406",
|
||||
"name": "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)."
|
||||
],
|
||||
"challengeSeed": "function find(arr, func) {\n var num = 0;\r\n return num;\r\n}\n\nfind([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');"
|
||||
],
|
||||
"MDNlinks" : ["Array.some()"]
|
||||
},
|
||||
{
|
||||
"_id": "a5deed1811a43193f9f1c841",
|
||||
"name": "Drop it like it's hot",
|
||||
"difficulty": "2.13",
|
||||
"description": [
|
||||
"Drop the elements of an array (first argument), starting from the front, until the predicate (second argument) returns true."
|
||||
],
|
||||
"challengeSeed": "function drop(arr, func) {\n // Drop them elements.\r\n return arr;\r\n}\n\ndrop([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([]);"
|
||||
],
|
||||
"MDNlinks" : ["Arguments object", "Array.shift()"]
|
||||
},
|
||||
{
|
||||
"_id": "ab306dbdcc907c7ddfc30830",
|
||||
"name": "Steamroller",
|
||||
"difficulty": "2.14",
|
||||
"description": [
|
||||
"Flatten a nested array. You must account for varying levels of nesting."
|
||||
],
|
||||
"challengeSeed": "function steamroller(arr) {\n // I'm a steamroller, baby\r\n return arr;\r\n}\n\nsteamroller([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');"
|
||||
],
|
||||
"MDNlinks" : ["Array.isArray()"]
|
||||
},
|
||||
{
|
||||
"_id": "a8d97bd4c764e91f9d2bda01",
|
||||
"name": "Binary Agents",
|
||||
"difficulty": "2.15",
|
||||
"description": [
|
||||
"Return an English translated sentence of the passed binary string.",
|
||||
"The binary string will be space separated."
|
||||
],
|
||||
"challengeSeed": "function binaryAgent(str) {\n return str;\r\n}\n\nbinaryAgent('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!\");"
|
||||
],
|
||||
"MDNlinks" : ["String.charCodeAt()", "String.fromCharCode()"]
|
||||
},
|
||||
{
|
||||
"_id": "a10d2431ad0c6a099a4b8b52",
|
||||
"name": "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.",
|
||||
"Remember, you can access object properties through either dot notation or [] notation."
|
||||
],
|
||||
"challengeSeed": "function every(collection, pre) {\n // Does everyone have one of these?\r\n return pre;\r\n}\n\nevery([{'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');"
|
||||
],
|
||||
"MDNlinks" : ["Object.hasOwnProperty()", "Object.getOwnPropertyNames()"]
|
||||
},
|
||||
{
|
||||
"_id": "a97fd23d9b809dac9921074f",
|
||||
"name": "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>",
|
||||
"If either argument isn't a valid number, return undefined."
|
||||
],
|
||||
"challengeSeed": "function add() {\n return false;\n}\n\nadd(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;"
|
||||
],
|
||||
"MDNlinks": ["Global Function Object", "Arguments object", "Closures", "Currying"]
|
||||
},
|
||||
{
|
||||
"_id": "a2f1d72d9b908d0bd72bb9f6",
|
||||
"name": "Make a Person",
|
||||
"difficulty": "3.12",
|
||||
"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).",
|
||||
"All functions that take an argument have an arity of 1, and the argument will be a string.",
|
||||
"These methods must be the only available means for interacting with the object."
|
||||
],
|
||||
"challengeSeed": "var Person = function(firstAndLast) {\n return firstAndLast;\r\n};\n\nvar bob = new Person('Bob Ross');\nbob.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');"
|
||||
],
|
||||
"MDNlinks" : ["Closures", "Details of the Object Model"]
|
||||
},
|
||||
{
|
||||
"_id": "af4afb223120f7348cdfc9fd",
|
||||
"name": "Map the Debris",
|
||||
"difficulty": "3.50",
|
||||
"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>.",
|
||||
"You can read about orbital periods <a href=\"http://en.wikipedia.org/wiki/Orbital_period\">on wikipedia</a>.",
|
||||
"The values should be rounded to the nearest whole number. The body being orbited is Earth.",
|
||||
"The radius of the earth is 6367.4447 kilometers, and the GM value of earth is 398600.4418"
|
||||
],
|
||||
"challengeSeed": "function orbitalPeriod(arr) {\n var GM = 398600.4418;\n var earthRadius = 6367.4447;\n return arr;\r\n}\r\n\r\norbitalPeriod([{name : \"sputkin\", avgAlt : 35873.5553}]);",
|
||||
"tests": [
|
||||
"expect(orbitalPeriod([{name : \"sputkin\", avgAlt : 35873.5553}])).to.eqls([{name: \"sputkin\", 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}]);"
|
||||
],
|
||||
"MDNlinks" : ["Math.pow()"]
|
||||
},
|
||||
{
|
||||
"_id" : "a3f503de51cfab748ff001aa",
|
||||
"name": "Pairwise",
|
||||
"difficulty": "3.51",
|
||||
"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.",
|
||||
"pairwise([1, 3, 2, 4], 4) would only equal 1, because only the first two elements can be paired to equal 4, and the first element has an index of 0!"
|
||||
],
|
||||
"challengeSeed": "function pairwise(arr, arg) {\n return arg;\n}\n\npairwise([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);"
|
||||
],
|
||||
"MDNlinks" : ["Array.reduce()"]
|
||||
},
|
||||
{
|
||||
"_id": "aff0395860f5d3034dc0bfc9",
|
||||
"name": "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."
|
||||
],
|
||||
"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);"
|
||||
],
|
||||
"challengeSeed": "function telephoneCheck(str) {\n // Good luck!\n return true;\n}\n\n\n\ntelephoneCheck(\"555-555-5555\");",
|
||||
"MDNlinks" : ["RegExp"]
|
||||
},
|
||||
{
|
||||
"_id": "a3f503de51cf954ede28891d",
|
||||
"name": "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."
|
||||
],
|
||||
"challengeSeed": "function sym(args) {\n return arguments;\r\n}\n\nsym([1, 2, 3], [5, 2, 1, 4]);",
|
||||
"tests": [
|
||||
"expect(sym([1, 2, 3], [5, 2, 1, 4])).to.eqls([3, 5, 4])",
|
||||
"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');"
|
||||
],
|
||||
"MDNlinks" : ["Array.reduce()"]
|
||||
},
|
||||
{
|
||||
"_id": "aa2e6f85cab2ab736c9a9b24",
|
||||
"name": "Cash Register",
|
||||
"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.", "Return the string \"Insufficient Funds\" if cash-in-drawer is less than the change due. Return the string \"Closed\" if cash-in-drawer is equal to the change due.", "Otherwise, return change in coin and bills, sorted in highest to lowest order."
|
||||
],
|
||||
"challengeSeed": "function drawer(price, cash, cid) {\n var change;\r\n // Here is your change, ma'am.\r\n return change;\r\n}\r\n\r\n// Example cash-in-drawer array:\r\n// [['PENNY', 1.01],\r\n// ['NICKEL', 2.05],\r\n// ['DIME', 3.10],\r\n// ['QUARTER', 4.25],\r\n// ['ONE', 90.00],\r\n// ['FIVE', 55.00],\r\n// ['TEN', 20.00],\r\n// ['TWENTY', 60.00],\r\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]]);",
|
||||
"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');"
|
||||
],
|
||||
"MDNlinks" : ["Global Object"]
|
||||
},
|
||||
{
|
||||
"_id": "a56138aff60341a09ed6c480",
|
||||
"name": "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."
|
||||
],
|
||||
"challengeSeed": "function inventory(arr1, arr2) {\n // All inventory must be accounted for or you're fired!\r\n return arr1;\r\n}\n\n// Example inventory lists\r\nvar curInv = [\r\n [21, 'Bowling Ball'],\r\n [2, 'Dirty Sock'],\r\n [1, 'Hair Pin'],\r\n [5, 'Microphone']\r\n];\r\n\r\nvar newInv = [\r\n [2, 'Hair Pin'],\r\n [3, 'Half-Eaten Apple'],\r\n [67, 'Bowling Ball'],\r\n [7, 'Toothpaste']\r\n];\r\n\r\ninventory(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']]);"
|
||||
],
|
||||
"MDNlinks" : ["Global Array Object"]
|
||||
},
|
||||
{
|
||||
"_id": "a7bf700cd123b9a54eef01d5",
|
||||
"name": "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."
|
||||
],
|
||||
"challengeSeed": "function permAlone(str) {\n return str;\n}\n\npermAlone('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);"
|
||||
],
|
||||
"MDNlinks" : ["Permutations", "RegExp"]
|
||||
},
|
||||
{
|
||||
"_id": "a19f0fbe1872186acd434d5a",
|
||||
"name": "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.",
|
||||
"For example, if the year and month are the same then only the day range should be displayed.",
|
||||
"Secondly, if the starting year is the current year, and the ending year can be inferred by the reader, the year should be omitted.",
|
||||
"Input date is formatted as YYYY-MM-DD"
|
||||
],
|
||||
"challengeSeed": "function friendly(str) {\n return str;\n}\n\nfriendly(['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'], 'one month apart can be inferred 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, 2016']);",
|
||||
"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']);"
|
||||
],
|
||||
"MDNlinks" : ["String.split()", "String.substr()", "parseInt()"]
|
||||
}
|
||||
]
|
219
seed_data/challenges/advanced-bonfires.json
Normal file
219
seed_data/challenges/advanced-bonfires.json
Normal file
@ -0,0 +1,219 @@
|
||||
{
|
||||
"name": "Advanced Algorithm Scripting",
|
||||
"order" : 0.011,
|
||||
"challenges": [
|
||||
{
|
||||
"_id": "aff0395860f5d3034dc0bfc9",
|
||||
"name": "Bonfire: 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.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</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);"
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function telephoneCheck(str) {",
|
||||
" // Good luck!",
|
||||
" return true;",
|
||||
"}",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"telephoneCheck(\"555-555-5555\");"
|
||||
],
|
||||
"MDNlinks" : ["RegExp"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a3f503de51cf954ede28891d",
|
||||
"name": "Bonfire: 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.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function sym(args) {",
|
||||
" return arguments;",
|
||||
"}",
|
||||
"",
|
||||
"sym([1, 2, 3], [5, 2, 1, 4]);"
|
||||
],
|
||||
"tests": [
|
||||
"expect(sym([1, 2, 3], [5, 2, 1, 4])).to.eqls([3, 5, 4])",
|
||||
"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');"
|
||||
],
|
||||
"MDNlinks" : ["Array.reduce()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "aa2e6f85cab2ab736c9a9b24",
|
||||
"name": "Bonfire: Cash Register",
|
||||
"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.", "Return the string \"Insufficient Funds\" if cash-in-drawer is less than the change due. Return the string \"Closed\" if cash-in-drawer is equal to the change due.", "Otherwise, return change in coin and bills, sorted in highest to lowest order.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function drawer(price, cash, cid) {",
|
||||
" var change;",
|
||||
" // Here is your change, ma'am.",
|
||||
" return change;",
|
||||
"}",
|
||||
"",
|
||||
"// Example cash-in-drawer array:",
|
||||
"// [['PENNY', 1.01],",
|
||||
"// ['NICKEL', 2.05],",
|
||||
"// ['DIME', 3.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');"
|
||||
],
|
||||
"MDNlinks" : ["Global Object"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a56138aff60341a09ed6c480",
|
||||
"name": "Bonfire: 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='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function inventory(arr1, arr2) {",
|
||||
" // All inventory must be accounted for or you're fired!",
|
||||
" return arr1;",
|
||||
"}",
|
||||
"",
|
||||
"// Example inventory lists",
|
||||
"var curInv = [",
|
||||
" [21, 'Bowling Ball'],",
|
||||
" [2, 'Dirty Sock'],",
|
||||
" [1, 'Hair Pin'],",
|
||||
" [5, 'Microphone']",
|
||||
"];",
|
||||
"",
|
||||
"var newInv = [",
|
||||
" [2, 'Hair Pin'],",
|
||||
" [3, 'Half-Eaten Apple'],",
|
||||
" [67, 'Bowling Ball'],",
|
||||
" [7, 'Toothpaste']",
|
||||
"];",
|
||||
"",
|
||||
"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']]);"
|
||||
],
|
||||
"MDNlinks" : ["Global Array Object"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a7bf700cd123b9a54eef01d5",
|
||||
"name": "Bonfire: 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.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function permAlone(str) {",
|
||||
" return str;",
|
||||
"}",
|
||||
"",
|
||||
"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);"
|
||||
],
|
||||
"MDNlinks" : ["Permutations", "RegExp"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a19f0fbe1872186acd434d5a",
|
||||
"name": "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.",
|
||||
"For example, if the year and month are the same then only the day range should be displayed.",
|
||||
"Secondly, if the starting year is the current year, and the ending year can be inferred by the reader, the year should be omitted.",
|
||||
"Input date is formatted as YYYY-MM-DD",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function friendly(str) {",
|
||||
" return str;",
|
||||
"}",
|
||||
"",
|
||||
"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'], 'one month apart can be inferred 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, 2016']);",
|
||||
"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']);"
|
||||
],
|
||||
"MDNlinks": ["String.split()", "String.substr()", "parseInt()"],
|
||||
"challengeType": 5
|
||||
}
|
||||
]
|
||||
}
|
179
seed_data/challenges/basejumps.json
Normal file
179
seed_data/challenges/basejumps.json
Normal file
@ -0,0 +1,179 @@
|
||||
{
|
||||
"name": "Full Stack JavaScript Projects",
|
||||
"order" : 0.014,
|
||||
"challenges": [
|
||||
{
|
||||
"_id": "bd7158d8c443eddfaeb5bcef",
|
||||
"name": "Waypoint: Get Set for Basejumps",
|
||||
"difficulty": 2.00,
|
||||
"challengeSeed": "128451852",
|
||||
"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.",
|
||||
"Wait for the workspace to finish processing and select it on the left sidebar, below the Create New Workspace button.",
|
||||
"Click the \"Start Editing\" button.",
|
||||
"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:add 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>.",
|
||||
"Now you're ready to move on to your first Basejump. 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."
|
||||
],
|
||||
"challengeType": 4,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7158d8c443eddfaeb5bdef",
|
||||
"name": "Basejump: Build a Voting App",
|
||||
"difficulty": 2.01,
|
||||
"challengeSeed": "128451852",
|
||||
"description": [
|
||||
"<span class='text-info'>Objective:</span> Build a full stack JavaScript app that successfully reverse-engineers this: <a href='http://voteplex.herokuapp.com/' target='_blank'>http://voteplex.herokuapp.com/</a> and deploy it to Heroku.",
|
||||
"Note that for each Basejump, you should create a new GitHub repository and a new Heroku project. If you can't remember how to do this, revisit <a href='/challenges/get-set-for-basejumps'>http://freecodecamp.com/challenges/get-set-for-basejumps</a>.",
|
||||
"As you build your app, you should frequently commit changes to your codebase. You can do this by running <code>git commit -am \"your commit message\"</code>. Note that you should replace \"your commit message\" with a brief summary of the changes you made to your code.",
|
||||
"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>.",
|
||||
"Here are the specific User Stories you should implement for this Basejump:",
|
||||
"<span class='text-info'>User Story:</span> As an authenticated user, I can keep my polls and come back later to access them.",
|
||||
"<span class='text-info'>User Story:</span> As an authenticated user, I can share my polls with my friends.",
|
||||
"<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 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.",
|
||||
"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>"
|
||||
],
|
||||
"challengeType": 4,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7158d8c443eddfaeb5bdff",
|
||||
"name": "Basejump: Build a Nightlife Coordination App",
|
||||
"difficulty": 2.02,
|
||||
"challengeSeed": "128451852",
|
||||
"description": [
|
||||
"<span class='text-info'>Objective:</span> Build a full stack JavaScript app that successfully reverse-engineers this: <a href='http://sociallife.herokuapp.com/' target='_blank'>http://sociallife.herokuapp.com/</a> and deploy it to Heroku.",
|
||||
"Note that for each Basejump, you should create a new GitHub repository and a new Heroku project. If you can't remember how to do this, revisit <a href='/challenges/get-set-for-basejumps'>http://freecodecamp.com/challenges/get-set-for-basejumps</a>.",
|
||||
"As you build your app, you should frequently commit changes to your codebase. You can do this by running <code>git commit -am \"your commit message\"</code>. Note that you should replace \"your commit message\" with a brief summary of the changes you made to your code.",
|
||||
"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>.",
|
||||
"Here are the specific User Stories you should implement for this Basejump:",
|
||||
"<span class='text-info'>User Story:</span> As an unauthenticated user, I can view all bars in my area.",
|
||||
"<span class='text-info'>User Story:</span> As an authenticated user, I can add myself to a bar to indicate I am going there tonight.",
|
||||
"<span class='text-info'>User Story:</span> As an authenticated user, I can remove myself from a bar if I no longer want to go there.",
|
||||
"<span class='text-info'>Bonus User Story:</span> As an unauthenticated user, when I login I should not have to search again.",
|
||||
"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>"
|
||||
],
|
||||
"challengeType": 4,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7158d8c443eddfaeb5bd0e",
|
||||
"name": "Basejump: Chart the Stock Market",
|
||||
"difficulty": 2.03,
|
||||
"challengeSeed": "128451852",
|
||||
"description": [
|
||||
"<span class='text-info'>Objective:</span> Build a full stack JavaScript app that successfully reverse-engineers this: <a href='http://stockjump.herokuapp.com/' target='_blank'>http://stockjump.herokuapp.com/</a> and deploy it to Heroku.",
|
||||
"Note that for each Basejump, you should create a new GitHub repository and a new Heroku project. If you can't remember how to do this, revisit <a href='/challenges/get-set-for-basejumps'>http://freecodecamp.com/challenges/get-set-for-basejumps</a>.",
|
||||
"As you build your app, you should frequently commit changes to your codebase. You can do this by running <code>git commit -am \"your commit message\"</code>. Note that you should replace \"your commit message\" with a brief summary of the changes you made to your code.",
|
||||
"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>.",
|
||||
"Here are the specific User Stories you should implement for this Basejump:",
|
||||
"<span class='text-info'>User Story:</span> As a user, I can view a graph displaying the recent trend lines for each added stock.",
|
||||
"<span class='text-info'>User Story:</span> As a user, I can add new stocks by their symbol name.",
|
||||
"<span class='text-info'>User Story:</span> As a user, I can remove stocks.",
|
||||
"<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.",
|
||||
"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>"
|
||||
],
|
||||
"challengeType": 4,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7158d8c443eddfaeb5bd0f",
|
||||
"name": "Basejump: Manage a Book Trading Club",
|
||||
"difficulty": 2.04,
|
||||
"challengeSeed": "128451852",
|
||||
"description": [
|
||||
"<span class='text-info'>Objective:</span> Build a full stack JavaScript app that successfully reverse-engineers this: <a href='http://bookoutpost.herokuapp.com/' target='_blank'>http://bookoutpost.herokuapp.com/</a> and deploy it to Heroku.",
|
||||
"Note that for each Basejump, you should create a new GitHub repository and a new Heroku project. If you can't remember how to do this, revisit <a href='/challenges/get-set-for-basejumps'>http://freecodecamp.com/challenges/get-set-for-basejumps</a>.",
|
||||
"As you build your app, you should frequently commit changes to your codebase. You can do this by running <code>git commit -am \"your commit message\"</code>. Note that you should replace \"your commit message\" with a brief summary of the changes you made to your code.",
|
||||
"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>.",
|
||||
"Here are the specific User Stories you should implement for this Basejump:",
|
||||
"<span class='text-info'>User Story:</span> As an authenticated user, I can view all books posted by every user.",
|
||||
"<span class='text-info'>User Story:</span> As an authenticated user, I can add a new book.",
|
||||
"<span class='text-info'>User Story:</span> As an authenticated user, I can update my settings to store my full name, city, and state.",
|
||||
"<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.",
|
||||
"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>"
|
||||
],
|
||||
"challengeType": 4,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7158d8c443eddfaeb5bdee",
|
||||
"name": "Basejump: Build a Pinterest Clone",
|
||||
"difficulty": 2.05,
|
||||
"challengeSeed": "128451852",
|
||||
"description": [
|
||||
"<span class='text-info'>Objective:</span> Build a full stack JavaScript app that successfully reverse-engineers this: <a href='http://linkterest.herokuapp.com/' target='_blank'>http://linkterest.herokuapp.com/</a> and deploy it to Heroku.",
|
||||
"Note that for each Basejump, you should create a new GitHub repository and a new Heroku project. If you can't remember how to do this, revisit <a href='/challenges/get-set-for-basejumps'>http://freecodecamp.com/challenges/get-set-for-basejumps</a>.",
|
||||
"As you build your app, you should frequently commit changes to your codebase. You can do this by running <code>git commit -am \"your commit message\"</code>. Note that you should replace \"your commit message\" with a brief summary of the changes you made to your code.",
|
||||
"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>.",
|
||||
"Here are the specific User Stories you should implement for this Basejump:",
|
||||
"<span class='text-info'>User Story:</span> As an unauthenticated user, I can login with Twitter.",
|
||||
"<span class='text-info'>User Story:</span> As an authenticated user, I can link to images.",
|
||||
"<span class='text-info'>User Story:</span> As an authenticated user, I can delete images that I've linked to.",
|
||||
"<span class='text-info'>User Story:</span> As an authenticated user, I can see a Pinterest-style wall of all the images I've linked to.",
|
||||
"<span class='text-info'>User Story:</span> As an unauthenticated user, I can browse other users' walls of images.",
|
||||
"<span class='text-info'>Bonus User Story:</span> As an authenticated user, if I upload an image that is broken, it will be replaced by a placeholder image. (can use jQuery broken image detection)",
|
||||
"<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.",
|
||||
"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>"
|
||||
],
|
||||
"challengeType": 4,
|
||||
"tests": []
|
||||
}
|
||||
]
|
||||
}
|
992
seed_data/challenges/basic-bonfires.json
Normal file
992
seed_data/challenges/basic-bonfires.json
Normal file
@ -0,0 +1,992 @@
|
||||
{
|
||||
"name": "Basic Algorithm Scripting",
|
||||
"order" : 0.007,
|
||||
"challenges": [
|
||||
{
|
||||
"_id": "bd7139d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Pair Program on Bonfires",
|
||||
"difficulty": 0.44,
|
||||
"challengeSeed": "119657641",
|
||||
"description": [
|
||||
"OK, we're finally ready to start pair programming!",
|
||||
"Pair Programming is where two people code together on the same computer. It is an efficient way to collaborate, and widely practiced at software companies. Pair Programming is one of the core concepts of \"Agile\" Software Development, which you will hear more about later.",
|
||||
"Many people use Skype or Google Hangouts to pair program, but if you talk with professional software engineers, they will tell you that it's not really pair programming unless both people have the ability to use the keyboard and mouse.",
|
||||
"The most popular tool for pair programming is Screen Hero. You can download Screen Hero for <a href='http://links.screenhero.com/e/c/eyJlbWFpbF9pZCI6Ik1qQTNNem9XQkNJQ1pBQUNjd0FYQVZrVEdnRkxNamtfX0JWZEdGVEpSZkVCWlRwbFpXRTBNamM0WVMxaE56SmlMVEV4WlRRdE9HUXpZUzFpWXpVNE1HRTJNalkxTldNNk1UUTJNVEEyQUE9PSIsInBvc2l0aW9uIjowLCJocmVmIjoiaHR0cDovL2RsLnNjcmVlbmhlcm8uY29tL3NtYXJ0ZG93bmxvYWQvZklYQU1UUUJBTEtQQkhQTC9TY3JlZW5oZXJvLnppcD9zb3VyY2U9d2ViIn0=' target='_blank'>Mac</a> or <a href='http://links.screenhero.com/e/c/eyJlbWFpbF9pZCI6Ik1qQTNNem9XQkNJQ1pBQUNjd0FYQVZrVEdnRkxNamtfX0JWZEdGVEpSZkVCWlRwbFpXRTBNamM0WVMxaE56SmlMVEV4WlRRdE9HUXpZUzFpWXpVNE1HRTJNalkxTldNNk1UUTJNVEEyQUE9PSIsInBvc2l0aW9uIjoxLCJocmVmIjoiaHR0cDovL2RsLnNjcmVlbmhlcm8uY29tL3NtYXJ0ZG93bmxvYWQvZklYQU1UUUJBTEtQQkhQTC9TY3JlZW5oZXJvLXNldHVwLmV4ZSJ9' target='_blank'>Windows</a>. Create your new user account from within the app.",
|
||||
"We have a special chat room for people ready to pair program. Go to our Slack chat room, navigate to the #letspair channel and type \"Hello Pair Programmers!\"",
|
||||
"If someone is available, they will be your \"pair\" - the person you pair programming with.",
|
||||
"If no one gets back to you in the first few minutes, don't worry. There will be lots of opportunities to pair program in the future.",
|
||||
"If someone does get back to you, private message them and ask for the email address they used to register Screen Hero.",
|
||||
"Add them as a new contact in Screen Hero, then click the monitor-looking button to attempt to share your screen with them.",
|
||||
"Once the Screen Hero session starts, your screen's margins will glow orange. You are now sharing your screen.",
|
||||
"Your pair will have their own cursor, and will be able to type text on his or her and keyboard.",
|
||||
"Now it's time to tackle our Bonfires.",
|
||||
"Go to <a href='http://freecodecamp.com/bonfires' target='_blank'>http://freecodecamp.com/bonfires</a> and start working through our Bonfire challenges.",
|
||||
"Once you you finish pair programming, end the session in Screen Hero session.",
|
||||
"Congratulations! You have completed your first pair programming session.",
|
||||
"Pair program as much as possible with different campers until you've completed all the Bonfire challenges. This is a big time investment, but the JavaScript practice you get will be well worth it!",
|
||||
"Mark this Waypoint complete and move on."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "ad7123c8c441eddfaeb5bdef",
|
||||
"name": "Bonfire: Meet Bonfire",
|
||||
"difficulty": "0",
|
||||
"description": [
|
||||
"Click the button below for further instructions.",
|
||||
"Your goal is to fix the failing test.",
|
||||
"First, run all the tests by clicking \"Run code\" 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;"
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function meetBonfire(argument) {",
|
||||
" // Good luck!",
|
||||
" console.log(\"you can read this function's argument in the developer tools\", argument);",
|
||||
"",
|
||||
" return false;",
|
||||
"}",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"meetBonfire(\"You can do this!\");"
|
||||
],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a202eed8fc186c8434cb6d61",
|
||||
"name": "Bonfire: 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');"
|
||||
],
|
||||
"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='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function reverseString(str) {",
|
||||
" return str;",
|
||||
"}",
|
||||
"",
|
||||
"reverseString('hello');"
|
||||
],
|
||||
"MDNlinks": ["Global String Object", "String.split()", "Array.reverse()", "Array.join()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a302f7aae1aa3152a5b413bc",
|
||||
"name": "Bonfire: 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);"
|
||||
],
|
||||
"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='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function factorialize(num) {",
|
||||
" return num;",
|
||||
"}",
|
||||
"",
|
||||
"factorialize(5);"
|
||||
],
|
||||
"MDNlinks": ["Arithmetic Operators"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "aaa48de84e1ecc7c742e1124",
|
||||
"name": "Bonfire: 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='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. 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);"
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function palindrome(str) {",
|
||||
" // Good luck!",
|
||||
" return true;",
|
||||
"}",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"palindrome(\"eye\");"
|
||||
],
|
||||
"MDNlinks": ["String.replace()", "String.toLowerCase()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a26cbbe9ad8655a977e1ceb5",
|
||||
"name": "Bonfire: 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='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function findLongestWord(str) {",
|
||||
" return str.length;",
|
||||
"}",
|
||||
"",
|
||||
"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);"
|
||||
],
|
||||
"MDNlinks": ["String.split()", "String.length"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "ab6137d4e35944e21037b769",
|
||||
"name": "Bonfire: 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='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function titleCase(str) {",
|
||||
" return str;",
|
||||
"}",
|
||||
"",
|
||||
"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\");"
|
||||
],
|
||||
"MDNlinks": ["String.charAt()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a789b3483989747d63b0e427",
|
||||
"name": "Bonfire: 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='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function largestOfFour(arr) {",
|
||||
" // You can do this!",
|
||||
" return arr;",
|
||||
"}",
|
||||
"",
|
||||
"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([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]])).should.eql([5,27,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]));"
|
||||
],
|
||||
"MDNlinks": ["Comparison Operators"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "acda2fb1324d9b0fa741e6b5",
|
||||
"name": "Bonfire: 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='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
|
||||
"challengeSeed": [
|
||||
"function end(str, target) {",
|
||||
" // \"Never give up and good luck will find you.\"",
|
||||
" // -- Falcor",
|
||||
" return str;",
|
||||
"}",
|
||||
"",
|
||||
"end('Bastian', 'n');"
|
||||
],
|
||||
"tests": [
|
||||
"assert.strictEqual(end('Bastian', 'n'), true, 'should equal true if target equals 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');"
|
||||
],
|
||||
"MDNlinks": ["String.substr()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "afcc8d540bea9ea2669306b6",
|
||||
"name": "Bonfire: 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='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function repeat(str, num) {",
|
||||
" // repeat after me",
|
||||
" return str;",
|
||||
"}",
|
||||
"",
|
||||
"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');"
|
||||
],
|
||||
"MDNlinks": ["Global String Object"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "ac6993d51946422351508a41",
|
||||
"name": "Bonfire: 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.",
|
||||
"Note that the three dots at the end add to the string length.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function truncate(str, num) {",
|
||||
" // Clear out that junk in your trunk",
|
||||
" return str;",
|
||||
"}",
|
||||
"",
|
||||
"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...');",
|
||||
"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');"
|
||||
],
|
||||
"MDNlinks": ["String.slice()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a9bd25c716030ec90084d8a1",
|
||||
"name": "Bonfire: 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='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function chunk(arr, size) {",
|
||||
" // Break it up.",
|
||||
" return arr;",
|
||||
"}",
|
||||
"",
|
||||
"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], 4), [[0, 1, 2, 3], [4, 5]], 'should return the last chunk as remaining elements');"
|
||||
],
|
||||
"MDNlinks": ["Array.push()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "ab31c21b530c0dafa9e241ee",
|
||||
"name": "Bonfire: 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='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function slasher(arr, howMany) {",
|
||||
" // it doesn't always pay to be first",
|
||||
" return arr;",
|
||||
"}",
|
||||
"",
|
||||
"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 when n < 1');",
|
||||
"assert.deepEqual(slasher([1, 2, 3], 9), [], 'should return an empty array when n >= array.length');"
|
||||
],
|
||||
"MDNlinks": ["Array.slice()", "Array.splice()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "af2170cad53daa0770fabdea",
|
||||
"name": "Bonfire: 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'.",
|
||||
"Another example, ['Alien', 'line'], should return true because all of the letters in 'line' are present in 'Alien'.",
|
||||
"Lastly, ['Mary', 'Aarmy'] should return false because 'Mary' is only 4 letters while 'Aarmy' is 5, so 'Mary' can't possibly contain 'Aarmy'",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function mutation(arr) {",
|
||||
" return arr;",
|
||||
"}",
|
||||
"",
|
||||
"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.false;",
|
||||
"expect(mutation(['Alien', 'line'])).to.be.true;"
|
||||
],
|
||||
"MDNlinks": ["Array.sort()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "adf08ec01beb4f99fc7a68f2",
|
||||
"name": "Bonfire: Falsey Bouncer",
|
||||
"difficulty": "1.50",
|
||||
"description": [
|
||||
"Remove all falsey values from an array.",
|
||||
"Falsey values in javascript are false, null, 0, \"\", undefined, and NaN.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function bouncer(arr) {",
|
||||
" // Don't show a false ID to this bouncer.",
|
||||
" return arr;",
|
||||
"}",
|
||||
"",
|
||||
"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');"
|
||||
],
|
||||
"MDNlinks": ["Boolean Objects", "Array.filter()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id":"a8e512fbe388ac2f9198f0fa",
|
||||
"name": "Bonfire: Where art thou",
|
||||
"difficulty":"1.55",
|
||||
"description":[
|
||||
"Make a function that looks through a list (first argument) and returns an array of all objects that have equivalent property values (second argument).",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. 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');"
|
||||
],
|
||||
"MDNlinks": ["Global Object", "Object.hasOwnProperty()", "Object.keys()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id":"a39963a4c10bc8b4d4f06d7e",
|
||||
"name": "Bonfire: 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='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function destroyer(arr) {",
|
||||
" // Remove all the values",
|
||||
" return arr;",
|
||||
"}",
|
||||
"",
|
||||
"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');"
|
||||
],
|
||||
"MDNlinks": ["Arguments object","Array.filter()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a24c1a4622e3c05097f71d67",
|
||||
"name": "Bonfire: 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='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function where(arr, num) {",
|
||||
" // Find my place in this sorted array.",
|
||||
" return num;",
|
||||
"}",
|
||||
"",
|
||||
"where([40, 60], 50);"
|
||||
],
|
||||
"MDNlinks" : ["Array.sort()"],
|
||||
"tests": [
|
||||
"expect(where([10, 20, 30, 40, 50], 35)).to.equal(3);",
|
||||
"expect(where([10, 20, 30, 40, 50], 30)).to.equal(2);"
|
||||
],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a3566b1109230028080c9345",
|
||||
"name": "Bonfire: 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.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function sumAll(arr) {",
|
||||
" return(1);",
|
||||
"}",
|
||||
"",
|
||||
"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);"
|
||||
],
|
||||
"MDNlinks": ["Math.max()", "Math.min()", "Array.reduce()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a5de63ebea8dbee56860f4f2",
|
||||
"name": "Bonfire: 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='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function diff(arr1, arr2) {",
|
||||
" var newArr = [];",
|
||||
" // Same, same; but different.",
|
||||
" return newArr;",
|
||||
"}",
|
||||
"",
|
||||
"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');"
|
||||
],
|
||||
"MDNlinks" : ["Comparison Operators", "String.slice()", "Array.filter()", "Array.indexOf()", "String.concat()"],
|
||||
"challengeType": 5
|
||||
|
||||
},
|
||||
{
|
||||
"_id": "a7f4d8f2483413a6ce226cac",
|
||||
"name": "Bonfire: 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\");"
|
||||
],
|
||||
"difficulty": "2.02",
|
||||
"description": [
|
||||
"Convert the given number into a roman numeral.",
|
||||
"All <a href=\"http://www.mathsisfun.com/roman-numerals.html\">roman numerals</a> answers should be provided in upper-case.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function convert(num) {",
|
||||
" return num;",
|
||||
"}",
|
||||
"",
|
||||
"convert(36);"
|
||||
],
|
||||
"MDNlinks": ["Array.splice()", "Array.indexOf()", "Array.join()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a0b5010f579e69b815e7c5d6",
|
||||
"name": "Bonfire: 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\");"
|
||||
],
|
||||
"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 the 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'",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function replace(str, before, after) {",
|
||||
" return str;",
|
||||
"}",
|
||||
"",
|
||||
"replace(\"A quick brown fox jumped over the lazy dog\", \"jumped\", \"leaped\");"
|
||||
],
|
||||
"MDNlinks": ["Array.splice()", "String.replace()", "Array.join()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "aa7697ea2477d1316795783b",
|
||||
"name": "Bonfire: 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\");"
|
||||
],
|
||||
"difficulty": "2.04",
|
||||
"description": [
|
||||
"Translate the provided string to pig latin.",
|
||||
"<a href=\"http://en.wikipedia.org/wiki/Pig_Latin\">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\".",
|
||||
"If a word begins with a vowel you just add \"way\" to the end.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function translate(str) {",
|
||||
" return str;",
|
||||
"}",
|
||||
"",
|
||||
"translate(\"consonant\");"
|
||||
],
|
||||
"MDNlinks": ["Array.indexOf()", "Array.push()", "Array.join()", "String.substr()", "String.split()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "afd15382cdfb22c9efe8b7de",
|
||||
"name": "Bonfire: 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');"
|
||||
],
|
||||
"difficulty": "2.05",
|
||||
"description": [
|
||||
"The DNA strand is missing the pairing element. Match each character with the missing element and return the results as a 2d array.",
|
||||
"<a href=\"http://en.wikipedia.org/wiki/Base_pair\">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.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function pair(str) {",
|
||||
" return str;",
|
||||
"}",
|
||||
"",
|
||||
"pair(\"GCG\");"
|
||||
],
|
||||
"MDNlinks": ["Array.push()", "String.split()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "af7588ade1100bde429baf20",
|
||||
"name" : "Bonfire: 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.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function fearNotLetter(str) {",
|
||||
" return str;",
|
||||
"}",
|
||||
"",
|
||||
"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;"
|
||||
],
|
||||
"MDNlinks": ["String.charCodeAt()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a77dbc43c33f39daa4429b4f",
|
||||
"name": "Bonfire: 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.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function boo(bool) {",
|
||||
" // What is the new fad diet for ghost developers? The Boolean.",
|
||||
" return bool;",
|
||||
"}",
|
||||
"",
|
||||
"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);"
|
||||
],
|
||||
"MDNlinks": ["Boolean Objects"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a105e963526e7de52b219be9",
|
||||
"name": "Bonfire: 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.",
|
||||
"The unique numbers should be sorted by their original order, but the final array should not be sorted in numerical order.",
|
||||
"Check the assertion tests for examples.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function unite(arr1, arr2, arr3) {",
|
||||
" return arr1;",
|
||||
"}",
|
||||
"",
|
||||
"unite([1, 2, 3], [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');"
|
||||
],
|
||||
"MDNlinks" : ["Array.reduce()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a6b0bb188d873cb2c8729495",
|
||||
"name": "Bonfire: Convert HTML Entities",
|
||||
"difficulty": "2.07",
|
||||
"description": [
|
||||
"Convert the characters \"&\", \"<\", \">\", '\"', and \"'\", in a string to their corresponding HTML entities.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function convert(str) {",
|
||||
" // :)",
|
||||
" return str;",
|
||||
"}",
|
||||
"",
|
||||
"convert('Dolce & Gabbana');"
|
||||
],
|
||||
"tests": [
|
||||
"assert.strictEqual(convert('Dolce & Gabbana'), 'Dolce & Gabbana', 'should escape characters');",
|
||||
"assert.strictEqual(convert('abc'), 'abc', 'should handle strings with nothing to escape');"
|
||||
],
|
||||
"MDNlinks": ["RegExp"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a103376db3ba46b2d50db289",
|
||||
"name": "Bonfire: 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='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function spinalCase(str) {",
|
||||
" // \"It's such a fine line between stupid, and clever.\"",
|
||||
" // --David St. Hubbins",
|
||||
" return str;",
|
||||
"}",
|
||||
"",
|
||||
"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');"
|
||||
],
|
||||
"MDNlinks": ["RegExp", "String.replace()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a5229172f011153519423690",
|
||||
"name": "Bonfire: 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.",
|
||||
"As an example, passing 4 to the function should return 5 because all the odd Fibonacci numbers under 4 are 1, 1, and 3.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function sumFibs(num) {",
|
||||
" return num;",
|
||||
"}",
|
||||
"",
|
||||
"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);"
|
||||
],
|
||||
"MDNlinks": ["Remainder"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a3bfc1673c0526e06d3ac698",
|
||||
"name": "Bonfire: 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.",
|
||||
"The provided number may not be a prime.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function sumPrimes(num) {",
|
||||
" return num;",
|
||||
"}",
|
||||
"",
|
||||
"sumPrimes(10);"
|
||||
],
|
||||
"tests": [
|
||||
"expect(sumPrimes(10)).to.be.a('number');",
|
||||
"expect(sumPrimes(10)).to.equal(17);",
|
||||
"expect(sumPrimes(977)).to.equal(73156);"
|
||||
],
|
||||
"MDNlinks" : ["For Loops", "Array.push()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "ae9defd7acaf69703ab432ea",
|
||||
"name": "Bonfire: Smallest Common Multiple",
|
||||
"difficulty": "2.11",
|
||||
"description": [
|
||||
"Find the smallest number that is evenly divisible by all numbers in the provided range.",
|
||||
"The range will be an array of two numbers that will not necessarily be in numerical order.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function smallestCommons(arr) {",
|
||||
" return arr;",
|
||||
"}",
|
||||
"",
|
||||
"",
|
||||
"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);",
|
||||
"(smallestCommons([1,13])).should.equal(360360);"
|
||||
],
|
||||
"MDNlinks" : ["Smallest Common Multiple"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a6e40f1041b06c996f7b2406",
|
||||
"name": "Bonfire: 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='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function find(arr, func) {",
|
||||
" var num = 0;",
|
||||
" return num;",
|
||||
"}",
|
||||
"",
|
||||
"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');"
|
||||
],
|
||||
"MDNlinks": ["Array.some()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a5deed1811a43193f9f1c841",
|
||||
"name": "Bonfire: Drop it like it's hot",
|
||||
"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='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function drop(arr, func) {",
|
||||
" // Drop them elements.",
|
||||
" return arr;",
|
||||
"}",
|
||||
"",
|
||||
"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([]);"
|
||||
],
|
||||
"MDNlinks": ["Arguments object", "Array.shift()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "ab306dbdcc907c7ddfc30830",
|
||||
"name": "Bonfire: Steamroller",
|
||||
"difficulty": "2.14",
|
||||
"description": [
|
||||
"Flatten a nested array. You must account for varying levels of nesting.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function steamroller(arr) {",
|
||||
" // I'm a steamroller, baby",
|
||||
" return arr;",
|
||||
"}",
|
||||
"",
|
||||
"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');"
|
||||
],
|
||||
"MDNlinks": ["Array.isArray()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a8d97bd4c764e91f9d2bda01",
|
||||
"name": "Bonfire: Binary Agents",
|
||||
"difficulty": "2.15",
|
||||
"description": [
|
||||
"Return an English translated sentence of the passed binary string.",
|
||||
"The binary string will be space separated.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function binaryAgent(str) {",
|
||||
" return str;",
|
||||
"}",
|
||||
"",
|
||||
"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!\");"
|
||||
],
|
||||
"MDNlinks": ["String.charCodeAt()", "String.fromCharCode()"
|
||||
],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a10d2431ad0c6a099a4b8b52",
|
||||
"name": "Bonfire: 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.",
|
||||
"Remember, you can access object properties through either dot notation or [] notation.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function every(collection, pre) {",
|
||||
" // Does everyone have one of these?",
|
||||
" return pre;",
|
||||
"}",
|
||||
"",
|
||||
"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');"
|
||||
],
|
||||
"MDNlinks": ["Object.hasOwnProperty()", "Object.getOwnPropertyNames()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "a97fd23d9b809dac9921074f",
|
||||
"name": "Bonfire: 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>",
|
||||
"If either argument isn't a valid number, return undefined.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function add() {",
|
||||
" return false;",
|
||||
"}",
|
||||
"",
|
||||
"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;"
|
||||
],
|
||||
"MDNlinks": ["Global Function Object", "Arguments object"],
|
||||
"challengeType": 5
|
||||
}
|
||||
]
|
||||
}
|
2028
seed_data/challenges/basic-html5-and-css.json
Normal file
2028
seed_data/challenges/basic-html5-and-css.json
Normal file
File diff suppressed because it is too large
Load Diff
155
seed_data/challenges/basic-javascript.json
Normal file
155
seed_data/challenges/basic-javascript.json
Normal file
@ -0,0 +1,155 @@
|
||||
{
|
||||
"name": "Basic JavaScript",
|
||||
"order" : 0.006,
|
||||
"challenges": [
|
||||
{
|
||||
"_id": "bd7129d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Build an Adventure Game",
|
||||
"difficulty": 0.24,
|
||||
"challengeSeed": "114604814",
|
||||
"description": [
|
||||
"Now that you understand some Computer Science fundamentals, let's focus on programming JavaScript!",
|
||||
"We're going to work through Codecademy's famous interactive JavaScript course.",
|
||||
"This course will teach us some JavaScript fundamentals while guiding us through the process of building interesting web apps, all within Codecademy's learner-friendly environment!",
|
||||
"Go to <a href='http://www.codecademy.com/courses/getting-started-v2/0/1' target='_blank'>http://www.codecademy.com/courses/getting-started-v2/0/1</a> and complete the section.",
|
||||
"Be sure to also complete this section: <a href='http://www.codecademy.com/courses/javascript-beginner-en-x9DnD/0/1' target='_blank'>http://www.codecademy.com/courses/javascript-beginner-en-x9DnD/0/1</a>."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7130d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Build Rock Paper Scissors",
|
||||
"difficulty": 0.25,
|
||||
"challengeSeed": "114604815",
|
||||
"description": [
|
||||
"Now we'll learn how JavaScript functions work, and use them to build a simple Rock Paper Scissors game.",
|
||||
"Go to <a href='http://www.codecademy.com/courses/javascript-beginner-en-6LzGd/0/1' target='_blank'>http://www.codecademy.com/courses/javascript-beginner-en-6LzGd/0/1</a> and complete the section.",
|
||||
"Be sure to also complete this section: <a href='http://www.codecademy.com/courses/javascript-beginner-en-Bthev-mskY8/0/1' target='_blank'>http://www.codecademy.com/courses/javascript-beginner-en-Bthev-mskY8/0/1</a>."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7131d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Learn JavaScript For Loops",
|
||||
"difficulty": 0.26,
|
||||
"challengeSeed": "114614220",
|
||||
"description": [
|
||||
"Let's learn more about the loops that make virtually all programs possible - the \"For Loop\" and \"While Loop\". First, we'll learn the For Loop.",
|
||||
"Go to <a href='http://www.codecademy.com/courses/javascript-beginner-en-NhsaT/0/1' target='_blank'>http://www.codecademy.com/courses/javascript-beginner-en-NhsaT/0/1web</a> and complete both the both For and While loop section.",
|
||||
"Be sure to also complete this section: <a href='http://www.codecademy.com/courses/javascript-beginner-en-XEDZA/0/1' target='_blank'>http://www.codecademy.com/courses/javascript-beginner-en-XEDZA/0/1</a>."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7132d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Learn JavaScript While Loops",
|
||||
"difficulty": 0.27,
|
||||
"challengeSeed": "114612889",
|
||||
"description": [
|
||||
"Go to <a href='http://www.codecademy.com/courses/javascript-beginner-en-ASGIv/0/1' target='_blank'>http://www.codecademy.com/courses/javascript-beginner-en-ASGIv/0/1</a> and complete the section.",
|
||||
"Be sure to also complete this section: <a href='http://www.codecademy.com/courses/javascript-beginner-en-mrTNH-6VIZ9/0/1' target='_blank'>http://www.codecademy.com/courses/javascript-beginner-en-mrTNH-6VIZ9/0/1</a>."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7133d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Learn Control Flow",
|
||||
"difficulty": 0.28,
|
||||
"challengeSeed": "114612888",
|
||||
"description": [
|
||||
"Much of human reasoning can be broken down into what we call Boolean Logic. Lucky for us, computers can think the same way! Let's learn how to instruct our computers by writing \"If Statements\" and \"Else Statements\".",
|
||||
"We'll also learn some advanced \"Control Flow\" principals, such as ways we can exit loops early.",
|
||||
"Go to <a href='http://www.codecademy.com/courses/javascript-beginner-en-qDwp0/0/1' target='_blank'>http://www.codecademy.com/courses/javascript-beginner-en-qDwp0/0/1</a> and complete the section.",
|
||||
"Be sure to also complete this section: <a href='http://www.codecademy.com/courses/javascript-beginner-en-ZA2rb/0/1' target='_blank'>http://www.codecademy.com/courses/javascript-beginner-en-ZA2rb/0/1</a>."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7134d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Build a Contact List",
|
||||
"difficulty": 0.29,
|
||||
"challengeSeed": "114612887",
|
||||
"description": [
|
||||
"Up to this point, you've been working mostly with strings and numbers. Now we're going to learn more complicated data structures, like \"Arrays\" and \"Objects\".",
|
||||
"Go to <a href='http://www.codecademy.com/courses/javascript-beginner-en-9Sgpi/0/1' target='_blank'>http://www.codecademy.com/courses/javascript-beginner-en-9Sgpi/0/1</a> and complete the section.",
|
||||
"Be sure to also complete this section: <a href='http://www.codecademy.com/courses/javascript-beginner-en-3bmfN/0/1' target='_blank'>http://www.codecademy.com/courses/javascript-beginner-en-3bmfN/0/1</a>."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7135d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Build an Address Book",
|
||||
"difficulty": 0.30,
|
||||
"challengeSeed": "114612885",
|
||||
"description": [
|
||||
"Let's learn more about objects.",
|
||||
"Go to <a href='http://www.codecademy.com/courses/spencer-sandbox/0/1' target='_blank'>http://www.codecademy.com/courses/spencer-sandbox/0/1</a> and complete the section.",
|
||||
"Be sure to also complete this section: <a href='http://www.codecademy.com/courses/building-an-address-book/0/1?curriculum_id=506324b3a7dffd00020bf661' target='_blank'>http://www.codecademy.com/courses/building-an-address-book/0/1?curriculum_id=506324b3a7dffd00020bf661</a>."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7136d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Build a Cash Register",
|
||||
"difficulty": 0.31,
|
||||
"challengeSeed": "114612882",
|
||||
"description": [
|
||||
"In this final Codecademy section, we'll learn even more about JavaScript objects.",
|
||||
"Go to <a href='http://www.codecademy.com/courses/objects-ii/0/1' target='_blank'>http://www.codecademy.com/courses/objects-ii/0/1</a> and complete this section.",
|
||||
"Be sure to also complete the final section: <a href='http://www.codecademy.com/courses/close-the-super-makert/0/1' target='_blank'>http://www.codecademy.com/courses/close-the-super-makert/0/1</a>."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7118d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Discover Chrome DevTools",
|
||||
"difficulty": 0.32,
|
||||
"challengeSeed": "110752743",
|
||||
"description": [
|
||||
"It's time to learn the most powerful tool your browser has - the Development Tools!",
|
||||
"If you aren't already using Chrome, you'll want to download it here: <a href='http://www.google.com/chrome/' target='_blank'>http://www.google.com/chrome/</a>. While it's true that Firefox has a tool called Firebug that is very similar to Chrome's DevTools, we will use Chrome for this challenge.",
|
||||
"Note that this course, jointly produced by Google and Code School, is technologically impressive, but occasionally buggy. If you encounter a bug, just ignore it and keep going.",
|
||||
"Go to <a href='http://discover-devtools.codeschool.com' target='_blank'>http://discover-devtools.codeschool.com</a>.",
|
||||
"Complete \"Chapter 1: Getting Started & Basic DOM and Styles\".",
|
||||
"Complete \"Chapter 2: Advanced DOM and Styles\".",
|
||||
"Complete \"Chapter 3: Working with the Console\".",
|
||||
"Complete \"Chapter 4: Debugging JavaScript\".",
|
||||
"Complete \"Chapter 5: Improving Network Performance\".",
|
||||
"Complete \"Chapter 6: Improving Performance\".",
|
||||
"Complete \"Chapter 7: Memory Profiling\"."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7138d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Learn Regular Expressions",
|
||||
"difficulty": 0.33,
|
||||
"challengeSeed": "112547802",
|
||||
"description": [
|
||||
"You can use a Regular Expression, or \"Regex\", to select specific types of characters in text.",
|
||||
"Check out <a href='http://www.regexr.com' target='_blank'>http://www.regexr.com</a>. It's a Regular Expression Sandbox for experimenting with Regular Expressions.",
|
||||
"Now go to <a href='http://www.regexone.com' target='_blank'>http://www.regexone.com</a>.",
|
||||
"Note that you can click \"continue\" to move on to the next step as soon as all the tasks have green check marks beside them. You can often do this just by using the wildcard \"dot\" operator, but try to use the techniques that each lesson recommends.",
|
||||
"Complete \"Complete the 15-lesson tutorial\"",
|
||||
"Complete \"Complete Practical Example 1: Matching a scientific or decimal number\"",
|
||||
"Complete \"Complete Practical Example 2: Matching phone numbers\"",
|
||||
"Complete \"Complete Practical Example 3: Matching emails\"",
|
||||
"Complete \"Complete Practical Example 4: Matching HTML\"",
|
||||
"Complete \"Complete Practical Example 5: Matching specific filenames\"",
|
||||
"Complete \"Complete Practical Example 6: Trimming whitespace from start and end of line\"",
|
||||
"Once you've completed these challenges, move on to our next Waypoint."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
}
|
||||
]
|
||||
}
|
1273
seed_data/challenges/bootstrap.json
Normal file
1273
seed_data/challenges/bootstrap.json
Normal file
File diff suppressed because it is too large
Load Diff
86
seed_data/challenges/computer-science.json
Normal file
86
seed_data/challenges/computer-science.json
Normal file
@ -0,0 +1,86 @@
|
||||
{
|
||||
"name": "Computer Science",
|
||||
"order" : 0.005,
|
||||
"challenges": [
|
||||
{
|
||||
"_id": "bd7123d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Learn Basic Computer Science",
|
||||
"difficulty": 0.90,
|
||||
"challengeSeed": "114628241",
|
||||
"description": [
|
||||
"Stanford has an excellent free online Computer Science curriculum. This interactive course uses a modified version of JavaScript. It will cover a lot of concepts quickly.",
|
||||
"Note that Harvard also has an excellent introduction to computer science course called CS50, but it takes more than 100 hours to complete, and doesn't use JavaScript.",
|
||||
"Despite being completely self-paced, Stanford's CS101 course is broken up into weeks. Each of the following challenges will address one of those weeks.",
|
||||
"Go to <a href='https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z54/z1/' target='_blank'>https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z54/z1/</a> and complete the first week's course work."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd8124d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Learn Loops",
|
||||
"difficulty": 0.19,
|
||||
"challengeSeed": "114597348",
|
||||
"description": [
|
||||
"Now let's tackle week 2 of Stanford's Intro to Computer Science course.",
|
||||
"This will introduce us to loops, a fundamental feature of every programming language.",
|
||||
"Go to <a href='https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z100/a7a70ce6e4724c58862ee6007284face/' target='_blank'>https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z100/a7a70ce6e4724c58862ee6007284face/</a> and complete Week 2."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd8125d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Learn Computer Hardware",
|
||||
"difficulty": 0.20,
|
||||
"challengeSeed": "114597347",
|
||||
"description": [
|
||||
"Week 3 of Stanford's Intro to Computer Science covers computer hardware and explains Moore's law of exponential growth in the price-performance of processors.",
|
||||
"This challenge will also give you an understanding of how bits and bytes work.",
|
||||
"Go to <a href='https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z143/z101/' target='_blank'>https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z143/z101/</a> and complete Week 3."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd8126d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Learn Computer Networking",
|
||||
"difficulty": 0.21,
|
||||
"challengeSeed": "114604811",
|
||||
"description": [
|
||||
"Now that you've learned about computer hardware, it's time to learn about the software that runs on top of it.",
|
||||
"Particularly important, you will learn about networks and TCP/IP - the protocol that powers the internet.",
|
||||
"Go to <a href='https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z187/z144/' target='_blank'>https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z187/z144/</a> and complete Week 4."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd8127d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Learn Boolean Logic",
|
||||
"difficulty": 0.22,
|
||||
"challengeSeed": "114604812",
|
||||
"description": [
|
||||
"Now we'll do some more table exercises and learn boolean logic.",
|
||||
"We'll also learn the difference between digital data and analog data.",
|
||||
"Go to <a href='https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z208/z188/' target='_blank'>https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z208/z188/</a> and complete Week 5."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd8128d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Learn Computer Security",
|
||||
"difficulty": 0.23,
|
||||
"challengeSeed": "114604813",
|
||||
"description": [
|
||||
"We're almost done with Stanford's Introduction to Computer Science course!",
|
||||
"We'll learn about one of the most important inventions of the 20th century - spreadsheets.",
|
||||
"We'll also learn about Computer Security and some of the more common vulnerabilities software systems have.",
|
||||
"Go to <a href='https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z229/z213/' target='_blank'>https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z229/z213/</a> and complete Week 6, the final week of the course."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
}
|
||||
]
|
||||
}
|
222
seed_data/challenges/full-stack-javascript.json
Normal file
222
seed_data/challenges/full-stack-javascript.json
Normal file
@ -0,0 +1,222 @@
|
||||
{
|
||||
"name": "Full Stack JavaScript",
|
||||
"order" : 0.013,
|
||||
"challenges": [
|
||||
{
|
||||
"_id": "bd7154d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: 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.",
|
||||
"In this course, we'll build a virtual shop entirely in Angular.js.",
|
||||
"Go to <a href='http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/1/section/1/video/1' target='_blank'>http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/1/section/1/video/1</a> and complete the section."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7155d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: 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 can alter the behavior of DOM elements based on the directives you've used.",
|
||||
"Let's learn how these powerful directives work, and how to use them to make your web apps more dynamic",
|
||||
"Go to <a href='http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/2/section/1/video/1' target='_blank'>http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/2/section/1/video/1</a> and complete the section."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7156d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Power Forms with Angular.js",
|
||||
"difficulty": 0.36,
|
||||
"challengeSeed": "114684729",
|
||||
"description": [
|
||||
"One area where Angular.js really shines is its powerful web forms.",
|
||||
"Learn how to create reactive Angular.js forms, including real-time form validation.",
|
||||
"Go to <a href='http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/3/section/1/video/1' target='_blank'>http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/3/section/1/video/1</a> and complete the section."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7157d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: 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.",
|
||||
"Go to <a href='http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/4/section/1/video/1' target='_blank'>http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/4/section/1/video/1</a> and complete the section."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7158d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: 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.",
|
||||
"We'll learn how to use services in this final Code School Angular.js challenge.",
|
||||
"Go to <a href='http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/5/section/1/video/1' target='_blank'>http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/5/section/1/video/1</a> and complete the section."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7153d8c441eddfaeb5bd0f",
|
||||
"name": "Waypoint: 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.",
|
||||
"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.",
|
||||
"Choose Node.js in the selection area below the name field.",
|
||||
"Click the Create button.",
|
||||
"Wait for the workspace to finish processing and select it on the left sidebar, below the Create New Workspace button.",
|
||||
"Click the \"Start Editing\" button.",
|
||||
"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.",
|
||||
"Run this command: <code>sudo npm install how-to-npm -g</code>",
|
||||
"Now start this tutorial by running <code>how-to-npm</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>.",
|
||||
"Complete \"Install NPM\"",
|
||||
"Complete \"Dev Environment\"",
|
||||
"Complete \"Login\"",
|
||||
"Complete \"Start a Project\"",
|
||||
"Complete \"Install a Module\"",
|
||||
"Complete \"Listing Dependencies\"",
|
||||
"Complete \"NPM Test\"",
|
||||
"Complete \"Package Niceties\"",
|
||||
"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 first 7 challenges, move on to our next waypoint."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7153d8c441eddfaeb5bdff",
|
||||
"name": "Waypoint: 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.",
|
||||
"Choose Node.js in the selection area below the name field.",
|
||||
"Click the Create button.",
|
||||
"Wait for the workspace to finish processing and select it on the left sidebar, below the Create New Workspace button.",
|
||||
"Click the \"Start Editing\" button.",
|
||||
"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.",
|
||||
"Run this command: <code>sudo npm install learnyounode -g</code>",
|
||||
"Now start this tutorial by running <code>learnyounode</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>.",
|
||||
"Complete \"Hello World\"",
|
||||
"Complete \"Baby Steps\"",
|
||||
"Complete \"My First I/O\"",
|
||||
"Complete \"My First Async I/O\"",
|
||||
"Complete \"Filtered LS\"",
|
||||
"Complete \"Make it Modular\"",
|
||||
"Complete \"HTTP Client\"",
|
||||
"Once you've completed these first 7 challenges, move on to our next waypoint."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7153d8c441eddfaeb5bdfe",
|
||||
"name": "Waypoint: 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>",
|
||||
"Complete \"HTTP Collect\"",
|
||||
"Complete \"Juggling Async\"",
|
||||
"Complete \"Time Server\"",
|
||||
"Once you've completed these 3 challenges, move on to our next waypoint."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7153d8c441eddfaeb5bdfd",
|
||||
"name": "Waypoint: 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.",
|
||||
"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 for the previous LearnYouNode challenges and start the tutorial by running <code>learnyounode</code>",
|
||||
"Complete \"HTTP File Server\"",
|
||||
"Complete \"HTTP Uppercaserer\"",
|
||||
"Complete \"HTTP JSON API Server\"",
|
||||
"Once you've completed these final 3 challenges, move on to our next waypoint."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7153d8c441eddfaeb5bd1f",
|
||||
"name": "Waypoint: Build Web Apps with Express.js",
|
||||
"difficulty": 0.43,
|
||||
"challengeSeed": "126411559",
|
||||
"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.",
|
||||
"Choose Node.js in the selection area below the name field.",
|
||||
"Click the Create button.",
|
||||
"Wait for the workspace to finish processing and select it on the left sidebar, below the Create New Workspace button.",
|
||||
"Click the \"Start Editing\" button.",
|
||||
"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.",
|
||||
"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>.",
|
||||
"Complete \"Hello World\"",
|
||||
"Complete \"Juggling Async\"",
|
||||
"Complete \"Time Server\"",
|
||||
"Complete \"HTTP Collect\"",
|
||||
"Complete \"Juggling Async\"",
|
||||
"Complete \"Time Server\"",
|
||||
"Once you've completed these challenges, move on to our next waypoint."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7140d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Manage Source Code with Git",
|
||||
"difficulty": 0.44,
|
||||
"challengeSeed": "114635309",
|
||||
"description": [
|
||||
"Version Control Systems like Git ensure that, no matter how you experiment with your code, you can always roll back your app to a stable previous state.",
|
||||
"Git is also a great way to share and contribute to open source software.",
|
||||
"Go to <a href='https://www.codeschool.com/courses/try-git' target='_blank'>https://www.codeschool.com/courses/try-git</a> and complete this short interactive course."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
}
|
||||
]
|
||||
}
|
22
seed_data/challenges/functional-programming.json
Normal file
22
seed_data/challenges/functional-programming.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "Functional Programming",
|
||||
"order" : 0.010,
|
||||
"challenges": [
|
||||
{
|
||||
"_id": "bd7129d8c441eddfbeb5bddf",
|
||||
"name": "Waypoint: Practice Functional Programming",
|
||||
"difficulty": 0.01,
|
||||
"challengeSeed": "114604814",
|
||||
"description": [
|
||||
"Functional programming holds the key to unlocking JavaScript's powerful asynchronous features.",
|
||||
"Jafar Husain's 42-step interactive Functional Programming course will familiarize you with the various ways you can recombine these functions.",
|
||||
"Functional programming in JavaScript involves using five key functions: \"map\", \"reduce\", \"filter\", \"concatAll\", and \"zip\".",
|
||||
"Click here to go to the challenge: <a href='http://jhusain.github.io/learnrx/' target='_blank'>http://jhusain.github.io/learnrx/</a>.",
|
||||
"This challenge will take several hours, but don't worry. Jafar's website will save your progress (using your browser's local storage) so you don't need to finish it in one sitting.",
|
||||
"If you've spent several minutes on one of these challenges, and still can't figure out its correct answer, you can click \"show answer\", then click \"run\" to advance to the next challenge. Be sure to read the correct answer and make sure you understand it before moving on."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
}
|
||||
]
|
||||
}
|
147
seed_data/challenges/get-set-for-free-code-camp.json
Normal file
147
seed_data/challenges/get-set-for-free-code-camp.json
Normal file
@ -0,0 +1,147 @@
|
||||
{
|
||||
"name": "Get Set for Free Code Camp",
|
||||
"order" : 0.001,
|
||||
"challenges": [
|
||||
{
|
||||
"_id": "bd7124d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Learn how Free Code Camp Works",
|
||||
"difficulty": 0.001,
|
||||
"challengeSeed": "125407438",
|
||||
"description": [
|
||||
"Watch this 1-minute video, or simply read this summary:",
|
||||
"Welcome to Free Code Camp. We're a community of busy people learning to code by building projects for nonprofits.",
|
||||
"We built this community because learning to code is hard. But anyone who can stay motivated can learn to code. And to stay motivated, you just need to: <ol><li>make friends with people who code</li><li>code a little every day</li><ol>",
|
||||
"All our challenges are <ol><li>free</li><li>self-paced</li><li>browser-based</li></ol>",
|
||||
"We'll spend <ol><li>200 hours learning tools like HTML, CSS, JavaScript, Node.js and databases</li><li>600 hours building practice projects</li><li>800 hours building full stack solutions for nonprofits</li></ol>",
|
||||
"By the end, we'll <ol><li>be good at coding</li><li>have the portfolio of apps with happy users to prove it</li></ol>",
|
||||
"Once you make it through Free Code Camp, you will be able to get a coding job. There are far more job openings out there than there are qualified coders to fill them.",
|
||||
"Now it's time to join our chat room. Click the \"I've completed this challenge\" button to move on to your next challenge."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7125d8c441eddfaeb5bd0f",
|
||||
"name": "Waypoint: Join Our Chat Room",
|
||||
"difficulty": 0.002,
|
||||
"challengeSeed": "124555254",
|
||||
"description": [
|
||||
"Now we're going to join the Free Code Camp chat room. You can come here any time of day to hang out, ask questions, or find another camper to pair program with.",
|
||||
"Make sure your Free Code Camp account includes your email address. Please note that the email address you use will be invisible to the public, but Slack will make it visible to other campers in our slack chat rooms. You can do this here: <a href='/account' target='_blank'>http://freecodecamp.com/account</a>.",
|
||||
"Click this link, which will email you an invite to Free Code Camp's Slack chat rooms: <a href='/api/slack' target='_blank'>http://freecodecamp.com/api/slack</a>.",
|
||||
"Now check your email and click the link in the email from Slack.",
|
||||
"Complete the sign up process, then update your biographical information and upload an image. A picture of your face works best. This is how people will see you in our chat rooms, so put your best foot forward.",
|
||||
"Now enter the General chat room and introduce yourself to our chat room by typing: \"Hello world!\".",
|
||||
"Tell your fellow campers how you found Free Code Camp. Also tell us why you want to learn to code.",
|
||||
"Keep the chat room open while you work through the other challenges. That way you ask for help if you get stuck on a challenge. You can also socialize when you feel like taking a break.",
|
||||
"You can also access this chat room by clicking the \"Chat\" button in the upper right hand corner.",
|
||||
"In order to keep our community a friendly and positive place to learn to code, please read and follow our Code of Conduct: <a href='/field-guide/what-is-the-free-code-camp-code-of-conduct?' target='_blank'>http://freecodecamp.com/field-guide/what-is-the-free-code-camp-code-of-conduct?</a>"
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7125d8c441eddfaeb5bdff",
|
||||
"name": "Waypoint: Preview our Challenge Map",
|
||||
"difficulty": 0.003,
|
||||
"challengeSeed": "125407437",
|
||||
"description": [
|
||||
"Before you start learning how to code, we'd like to introduce you to a few things.",
|
||||
"Let's look at our Challenge Map. Click on the \"Map\" button in the upper right hand corner. This map shows all the challenges that will teach you how to code.",
|
||||
"You should complete all these challenges in order.",
|
||||
"Once you finish these Waypoint challenges, you'll move on to Bonfires (algorithm practice), then Ziplines (front end development practice) and finally Basejumps (full stack development practice). After that, you'll start building projects for nonprofits.",
|
||||
"This challenge map is just for your reference. You can always just press the \"Learn\" button, and it will take you to your next challenge.",
|
||||
"Finally, please note that our open-source curriculum is a work in progress. Our volunteer community is constantly improving it. If you think you've encountered a bug, typo, or something that seems confusing, please open a GitHub issue: <a href='https://github.com/FreeCodeCamp/freecodecamp/issues'>https://github.com/FreeCodeCamp/freecodecamp/issues</a>."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7125d8c441eddfaeb5bd1f",
|
||||
"name": "Waypoint: Browse our Field Guide",
|
||||
"difficulty": 0.004,
|
||||
"challengeSeed": "125407435",
|
||||
"description": [
|
||||
"Free Code Camp has an up-to-date field guide that will answer your many questions.",
|
||||
"Click the \"Field Guide\" button in the upper right hand corner.",
|
||||
"You can browse the field guide at your convenience. Most of its articles take less than 1 minute to read.",
|
||||
"When you click the Field Guide button, it will always take you back to whichever article you were last reading.",
|
||||
"Read a few field guide articles, then move on to your next challenge."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7125d8c441eddfaeb5bd2f",
|
||||
"name": "Waypoint: Customize your Portfolio Page",
|
||||
"difficulty": 0.005,
|
||||
"challengeSeed": "125407433",
|
||||
"description": [
|
||||
"You and all your fellow campers have portfolio pages.",
|
||||
"To see your portfolio page, click your picture in the upper right hand corner.",
|
||||
"Your portfolio page will automatically show off your progress through Free Code Camp.",
|
||||
"Click the \"Update my portfolio page or manage my account\" button",
|
||||
"You can link to your GitHub, Twitter and LinkedIn accounts. If you've already built some websites, you can link to them here as well.",
|
||||
"Be sure to click the \"Update my Bio\" or \"Update my Social Links\" button to save this new information to your portfolio page.",
|
||||
"Once you're happy with your portfolio page, you can move on to your next challenge."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7126d8c441eddfaeb5bd3f",
|
||||
"name": "Waypoint: Try Camper News",
|
||||
"difficulty": 0.006,
|
||||
"challengeSeed": "124553410",
|
||||
"description": [
|
||||
"Camper News is the best place for our campers to share and discuss helpful links.",
|
||||
"Click \"News\" in the upper right hand corner.",
|
||||
"You'll see a variety of links that have been submitted. Click on the \"Discuss\" button under one of them.",
|
||||
"You can upvote links. This will push the link up the rankings of hot links.",
|
||||
"You an also comment on a link. If someone responds to your comment, you'll get an email notification so you can come back and respond to them.",
|
||||
"You can also submit links. You can modify the link's headline and also leave an initial comment about the link.",
|
||||
"You can view the portfolio pages of any camper who has posted links or comments on Camper News. Just click on their photo.",
|
||||
"When you submit a link, you'll get a point. You will also get a point each time someone upvotes your link.",
|
||||
"Now that you've learned how to use Camper News, let's move on to your next challenge."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7126d8c441eddfaeb5bd3e",
|
||||
"name": "Waypoint: Meet Other Campers in your City",
|
||||
"difficulty": 0.007,
|
||||
"challengeSeed": "127358841",
|
||||
"description": [
|
||||
"One of the best ways to stay motivated when learning to code is to hang out with other campers.",
|
||||
"Slack and Camper News are great ways to communicate with other campers, but there's no substitute for meeting people in-person.",
|
||||
"The easiest way to meet other campers in your city is to join your city's Facebook Group. Click <a href='/field-guide/how-can-i-find-other-free-code-camp-campers-in-my-city' target='_blank'>here</a> to view our growing list of local groups.",
|
||||
"Click the link to your city, then, once Facebook loads, click \"Join group\".",
|
||||
"Our local groups are new, so if you don't see your city on this list, you should follow the directions to create a Facebook group for your city.",
|
||||
"If you don't have a Facebook account, we strongly recommend you create one, even if it's just for the purpose of coordinating with campers in your city through this group.",
|
||||
"Our groups allow you to create events, coordinate those events, and share photos from the events afterward.",
|
||||
"Whether you're hosting a study group, pair programming at your local library, or going to a weekend hackathon, your city's group will help you make it happen."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7137d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Get Help the Hacker Way with RSAP",
|
||||
"difficulty": 0.008,
|
||||
"challengeSeed": "125407432",
|
||||
"description": [
|
||||
"Let's cover one last thing before you start working through our lessons: how to get help.",
|
||||
"Any time you get stuck or don't know what to do next, follow this simple algorithm (procedure): RSAP (Read, Search, Ask, Post).",
|
||||
"First, R - Read the documentation or error message. A key skill that good coders have is the ability to interpret and then follow instructions.",
|
||||
"Next, S - 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.",
|
||||
"Then, if you still haven't found an answer to your question, A - Ask your friends. If you have trouble, you can ask your fellow campers. We have a special chat room specifically for getting help with tools you learn through these Free Code Camp Challenges. Go to <a href='https://freecode.slack.com/messages/help/' target='_blank'>https://freecode.slack.com/messages/help/</a>. Keep this chat open while you work on the remaining challenges.",
|
||||
"Finally, P - Post on Stack Overflow. Before you attempt to do this, read Stack Overflow's guide to asking good questions: <a href='http://stackoverflow.com/help/how-to-ask'>http://stackoverflow.com/help/how-to-ask</a>.",
|
||||
"Here's our detailed field guide on getting help: <a href='/field-guide/how-do-i-get-help-when-i-get-stuck' target='_blank'>http://freecodecamp.com/field-guide/how-do-i-get-help-when-i-get-stuck</a>.",
|
||||
"Now you have a clear algorithm to follow when you need help! Let's start coding! Move on to your next challenge."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
}
|
||||
]
|
||||
}
|
99
seed_data/challenges/intermediate-bonfires.json
Normal file
99
seed_data/challenges/intermediate-bonfires.json
Normal file
@ -0,0 +1,99 @@
|
||||
{
|
||||
"name": "Intermediate Algorithm Scripting",
|
||||
"order" : 0.009,
|
||||
"challenges": [
|
||||
{
|
||||
"_id": "a2f1d72d9b908d0bd72bb9f6",
|
||||
"name": "Bonfire: 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).",
|
||||
"All functions that take an argument have an arity of 1, and the argument will be a string.",
|
||||
"These methods must be the only available means for interacting with the object.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"var Person = function(firstAndLast) {",
|
||||
" return firstAndLast;",
|
||||
"};",
|
||||
"",
|
||||
"var bob = new Person('Bob Ross');",
|
||||
"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');"
|
||||
],
|
||||
"MDNlinks": ["Closures", "Details of the Object Model"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id": "af4afb223120f7348cdfc9fd",
|
||||
"name": "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>.",
|
||||
"You can read about orbital periods <a href=\"http://en.wikipedia.org/wiki/Orbital_period\">on wikipedia</a>.",
|
||||
"The values should be rounded to the nearest whole number. The body being orbited is Earth.",
|
||||
"The radius of the earth is 6367.4447 kilometers, and the GM value of earth is 398600.4418",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function orbitalPeriod(arr) {",
|
||||
" var GM = 398600.4418;",
|
||||
" var earthRadius = 6367.4447;",
|
||||
" return arr;",
|
||||
"}",
|
||||
"",
|
||||
"orbitalPeriod([{name : \"sputkin\", avgAlt : 35873.5553}]);"
|
||||
],
|
||||
"tests": [
|
||||
"expect(orbitalPeriod([{name : \"sputkin\", avgAlt : 35873.5553}])).to.eqls([{name: \"sputkin\", 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}]);"
|
||||
],
|
||||
"MDNlinks": ["Math.pow()"],
|
||||
"challengeType": 5
|
||||
},
|
||||
{
|
||||
"_id" : "a3f503de51cfab748ff001aa",
|
||||
"name": "Bonfire: 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.",
|
||||
"pairwise([1, 3, 2, 4], 4) would only equal 1, because only the first two elements can be paired to equal 4, and the first element has an index of 0!",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try to pair program. Write your own code."
|
||||
],
|
||||
"challengeSeed": [
|
||||
"function pairwise(arr, arg) {",
|
||||
" return arg;",
|
||||
"}",
|
||||
"",
|
||||
"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);"
|
||||
],
|
||||
"MDNlinks" : ["Array.reduce()"],
|
||||
"challengeType": 5
|
||||
}
|
||||
]
|
||||
}
|
74
seed_data/challenges/jquery-ajax-and-json.json
Normal file
74
seed_data/challenges/jquery-ajax-and-json.json
Normal file
@ -0,0 +1,74 @@
|
||||
{
|
||||
"name": "jQuery",
|
||||
"order" : 0.004,
|
||||
"challenges": [
|
||||
{
|
||||
"_id": "bd7112d8c441eddfaeb5bded",
|
||||
"name": "Waypoint: Get Started with jQuery",
|
||||
"difficulty": 0.13,
|
||||
"challengeSeed": "125671865",
|
||||
"description": [
|
||||
"jQuery is a powerful library built in Javascript for manipulating HTML elements.",
|
||||
"It's a lot easier to use than Javascript itself, so we'll learn it first.",
|
||||
"It's also extremely popular with employers, so we're going to learn it well.",
|
||||
"Codecademy has an excellent free course that will walk us through the basics of jQuery.",
|
||||
"Go to <a href='http://www.codecademy.com/courses/web-beginner-en-bay3D/0/1' target='_blank'>http://www.codecademy.com/courses/web-beginner-en-bay3D/0/1</a> and complete the first section."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7113d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Write Functions with jQuery",
|
||||
"difficulty": 0.14,
|
||||
"challengeSeed": "125658029",
|
||||
"description": [
|
||||
"Now we're ready to write your first jQuery functions.",
|
||||
"Functions are little sub-programs. You can call a function and ask it to do something. Then it will return an answer.",
|
||||
"First, you'll learn about one of the most important jQuery functions of all: <code>$(document).ready()</code>.",
|
||||
"Go to <a href='http://www.codecademy.com/courses/web-beginner-en-GfjC6/0/1' target='_blank'>http://www.codecademy.com/courses/web-beginner-en-GfjC6/0/1</a> and complete the second section."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7114d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Harness Dynamic HTML",
|
||||
"difficulty": 0.15,
|
||||
"challengeSeed": "125658028",
|
||||
"description": [
|
||||
"Did you know that you can create HTML elements using jQuery?",
|
||||
"Let's learn some more advanced ways to use jQuery to manipulate the DOM.",
|
||||
"Go to <a href='http://www.codecademy.com/courses/web-beginner-en-v6phg/0/1' target='_blank'>http://www.codecademy.com/courses/web-beginner-en-v6phg/0/1</a> and complete the third section."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7115d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Listen for jQuery Events",
|
||||
"difficulty": 0.16,
|
||||
"challengeSeed": "125658027",
|
||||
"description": [
|
||||
"jQuery can listen for events, such as clicking a button, and respond to them.",
|
||||
"Here we'll learn how to use the jQuery <code>click()</code> function to respond to events in the browser.",
|
||||
"Go to <a href='http://www.codecademy.com/courses/web-beginner-en-JwhI1/0/1' target='_blank'>http://www.codecademy.com/courses/web-beginner-en-JwhI1/0/1</a> and complete the fourth section."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7116d8c441eddfaeb5bdef",
|
||||
"name": "Waypoint: Trigger jQuery Effects",
|
||||
"difficulty": 0.17,
|
||||
"challengeSeed": "125658025",
|
||||
"description": [
|
||||
"We can use jQuery to do all kinds of visual effects and transitions.",
|
||||
"Let's explore some of the fun ways we can manipulate DOM elements with jQuery.",
|
||||
"Go to <a href='http://www.codecademy.com/courses/web-beginner-en-jtFIC/0/1' target='_blank'>http://www.codecademy.com/courses/web-beginner-en-jtFIC/0/1</a> and complete the fifth section."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
}
|
||||
]
|
||||
}
|
146
seed_data/challenges/object-oriented-javascript.json
Normal file
146
seed_data/challenges/object-oriented-javascript.json
Normal file
@ -0,0 +1,146 @@
|
||||
{
|
||||
"name": "Object Oriented JavaScript",
|
||||
"order" : 0.008,
|
||||
"challenges": [
|
||||
{
|
||||
"_id": "bd7129d8c441eddfaeb5bddf",
|
||||
"name": "Waypoint: Scope Your Variables",
|
||||
"difficulty": 0.01,
|
||||
"challengeSeed": "128836683",
|
||||
"description": [
|
||||
"Objects will allow you to build applications more efficiently by using small, reusable blocks of code.",
|
||||
"This course on Udacity will help you learn Object-Oriented Programming in JavaScript.",
|
||||
"First, we'll learn how JavaScript works in terms of scopes. You'll learn the difference between a \"Lexical Scope\" and an \"Execution Context\".",
|
||||
"This theoretical foundation is useful for understanding when a variable can be accessed and when it can't.",
|
||||
"You can save your progress by creating a free Udacity account, but note that it's also possible to complete this entire course without an account by following the links we provide.",
|
||||
"Go to <a href='https://www.udacity.com/course/viewer#!/c-ud015/l-2593668697/m-2541189051' target='_blank'>https://www.udacity.com/course/viewer#!/c-ud015/l-2593668697/m-2541189051</a> and start the course.",
|
||||
"Once you've completed this first section of scopes, mark this Waypoint complete and move on to the next one."
|
||||
],
|
||||
"challengeType": 2
|
||||
},
|
||||
{
|
||||
"_id": "bd7131d8c441eddfaeb5bdbf",
|
||||
"name": "Waypoint: Reference your Current Object with This",
|
||||
"difficulty": 0.03,
|
||||
"challengeSeed": "128836508",
|
||||
"description": [
|
||||
"In this section, you'll learn how you can use the keyword <code>this</code> to dynamically point to your current object.",
|
||||
"For example, if we were inside the function <code>camper.completeCourse()</code>, <code>this</code> would refer to the specific camper upon which we were running the function.",
|
||||
"Note that this section poses several trick questions that were designed to make you think. Don't get hung up on them, just keep moving forward.",
|
||||
"You can save your progress by creating a free Udacity account, but note that it's also possible to complete this entire course without an account by following the links we provide.",
|
||||
"Go to <a href='https://www.udacity.com/course/viewer#!/c-ud015/l-2593668699/m-2780408563' target='_blank'>https://www.udacity.com/course/viewer#!/c-ud015/l-2593668699/m-2780408563</a> and start the course.",
|
||||
"Once you've completed this section of using the keyword <code>this</code>, mark this Waypoint complete and move on to the next one."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7132d8c441eddfaeb5bdaf",
|
||||
"name": "Waypoint: Traverse the Prototype Chain",
|
||||
"difficulty": 0.04,
|
||||
"challengeSeed": "128836684",
|
||||
"description": [
|
||||
"Next we'll learn about the multiple ways you can create a copy of an object.",
|
||||
"We'll also learn how an object's missing attributes can traverse the \"prototype chain\".",
|
||||
"You can save your progress by creating a free Udacity account, but note that it's also possible to complete this entire course without an account by following the links we provide.",
|
||||
"Go to <a href='https://www.udacity.com/course/viewer#!/c-ud015/l-2593668700/m-2616738615' target='_blank'>https://www.udacity.com/course/viewer#!/c-ud015/l-2593668700/m-2616738615</a> and start the course.",
|
||||
"Once you've completed this section on prototype chain traversal, mark this Waypoint complete and move on to the next one."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7133d8c441eddfaeb5bd0f",
|
||||
"name": "Waypoint: Reuse Code with Decorators",
|
||||
"difficulty": 0.05,
|
||||
"challengeSeed": "128836681",
|
||||
"description": [
|
||||
"In this section, we'll learn about the \"Decorator Pattern\".",
|
||||
"The Decorator Pattern will help you \"decorate\" an existing object with additional attributes. This pattern helps you reuse code, reducing the total amount of code you'll need to write and maintain.",
|
||||
"It's a convenient way to add functionality to objects without changing their underlying structure.",
|
||||
"You can save your progress by creating a free Udacity account, but note that it's also possible to complete this entire course without an account by following the links we provide.",
|
||||
"Go to <a href='https://www.udacity.com/course/viewer#!/c-ud015/l-2794468536/m-2697628561' target='_blank'>https://www.udacity.com/course/viewer#!/c-ud015/l-2794468536/m-2697628561</a> and start the course.",
|
||||
"Once you've completed this section of decorators, mark this Waypoint complete and move on to the next one."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7134d8c441eddfaeb5bd1f",
|
||||
"name": "Waypoint: Build Objects with Functional Classes",
|
||||
"difficulty": 0.06,
|
||||
"challengeSeed": "128836503",
|
||||
"description": [
|
||||
"Now we'll go over the simplest way to implement a JavaScript class.",
|
||||
"A class is a set of functions that you can use to easily produce similar objects.",
|
||||
"You may have heard JavaScript doesn't have classes. While this is technically true, don't let this fact prevent you from learning the important concepts in this section.",
|
||||
"You can save your progress by creating a free Udacity account, but note that it's also possible to complete this entire course without an account by following the links we provide.",
|
||||
"Go to <a href='https://www.udacity.com/course/viewer#!/c-ud015/l-2794468537/m-2961989110' target='_blank'>https://www.udacity.com/course/viewer#!/c-ud015/l-2794468537/m-2961989110</a> and start the course.",
|
||||
"Once you've completed this section of functional classes, mark this Waypoint complete and move on to the next one."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7135d8c441eddfaeb5bd2f",
|
||||
"name": "Waypoint: Build Objects with Prototypal Classes",
|
||||
"difficulty": 0.07,
|
||||
"challengeSeed": "128836505",
|
||||
"description": [
|
||||
"Now we'll learn how one object can be prototyped off of another object.",
|
||||
"Objects will delegate their \"failed lookups\" on up through the \"prototype chain\".",
|
||||
"This means that when you create a second object based off another object, then try to access an attribute that the second object doesn't have, JavaScript will \"fall through\" to the original object to see whether it has that attribute.",
|
||||
"You can save your progress by creating a free Udacity account, but note that it's also possible to complete this entire course without an account by following the links we provide.",
|
||||
"Go to <a href='https://www.udacity.com/course/viewer#!/c-ud015/l-2794468538/m-3034538557' target='_blank'>https://www.udacity.com/course/viewer#!/c-ud015/l-2794468538/m-3034538557</a> and start the course.",
|
||||
"Once you've completed this section of prototypal classes, mark this Waypoint complete and move on to the next one."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7136d8c441eddfaeb5bd3f",
|
||||
"name": "Waypoint: Understand Pseudoclassical Patterns",
|
||||
"difficulty": 0.08,
|
||||
"challengeSeed": "128836689",
|
||||
"description": [
|
||||
"JavaScript doesn't have the traditional \"classes\" that lower-level languages like C++ and Java have.",
|
||||
"Instead, JavaScript does some tricks to allow you to write code as though it had these traditional classes. We call these \"pseudo-classes\".",
|
||||
"In this section, we'll learn how to build these pseudo-classes. We'll also learn some tricks for figuring out where these objects originally came from.",
|
||||
"You can save your progress by creating a free Udacity account, but note that it's also possible to complete this entire course without an account by following the links we provide.",
|
||||
"Go to <a href='https://www.udacity.com/course/viewer#!/c-ud015/l-2794468539/e-2783098540/m-2695768694' target='_blank'>https://www.udacity.com/course/viewer#!/c-ud015/l-2794468539/e-2783098540/m-2695768694</a> and start the course.",
|
||||
"Once you've completed this section pseudoclasses, mark this Waypoint complete and move on to the next one."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7136d8c441eddfaeb5bd4f",
|
||||
"name": "Waypoint: Subclass one Object to Another",
|
||||
"difficulty": 0.09,
|
||||
"challengeSeed": "128836686",
|
||||
"description": [
|
||||
"Now we know the three ways that we can create objects. Through: <ol><li>functions</li><li>prototyping</li><li>pseudo classing</li></ol>",
|
||||
"Let's learn how to \"subclass\" one object to another. This will give our new object the attributes of the original object. It will allow us to make further modifications to the new object without affecting the original object.",
|
||||
"You can save your progress by creating a free Udacity account, but note that it's also possible to complete this entire course without an account by following the links we provide.",
|
||||
"Go to <a href='https://www.udacity.com/course/viewer#!/c-ud015/l-2794468540/m-2785128536' target='_blank'>https://www.udacity.com/course/viewer#!/c-ud015/l-2794468540/m-2785128536</a> and start the course.",
|
||||
"Once you've completed this section on subclassing, mark this Waypoint complete and move on to the next one."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7136d8c441eddfaeb5bd5f",
|
||||
"name": "Waypoint: Use Pseudoclassical Subclasses",
|
||||
"difficulty": 0.10,
|
||||
"challengeSeed": "128836937",
|
||||
"description": [
|
||||
"This final section will teach us how to create subclasses from pseudo classes.",
|
||||
"You can save your progress by creating a free Udacity account, but note that it's also possible to complete this entire course without an account by following the links we provide.",
|
||||
"Go to <a href='https://www.udacity.com/course/viewer#!/c-ud015/l-2794468541/e-2693158566/m-2688408703' target='_blank'>https://www.udacity.com/course/viewer#!/c-ud015/l-2794468541/e-2693158566/m-2688408703</a> and start the course.",
|
||||
"Once you've completed this final section on pseudoclassical subclassing, mark this Waypoint complete and move on."
|
||||
],
|
||||
"challengeType": 2,
|
||||
"tests": []
|
||||
}
|
||||
]
|
||||
}
|
205
seed_data/challenges/ziplines.json
Normal file
205
seed_data/challenges/ziplines.json
Normal file
@ -0,0 +1,205 @@
|
||||
{
|
||||
"name": "Front End Development Projects",
|
||||
"order" : 0.012,
|
||||
"challenges": [
|
||||
{
|
||||
"_id": "bd7158d8c442eddfbeb5bd1f",
|
||||
"name": "Waypoint: Get Set for Ziplines",
|
||||
"difficulty": 1.00,
|
||||
"challengeSeed": "125658022",
|
||||
"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.",
|
||||
"For many of these challenges, you will be using JSON data from external API endpoints, such as Twitch.tv and Twitter. Note that you don't need to have a database to use these data.",
|
||||
"The easiest way to manipulate these data is with <a href='http://api.jquery.com/jquery.getjson/' target='_blank'>jQuery $.getJSON()</a>.",
|
||||
"Whatever you do, don't get discouraged! Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</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 in the \"External CSS File or Another Pen\" text field, type \"bootstrap\" and scroll down until you see the latest version of Bootstrap. Click it.",
|
||||
"Verify that bootstrap is active by adding the following code to your HTML: <code><h1 class='text-primary'>Hello CodePen!</h1></code>. The text's color should be Bootstrap blue.",
|
||||
"Click the gear next the JavaScript. Click the \"Latest version of...\" select box and choose jQuery.",
|
||||
"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.",
|
||||
"Now you're ready for your first Zipline. 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."
|
||||
],
|
||||
"challengeType": 3,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7158d8c442eddfaeb5bd1f",
|
||||
"name": "Zipline: Use the Twitch.tv JSON API",
|
||||
"difficulty": 1.01,
|
||||
"challengeSeed": "126411564",
|
||||
"description": [
|
||||
"<span class='text-info'>Objective:</span> Build a <a href='http://codepen.io' target='_blank'>CodePen.io</a> 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. 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'>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\",\"comster404\",\"brunofin\",\"thomasballinger\",\"noobs2ninjas\",\"beohoff\"]</code>",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try using <a href='http://api.jquery.com/jquery.each/'>jQuery's $.getJSON()</a> to consume APIs.",
|
||||
"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>"
|
||||
],
|
||||
"challengeType": 3,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7158d8c442eddfaeb5bd13",
|
||||
"name": "Zipline: 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> that successfully reverse-engineers this: <a href='http://codepen.io/AdventureBear/full/vEoVMw' target='_blank'>http://codepen.io/AdventureBear/full/vEoVMw</a>.",
|
||||
"<span class='text-info'>Rule #1:</span> Don't look at the example project's code. 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 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.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try using <a href='http://api.jquery.com/jquery.each/'>jQuery's $.getJSON()</a> to consume APIs.",
|
||||
"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>"
|
||||
],
|
||||
"challengeType": 3,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7158d8c442eddfaeb5bd10",
|
||||
"name": "Zipline: 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> 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. 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='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try using <a href='http://api.jquery.com/jquery.each/'>jQuery's $.getJSON()</a> to consume APIs.",
|
||||
"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>"
|
||||
],
|
||||
"challengeType": 3,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7158d8c442eddfaeb5bd18",
|
||||
"name": "Zipline: Stylize Stories on Camper News",
|
||||
"difficulty": 1.04,
|
||||
"challengeSeed": "126415129",
|
||||
"description": [
|
||||
"<span class='text-info'>Objective:</span> Build a <a href='http://codepen.io' target='_blank'>CodePen.io</a> 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'>Rule #1:</span> Don't look at the example project's code. 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/stories/hotStories</code>.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try using <a href='http://api.jquery.com/jquery.each/'>jQuery's $.getJSON()</a> to consume APIs.",
|
||||
"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>"
|
||||
],
|
||||
"challengeType": 3,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7158d8c442eddfaeb5bd19",
|
||||
"name": "Zipline: Wikipedia Viewer",
|
||||
"difficulty": 1.05,
|
||||
"challengeSeed": "126415131",
|
||||
"description": [
|
||||
"<span class='text-info'>Objective:</span> Build a <a href='http://codepen.io' target='_blank'>CodePen.io</a> that successfully reverse-engineers this: <a href='http://codepen.io/GeoffStorbeck/full/MwgQea' target='_blank'>http://codepen.io/GeoffStorbeck/full/MwgQea</a>.",
|
||||
"<span class='text-info'>Rule #1:</span> Don't look at the example project's code. 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 search Wikipedia entries in a search box and see the resulting Wikipedia entries.",
|
||||
"<span class='text-info'>Bonus User Story:</span>As a user, I can click a button to see a random Wikipedia entry.",
|
||||
"<span class='text-info'>Bonus User Story:</span>As a user, when I type in the search box, I can see a dropdown menu with autocomplete options for matching Wikipedia entries.",
|
||||
"<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='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</a> if you get stuck. Try using <a href='http://api.jquery.com/jquery.each/'>jQuery's $.getJSON()</a> to consume APIs.",
|
||||
"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>"
|
||||
],
|
||||
"challengeType": 3,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7158d8c442eddfaeb5bd0f",
|
||||
"name": "Zipline: Build a Pomodoro Clock",
|
||||
"difficulty": 1.06,
|
||||
"challengeSeed": "126411567",
|
||||
"description": [
|
||||
"<span class='text-info'>Objective:</span> Build a <a href='http://codepen.io' target='_blank'>CodePen.io</a> that successfully reverse-engineers this: <a href='http://codepen.io/GeoffStorbeck/full/RPbGxZ/' target='_blank'>http://codepen.io/GeoffStorbeck/full/RPbGxZ/</a>.",
|
||||
"<span class='text-info'>Rule #1:</span> Don't look at the example project's code. 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 start a 25 minute pomodoro, and the timer will go off once 25 minutes has elapsed.",
|
||||
"<span class='text-info'>Bonus User Story:</span> As a user, I can reset the clock for my next pomodoro.",
|
||||
"<span class='text-info'>Bonus User Story:</span> As a user, I can customize the length of each pomodoro.",
|
||||
"Remember to use <a href='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</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>"
|
||||
],
|
||||
"challengeType": 3,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7158d8c442eddfaeb5bd17",
|
||||
"name": "Zipline: Build a JavaScript Calculator",
|
||||
"difficulty": 1.07,
|
||||
"challengeSeed": "126411565",
|
||||
"description": [
|
||||
"<span class='text-info'>Objective:</span> Build a <a href='http://codepen.io' target='_blank'>CodePen.io</a> 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. 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='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</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>"
|
||||
],
|
||||
"challengeType": 3,
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "bd7158d8c442eddfaeb5bd1c",
|
||||
"name": "Zipline: Build a Tic Tac Toe Game",
|
||||
"difficulty": 1.08,
|
||||
"challengeSeed": "126415123",
|
||||
"description": [
|
||||
"<span class='text-info'>Objective:</span> Build a <a href='http://codepen.io' target='_blank'>CodePen.io</a> that successfully reverse-engineers this: <a href='http://codepen.io/alex-dixon/full/JogOpQ/' target='_blank'>http://codepen.io/alex-dixon/full/JogOpQ/</a>.",
|
||||
"<span class='text-info'>Rule #1:</span> Don't look at the example project's code. 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 play a game of Tic Tac Toe with the computer.",
|
||||
"<span class='text-info'>Bonus User Story:</span> As a user, I can never actually win against the computer - at best I can tie.",
|
||||
"<span class='text-info'>Bonus User Story:</span> As a user, my game will reset as soon as it's over so I can play again.",
|
||||
"<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='/field-guide/how-do-i-get-help-when-I-get-stuck'>RSAP</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>"
|
||||
],
|
||||
"challengeType": 3,
|
||||
"tests": []
|
||||
}
|
||||
]
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -17,7 +17,7 @@
|
||||
"<div class=\"col-xs-12 col-sm-10 col-sm-offset-1\">",
|
||||
" <h3 class='text-left'>We're a community of busy people who learn to code by building projects for nonprofits.</h3>",
|
||||
" <p class='text-left'>We help our campers (students):</p>",
|
||||
" <p>",
|
||||
" <p class='large-p'>",
|
||||
" <ol>",
|
||||
" <li>Learn full stack JavaScript</li>",
|
||||
" <li>Build a portfolio of real apps that real people are using</li>",
|
||||
@ -34,13 +34,13 @@
|
||||
"<div class=\"col-xs-12 col-sm-10 col-sm-offset-1\">",
|
||||
" <h3 class='text-left'>Learning to code is hard.</h3>",
|
||||
" <p class='text-left'>Most people who successfully learn to code:</p>",
|
||||
" <p>",
|
||||
" <p class='large-p'>",
|
||||
" <ol>",
|
||||
" <li>Make friends with people who code</li>",
|
||||
" <li>Code a little every day</li>",
|
||||
" </ol>",
|
||||
" </p>",
|
||||
" <p>We give you the structure and the community you need so you can successfully learn to code.</p>",
|
||||
" <p class='large-p'>We give you the structure and the community you need so you can successfully learn to code.</p>",
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
@ -50,7 +50,7 @@
|
||||
"description": [
|
||||
"<div class=\"col-xs-12 col-sm-10 col-sm-offset-1\">",
|
||||
" <h3>Our main advantage is that we're accessible to busy adults who want to change careers. Specifically, we're:</h3>",
|
||||
" <p>",
|
||||
" <p class='large-p'>",
|
||||
" <ul>",
|
||||
" <li>• Free</li>",
|
||||
" <li>• Self-paced</li>",
|
||||
@ -89,7 +89,7 @@
|
||||
" <h3 class='text-left'>If you complete this program, <span class='text-info'>you will be able to get a coding job</span>. Many of our campers have already gotten coding jobs.</h3>",
|
||||
" <img class='img-center img-responsive' src=\"https://www.evernote.com/shard/s116/sh/55c128c7-5d99-41cc-b03d-b3de22611c8d/b43e467b3889f646fec34bb4c161e2a2/deep/0/What's-wrong-with-this-picture----Code.org.png\"/>",
|
||||
" <h3>Here are the facts:</h3>",
|
||||
" <p>",
|
||||
" <p class='large-p'>",
|
||||
" <ul>",
|
||||
" <li>• There are hundreds of thousands of unfilled coding jobs.</li>",
|
||||
" <li>• Employers and the US government have joined together to promote nontraditional coding programs like Free Code Camp.</li>",
|
||||
@ -106,7 +106,7 @@
|
||||
"description": [
|
||||
"<div class=\"text-left col-xs-12 col-md-10 col-md-offset-1\">",
|
||||
" <h3>First, you'll learn basic web design tools like:</h3>",
|
||||
" <p>",
|
||||
" <p class='large-p'>",
|
||||
" <ul>",
|
||||
" <li>• HTML - the structure of web pages</li>",
|
||||
" <li>• CSS - the visual style of web pages</li>",
|
||||
@ -116,14 +116,14 @@
|
||||
" </ul>",
|
||||
" </p>",
|
||||
" <h3>Then you'll learn computer science and the art of programming:</h3>",
|
||||
" <p>",
|
||||
" <p class='large-p'>",
|
||||
" <ul>",
|
||||
" <li>• JavaScript - the one programming language that all web browsers use</li>",
|
||||
" <li>• Algorithms - step-by-step recipes for getting things done</li>",
|
||||
" </ul>",
|
||||
" </p>",
|
||||
" <h3>Finally you'll learn Agile Methodologies and Full Stack JavaScript to build projects for nonprofits:</h3>",
|
||||
" <p>",
|
||||
" <p class='large-p'>",
|
||||
" <ul>",
|
||||
" <li>• Agile - a set of software development principles that focus the design and production of a project on the needs of its users</li>",
|
||||
" <li>• Git - a version control system for saving and sharing your projects</li>",
|
||||
@ -142,7 +142,7 @@
|
||||
"description": [
|
||||
"<div class=\"text-left col-xs-12 col-md-10 col-md-offset-1\">",
|
||||
" <h3>It takes about 1,600 hours of coding to develop the skills you'll need to get an entry level software engineering job.</h3>",
|
||||
" <p>Most coding bootcamps try to jam all this into 3 or 4 months of intensive study. Free Code Camp is fully online, and there will always be other people at your skill level that you can pair program with, so you can learn at your own pace. Here are some example coding schedules:</p>",
|
||||
" <p class='large-p'>Most coding bootcamps try to jam all this into 3 or 4 months of intensive study. Free Code Camp is fully online, and there will always be other people at your skill level that you can pair program with, so you can learn at your own pace. Here are some example coding schedules:</p>",
|
||||
" <table class=\"table\">",
|
||||
" <thead>",
|
||||
" <th>Time budgeted</th>",
|
||||
@ -178,9 +178,9 @@
|
||||
"name": "Why does Free Code Camp use JavaScript instead of Ruby or Python?",
|
||||
"description": [
|
||||
"<div class=\"text-left col-xs-12 col-md-10 col-md-offset-1\">",
|
||||
" <p>Like JavaScript, Ruby and Python are high-level scripting languages that can be used for full stack web development.</p>",
|
||||
" <p>But even if you learned these languages, you'd still need to learn JavaScript. That's because JavaScript is the only language that runs in web browsers. JavaScript has been around for 20 years, and it is still growing in popularity.</p>",
|
||||
" <p>Because of this, JavaScript has more tools and online learning resources than any other language.</p>",
|
||||
" <p class='large-p'>Like JavaScript, Ruby and Python are high-level scripting languages that can be used for full stack web development.</p>",
|
||||
" <p class='large-p'>But even if you learned these languages, you'd still need to learn JavaScript. That's because JavaScript is the only language that runs in web browsers. JavaScript has been around for 20 years, and it is still growing in popularity.</p>",
|
||||
" <p class='large-p'>Because of this, JavaScript has more tools and online learning resources than any other language.</p>",
|
||||
" <img src=\"https://s3.amazonaws.com/freecodecamp/github-repo-growth.png\" style=\"max-height: 355px;\" alt=\"A chart showing the volume of new GitHub repositories by year, with JavaScript growing and most languages declining.\" class=\"img-center img-responsive\"/>",
|
||||
"<br>",
|
||||
"</div>"
|
||||
@ -193,8 +193,8 @@
|
||||
"<div class=\"text-left col-xs-12 col-md-10 col-md-offset-1\">",
|
||||
" <h3>Pair programming is where two people code together on one computer.</h3>",
|
||||
" <img class='img-responsive img-center' src='http://cs10.org/sp15/resources/images/pairprogramming.jpg'>",
|
||||
" <p>You discuss different approaches to solving problems, and keep each other motivated. The result is better code than either of you could have written by yourselves. Because of its benefits, many engineers pair program full time. And it's the best way to learn coding. Thanks to tools that allow two people to share mouse and keyboard inputs, you can pair program with a friend without needing to be in the same room.</p>",
|
||||
" <p>By pair programming with other Free Code Camp students on our coding challenges. Eventually, you'll work with people at nonprofits to build real-life software solutions.</p>",
|
||||
" <p class='large-p'>You discuss different approaches to solving problems, and keep each other motivated. The result is better code than either of you could have written by yourselves. Because of its benefits, many engineers pair program full time. And it's the best way to learn coding. Thanks to tools that allow two people to share mouse and keyboard inputs, you can pair program with a friend without needing to be in the same room.</p>",
|
||||
" <p class='large-p'>By pair programming with other Free Code Camp students on our coding challenges. Eventually, you'll work with people at nonprofits to build real-life software solutions.</p>",
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
@ -204,7 +204,7 @@
|
||||
"description": [
|
||||
"<div class=\"col-xs-12 col-sm-10 col-sm-offset-1\">",
|
||||
" <h3>When you get stuck, remember: RSAP.</h3>",
|
||||
" <p>",
|
||||
" <p class='large-p'>",
|
||||
" <ol>",
|
||||
" <li><span class='text-info'>Read</span> the documentation or error</li>",
|
||||
" <li><span class='text-info'>Search</span> Google</li>",
|
||||
@ -212,11 +212,11 @@
|
||||
" <li><span class='text-info'>Post</span> on Stack Overflow</li>",
|
||||
" </ol>",
|
||||
" </p>",
|
||||
" <p>This is the most time-efficient way to handle being stuck, and it's the most respectful of other people's time, too.</p>",
|
||||
" <p>Most of the time, you'll solve your problem after just one or two steps of this algorithm.</p>",
|
||||
" <p>We have a special chat room just for getting help: <a href='https://freecode.slack.com/messages/help/' target='_blank'>https://freecode.slack.com/messages/help/</a></p>",
|
||||
" <p>Also, if you need to post on Stack Overflow, be sure to read their guide to asking good questions: <a href='http://stackoverflow.com/help/how-to-ask' target='_blank'>http://stackoverflow.com/help/how-to-ask</a>.</p>",
|
||||
" <p>Learning to code is hard. But it's a lot easier if you ask for help when you need it!</p>",
|
||||
" <p class='large-p'>This is the most time-efficient way to handle being stuck, and it's the most respectful of other people's time, too.</p>",
|
||||
" <p class='large-p'>Most of the time, you'll solve your problem after just one or two steps of this algorithm.</p>",
|
||||
" <p class='large-p'>We have a special chat room just for getting help: <a href='https://freecode.slack.com/messages/help/' target='_blank'>https://freecode.slack.com/messages/help/</a></p>",
|
||||
" <p class='large-p'>Also, if you need to post on Stack Overflow, be sure to read their guide to asking good questions: <a href='http://stackoverflow.com/help/how-to-ask' target='_blank'>http://stackoverflow.com/help/how-to-ask</a>.</p>",
|
||||
" <p class='large-p'>Learning to code is hard. But it's a lot easier if you ask for help when you need it!</p>",
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
@ -226,8 +226,8 @@
|
||||
"description": [
|
||||
"<div class=\"col-xs-12 col-sm-10 col-sm-offset-1\">",
|
||||
" <h3>This guide was designed as a reference for you. You shouldn't try to read it all today.</h3>",
|
||||
" <p>Feel free to come back any time and jump around, reading any articles that seem interesting to you at the time.</p>",
|
||||
" <p>If you're currently doing our \"Browse our Field Guide\" Waypoint, go ahead and mark that challenge complete and move on to your next Waypoint.</p>",
|
||||
" <p class='large-p'>Feel free to come back any time and jump around, reading any articles that seem interesting to you at the time.</p>",
|
||||
" <p class='large-p'>If you're currently doing our \"Browse our Field Guide\" Waypoint, go ahead and mark that challenge complete and move on to your next Waypoint.</p>",
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
@ -237,9 +237,9 @@
|
||||
"description": [
|
||||
"<div class=\"text-left col-xs-12 col-md-10 col-md-offset-1\">",
|
||||
" <h3>We are completely free for both students and for nonprofits.</h3>",
|
||||
" <p>Our name is Free Code Camp. We are a free code camp. If you had to pay us (or sign over future earnings), we'd have to change our name. And we are not going to do that.</p>",
|
||||
" <p>Everyone working on our community and our open source projects is a volunteer.</p>",
|
||||
" <p>We plan to eventually cover our operational costs by earning job placement bonuses from companies who hire our graduates. Note that we will not actually garnish any wages from our graduates - employers are already paying recruiters thousands of dollars to find successful candidates. Employers will simply pay the recruitment bonus to Free Code Camp instead of paying a recruiter.</p>",
|
||||
" <p class='large-p'>Our name is Free Code Camp. We are a free code camp. If you had to pay us (or sign over future earnings), we'd have to change our name. And we are not going to do that.</p>",
|
||||
" <p class='large-p'>Everyone working on our community and our open source projects is a volunteer.</p>",
|
||||
" <p class='large-p'>We plan to eventually cover our operational costs by earning job placement bonuses from companies who hire our graduates. Note that we will not actually garnish any wages from our graduates - employers are already paying recruiters thousands of dollars to find successful candidates. Employers will simply pay the recruitment bonus to Free Code Camp instead of paying a recruiter.</p>",
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
@ -249,8 +249,8 @@
|
||||
"description": [
|
||||
"<div class=\"text-left col-xs-12 col-md-10 col-md-offset-1\">",
|
||||
" <h3>Unlike coding bootcamps, anyone can study at Free Code Camp.</h3>",
|
||||
" <p>We're not going to tell you that you can't become a software engineer. We believe the only person who should be able to tell you that is you.</p>",
|
||||
" <p>If you persevere, and keep working through our challenges and nonprofit projects, you will become an employable software engineer.</p>",
|
||||
" <p class='large-p'>We're not going to tell you that you can't become a software engineer. We believe the only person who should be able to tell you that is you.</p>",
|
||||
" <p class='large-p'>If you persevere, and keep working through our challenges and nonprofit projects, you will become an employable software engineer.</p>",
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
@ -260,17 +260,17 @@
|
||||
"description": [
|
||||
"<div class=\"col-xs-12 col-sm-10 col-sm-offset-1\">",
|
||||
" <h3>If you're interested in coding JavaScript live in front of dozens of people on our popular <a href='http://twitch.tv/freecodecamp' target='_blank'>twitch.tv channel</a>, we'd love to have you.</h3>",
|
||||
"<p>Please follow these steps to get started:</p>",
|
||||
" <p>",
|
||||
"<p class='large-p'>Please follow these steps to get started:</p>",
|
||||
" <p class='large-p'>",
|
||||
" <ol>",
|
||||
" <li>Follow <a href='http://www.hdpvrcapture.com/wordpress/?p=5951' target='_blank'>this tutorial</a> to set up your computer for streaming.</li>",
|
||||
" <li>Contact Jason Ruekert - he's @jsonify in Slack. He's in charge of our Twitch.tv channel. Tell him what you'd like to stream, and when you're available to stream.</li>",
|
||||
" <li>Jason will pair with you using Screen Hero to verify your computer is configured properly to stream.</li>",
|
||||
" </ol>",
|
||||
" </p>",
|
||||
" <p>Be respectful of your audience. Everything you stream should be related to coding JavaScript, and should be acceptable for children. (Yes, children do sometimes watch our Twitch stream to learn to code).</p>",
|
||||
" <p>While you're streaming, keep the chat room open so you can respond to questions from your viewers. If someone follows Free Code Camp on Twitch, try to thank them.</p>",
|
||||
" <p>If you do a good job, we'll invite you back to stream some more. Who knows, you might become one of our regular streamers!</p>",
|
||||
" <p class='large-p'>Be respectful of your audience. Everything you stream should be related to coding JavaScript, and should be acceptable for children. (Yes, children do sometimes watch our Twitch stream to learn to code).</p>",
|
||||
" <p class='large-p'>While you're streaming, keep the chat room open so you can respond to questions from your viewers. If someone follows Free Code Camp on Twitch, try to thank them.</p>",
|
||||
" <p class='large-p'>If you do a good job, we'll invite you back to stream some more. Who knows, you might become one of our regular streamers!</p>",
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
@ -389,7 +389,7 @@
|
||||
" </ol>",
|
||||
" </h4>",
|
||||
" <h3>If you didn't see your city on this list, you should create your own Facebook group for your city. Please follow these steps:</h3>",
|
||||
" <p>",
|
||||
" <p class='large-p'>",
|
||||
" <ol>",
|
||||
" <li>Sign in to Facebook.</li>",
|
||||
" <li>Click the down arrow in the upper right corner of the screen, then choose \"Create Group\" from the options.",
|
||||
@ -417,8 +417,8 @@
|
||||
" <li>Join our #local-group-leaders channel on Slack, where we share ideas about involving campers in your city.</li>",
|
||||
" </ol>",
|
||||
" </p>",
|
||||
" <p>If you don't have a Facebook page, we strongly recommend you create one, even if it's just for the purpose of coordinating with campers in your city through this group.</p>",
|
||||
" <p>If Facebook is blocked in your country, feel free to use social network with a similar group functionality that's popular in your region.</p>",
|
||||
" <p class='large-p'>If you don't have a Facebook page, we strongly recommend you create one, even if it's just for the purpose of coordinating with campers in your city through this group.</p>",
|
||||
" <p class='large-p'>If Facebook is blocked in your country, feel free to use social network with a similar group functionality that's popular in your region.</p>",
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
@ -431,6 +431,20 @@
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"_id": "bd7158d9c442eddfaeb5b2ef",
|
||||
"name": "Why doesn't Free Code Camp teach technical interviewing skills?",
|
||||
"description": [
|
||||
"<div class=\"col-xs-12 col-sm-10 col-sm-offset-1\">",
|
||||
" <h3>The skills you need to successfully interview for a job are quite different from the skills you'll need on the job.</h3><br>",
|
||||
" <p class='large-p'>More and more employers are moving to a pair-programming-centric interview style. If you apply to these places, you don't need to make special preparations your interview - just pair program like you would on any Free Code Camp project.</p>",
|
||||
" <p class='large-p'>If you intend to apply for a job at a larger tech company like Apple, Microsoft, Google, Facebook or Amazon, you can prepare for your interviews by simply working through this single authoritative book. Many of the questions you'll be asked during your interviews will come straight out of this book, which is standard-issue in Silicon Valley.</p>",
|
||||
" <img src='http://a3.mzstatic.com/us/r1000/095/Purple/3f/58/42/mzl.xypmpeal.320x480-75.jpg' class='img-center img-responsive'>",
|
||||
" <p class='large-p'>You can download the 4th edition of this book in PDF form for free <a href='http://www.mktechnicalclasses.com/Notes/Cracking%20the%20Coding%20Interview,%204%20Edition%20-%20150%20Programming%20Interview%20Questions%20and%20Solutions.pdf' target='_blank'>here</a> or buy the 5th edition of the book <a href='http://www.amazon.com/gp/product/098478280X/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=098478280X&linkCode=as2&tag=out0b4b-20&linkId=4LOZ5JGICYZJO33D' target='_blank'>here</a>.",
|
||||
" <p class='large-p'>We may focus more on interview preparation in the future if we determine that it's necessary. In the mean time, Free Code Camp will continue to focus skills that are directly related to becoming a job-ready software engineer.",
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"_id": "bd7158d9c442eddfaeb5bdef",
|
||||
"name": "How do I best use the Global Control Shortcuts for Mac?",
|
||||
@ -438,8 +452,8 @@
|
||||
"<div class=\"col-xs-12 col-sm-10 col-sm-offset-1\">",
|
||||
" <h3>These Global Control Shortcuts for Mac will save you hours by speeding up your typing.</h3><br>",
|
||||
" <div class=\"embed-responsive embed-responsive-16by9\"><iframe src=\"//player.vimeo.com/video/107073108\" class=\"embed-responsive-item\"></iframe></div>",
|
||||
" <p>These global shortcuts work everywhere on a Mac:</p>",
|
||||
" <p>",
|
||||
" <p class='large-p'>These global shortcuts work everywhere on a Mac:</p>",
|
||||
" <p class='large-p'>",
|
||||
" <ul>",
|
||||
" <li>Control + F = Forward</li>",
|
||||
" <li>Control + B = Backward</li>",
|
||||
@ -464,8 +478,8 @@
|
||||
" <div class=\"embed-responsive embed-responsive-16by9\">",
|
||||
" <iframe src=\"//player.vimeo.com/video/115194016\" class=\"embed-responsive-item\"></iframe>",
|
||||
" </div>",
|
||||
" <p>The shortcuts:</p>",
|
||||
" <p>",
|
||||
" <p class='large-p'>The shortcuts:</p>",
|
||||
" <p class='large-p'>",
|
||||
" <ul>",
|
||||
" <li>j - move down</li>",
|
||||
" <li>k - move up</li>",
|
||||
@ -492,8 +506,8 @@
|
||||
" <div class=\"embed-responsive embed-responsive-16by9\">",
|
||||
" <iframe src=\"//player.vimeo.com/video/115194017\" class=\"embed-responsive-item\"></iframe>",
|
||||
" </div>",
|
||||
" <p>Here are the technologies we used here:</p>",
|
||||
" <p>",
|
||||
" <p class='large-p'>Here are the technologies we used here:</p>",
|
||||
" <p class='large-p'>",
|
||||
" <ul>",
|
||||
" <li><a href='http://www.atom.io/'>atom.io</a> - a free code editor</li>",
|
||||
" <li><a href='http://www.startbootstrap.com/'>startbootstrap.com</a> - a collection of free responsive (Bootstrap) templates</li>",
|
||||
@ -501,7 +515,7 @@
|
||||
" <li><a href='http://www.bitballoon.com/'>bitballoon.com</a> - a tool for drag and drop website deployment</li>",
|
||||
" </ul>",
|
||||
" </p>",
|
||||
" <p>You will quickly reach the limits of what you can do without actually coding, but it's nice to be able to rapidly build working prototype websites like this.</p>",
|
||||
" <p class='large-p'>You will quickly reach the limits of what you can do without actually coding, but it's nice to be able to rapidly build working prototype websites like this.</p>",
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
@ -510,15 +524,15 @@
|
||||
"name": "How do Free Code Camp's Nonprofit Projects work?",
|
||||
"description": [
|
||||
"<div class='col-xs-12 col-sm-10 col-sm-offset-1'>",
|
||||
" <p>Building nonprofit projects is the main way that our campers learn full stack JavaScript and agile software development. Once you complete the Free Code Camp Waypoints, Bonfires, Ziplines and Basejumps, you'll begin this process.</p>",
|
||||
" <p class='large-p'>Building nonprofit projects is the main way that our campers learn full stack JavaScript and agile software development. Once you complete the Free Code Camp Waypoints, Bonfires, Ziplines and Basejumps, you'll begin this process.</p>",
|
||||
" <h3>Starting with the end in mind</h3>",
|
||||
" <p>Our goal at Free Code Camp is to help you land a job as a junior software developer (or, if you prefer, a 'pivot job' that leads your current career in a more technical direction).</p>",
|
||||
" <p>You'll continue to work on nonprofit projects until you've built a sufficiently impressive portfolio and references to start your job search. Your portfolio will ultimately have three to five nonprofit projects. We estimate that the 900 hours of nonprofit projects you're going to complete, in addition to the 100 hours of challenges you've already completed, will be enough to qualify you for your first coding job. This will produce a much broader portfolio than a traditional coding bootcamp, which generally only has one or two capstone projects.</p>",
|
||||
" <p class='large-p'>Our goal at Free Code Camp is to help you land a job as a junior software developer (or, if you prefer, a 'pivot job' that leads your current career in a more technical direction).</p>",
|
||||
" <p class='large-p'>You'll continue to work on nonprofit projects until you've built a sufficiently impressive portfolio and references to start your job search. Your portfolio will ultimately have three to five nonprofit projects. We estimate that the 900 hours of nonprofit projects you're going to complete, in addition to the 100 hours of challenges you've already completed, will be enough to qualify you for your first coding job. This will produce a much broader portfolio than a traditional coding bootcamp, which generally only has one or two capstone projects.</p>",
|
||||
" <h3>Choosing your first Nonprofit Project</h3>",
|
||||
" <p>We've categorized all the nonprofit projects by estimated time investment per camper: 100 hours, 200 hours, and 300 hours. These are only rough estimates.</p>",
|
||||
" <p>Example: if you and the camper you're paired up with (your pair) each stated you could work 20 hours per week. If the project is a 100 hour per camper project, you should be able to complete it in about 5 weeks.</p>",
|
||||
" <p>Our team of nonprofit project camp counselors will match you and your pair based on:</p>",
|
||||
" <p>",
|
||||
" <p class='large-p'>We've categorized all the nonprofit projects by estimated time investment per camper: 100 hours, 200 hours, and 300 hours. These are only rough estimates.</p>",
|
||||
" <p class='large-p'>Example: if you and the camper you're paired up with (your pair) each stated you could work 20 hours per week. If the project is a 100 hour per camper project, you should be able to complete it in about 5 weeks.</p>",
|
||||
" <p class='large-p'>Our team of nonprofit project camp counselors will match you and your pair based on:</p>",
|
||||
" <p class='large-p'>",
|
||||
" <ol>",
|
||||
" <li>Your estimated time commitment (10, 20 or 40 hours per week)</li>",
|
||||
" <li>Your time zone</li>",
|
||||
@ -526,11 +540,11 @@
|
||||
" <li>Prior coding experience (we'd like both campers to be able to contribute equally)</li>",
|
||||
" </ol>",
|
||||
" </p>",
|
||||
" <p>We won't take age or gender into account. This will provide you with valuable experience in meshing with diverse teams, which is a reality of the contemporary workplace.</p>",
|
||||
" <p>You'll only work on one project at a time. Once you start a nonprofit project, we'll remove you from all other nonprofit project you've expressed interest in. There's a good chance those projects will no longer be available when you finish your current project, anyway. Don't worry, though - we get new nonprofit project requests every day, so there will be plenty more projects for you to consider after you finish your current one.</p>",
|
||||
" <p class='large-p'>We won't take age or gender into account. This will provide you with valuable experience in meshing with diverse teams, which is a reality of the contemporary workplace.</p>",
|
||||
" <p class='large-p'>You'll only work on one project at a time. Once you start a nonprofit project, we'll remove you from all other nonprofit project you've expressed interest in. There's a good chance those projects will no longer be available when you finish your current project, anyway. Don't worry, though - we get new nonprofit project requests every day, so there will be plenty more projects for you to consider after you finish your current one.</p>",
|
||||
" <h3>Finalizing the Project</h3>",
|
||||
" <p>Before you can start working on the project, our team of Nonprofit Project Coordinators will go through the following process:</p>",
|
||||
" <p>",
|
||||
" <p class='large-p'>Before you can start working on the project, our team of Nonprofit Project Coordinators will go through the following process:</p>",
|
||||
" <p class='large-p'>",
|
||||
" <ol>",
|
||||
" <li>We'll wait until there are two campers who have chosen the same project and look like they're a good match for one another based on the factors mentioned above.</li>",
|
||||
" <li>We'll call the stakeholder to confirm once again that he or she agrees with our  <a href=\"freecodecamp.com/nonprofits\">terms  </a>and has signed our  <a href=\"http://goo.gl/forms/0YKkd9bpcR\">Nonprofit Project Stakeholder Pledge</a>.</li>",
|
||||
@ -538,27 +552,27 @@
|
||||
" <li>If the stakeholder and both campers shows up promptly, and seem enthusiastic and professional, we'll start the project.</li>",
|
||||
" </ol>",
|
||||
" </p>",
|
||||
" <p>This lengthy process serves an important purpose: it reduces the likelihood that any of our campers or stakeholders will waste their precious time.</p>",
|
||||
" <p class='large-p'>This lengthy process serves an important purpose: it reduces the likelihood that any of our campers or stakeholders will waste their precious time.</p>",
|
||||
" <h3>Nonprofit Stakeholders</h3>",
|
||||
" <p>Each nonprofit project was submitted by a nonprofit. A representative from this nonprofit has agreed to serve as a \"stakeholder\" - an authorative person who understands the organization and its needs for this particular project.</p>",
|
||||
" <p>Stakeholders have a deep understanding of their organizations' needs. Campers will work with them to figure out the best solutions to these needs.</p>",
|
||||
" <p>When you and your pair first speak with your nonprofit stakeholder, you'll:</p>",
|
||||
" <p>",
|
||||
" <p class='large-p'>Each nonprofit project was submitted by a nonprofit. A representative from this nonprofit has agreed to serve as a \"stakeholder\" - an authorative person who understands the organization and its needs for this particular project.</p>",
|
||||
" <p class='large-p'>Stakeholders have a deep understanding of their organizations' needs. Campers will work with them to figure out the best solutions to these needs.</p>",
|
||||
" <p class='large-p'>When you and your pair first speak with your nonprofit stakeholder, you'll:</p>",
|
||||
" <p class='large-p'>",
|
||||
" <ul>",
|
||||
" <li>talk at length to better understand their needs.</li>",
|
||||
" <li>create a new Trello board and use it to prioritize what needs to be built.</li>",
|
||||
" <li>and establish deadlines based on your weekly time commitment, and how long you think each task will take.</li>",
|
||||
" </ul>",
|
||||
" </p>",
|
||||
" <p>It's notoriously difficult to estimate how long building software projects will take, so feel free to ask camp counselors for help.</p>",
|
||||
" <p>You'll continue to meet with your stakeholder at least twice a month in your project's Slack channel.</p>",
|
||||
" <p>You should also ask questions in your project's Slack channel as they come up throughout the week, and your stakeholder can answer them asynchronously.</p>",
|
||||
" <p>Getting \"blocked\" on a task can take away your sense of forward momentum, so be sure to proactively seek answers to any ambiguities you encounter.</p>",
|
||||
" <p>Ultimately, the project will be considered complete once both the stakeholder's needs have been met, and you and your pair are happy with the project. Then you can add it to your portfolio!</p>",
|
||||
" <p class='large-p'>It's notoriously difficult to estimate how long building software projects will take, so feel free to ask camp counselors for help.</p>",
|
||||
" <p class='large-p'>You'll continue to meet with your stakeholder at least twice a month in your project's Slack channel.</p>",
|
||||
" <p class='large-p'>You should also ask questions in your project's Slack channel as they come up throughout the week, and your stakeholder can answer them asynchronously.</p>",
|
||||
" <p class='large-p'>Getting \"blocked\" on a task can take away your sense of forward momentum, so be sure to proactively seek answers to any ambiguities you encounter.</p>",
|
||||
" <p class='large-p'>Ultimately, the project will be considered complete once both the stakeholder's needs have been met, and you and your pair are happy with the project. Then you can add it to your portfolio!</p>",
|
||||
" <h3>Working with your Pair</h3>",
|
||||
" <p>You and your pair will pair program (code together on the same computer virtually) about half of the time, and work independently the other half of the time.</p>",
|
||||
" <p>Here are our recommended ways of collaborating:</p>",
|
||||
" <p>",
|
||||
" <p class='large-p'>You and your pair will pair program (code together on the same computer virtually) about half of the time, and work independently the other half of the time.</p>",
|
||||
" <p class='large-p'>Here are our recommended ways of collaborating:</p>",
|
||||
" <p class='large-p'>",
|
||||
" <ul>",
|
||||
" <li>• Slack has robust private messaging functionality. It's the main way our team communicates, and we recommend it over email.</li>",
|
||||
" <li>• Trello is great for managing projects. Work with your stakeholder to create Trello cards, and update these cards regularly as you make progress on them.</li>",
|
||||
@ -567,15 +581,15 @@
|
||||
" </ul>",
|
||||
" </p>",
|
||||
" <h3>Hosting Apps</h3>",
|
||||
" <p>Unless your stakeholder has an existing modern host (AWS, Digital Ocean), you'll need to transition them over to a new platform. We believe Heroku is the best choice for a vast majority of web projects. It's free, easy to use, and has both browser and command line interfaces. It's owned by Salesforce and used by a ton of companies, so it's accountable and unlikely to go away.</p>",
|
||||
" <p>If you need help convincing your stakeholder that Heroku is the ideal platform, we'll be happy to talk with them.</p>",
|
||||
" <p class='large-p'>Unless your stakeholder has an existing modern host (AWS, Digital Ocean), you'll need to transition them over to a new platform. We believe Heroku is the best choice for a vast majority of web projects. It's free, easy to use, and has both browser and command line interfaces. It's owned by Salesforce and used by a ton of companies, so it's accountable and unlikely to go away.</p>",
|
||||
" <p class='large-p'>If you need help convincing your stakeholder that Heroku is the ideal platform, we'll be happy to talk with them.</p>",
|
||||
" <h3>Maintaining Apps</h3>",
|
||||
" <p>Once you complete a nonprofit project, your obligation to its stakeholder is finished. You goal is to leave behind a well documented solution that can be easily maintained by a contract JavaScript developer (or even a less-technical \"super user\").</p>",
|
||||
" <p>While you will no longer need to help with feature development, we encourage you to consider helping your stakeholder with occasional patches down the road. After all, this project will be an important piece of your portfolio, and you'll want it to remain in good shape for curious future employers.</p>",
|
||||
" <p class='large-p'>Once you complete a nonprofit project, your obligation to its stakeholder is finished. You goal is to leave behind a well documented solution that can be easily maintained by a contract JavaScript developer (or even a less-technical \"super user\").</p>",
|
||||
" <p class='large-p'>While you will no longer need to help with feature development, we encourage you to consider helping your stakeholder with occasional patches down the road. After all, this project will be an important piece of your portfolio, and you'll want it to remain in good shape for curious future employers.</p>",
|
||||
" <h3>Pledging to finish the project</h3>",
|
||||
" <p>Your nonprofit stakeholder, your pair, and the volunteer camp counselor team are all counting on you to finish your nonprofit project. If you walk away from an unfinished nonprofit project, you'll become ineligible to ever be assigned another one.</p>",
|
||||
" <p>To confirm that you understand the seriousness of this commitment, we require that all campers  <a href=\"http://goo.gl/forms/ZMn96z2QqY\">sign this pledge  </a>before starting on their nonprofit projects.</p>",
|
||||
" <p>There will likely be times of confusion or frustration. This is normal in software development. The most important thing is that you do not give up and instead persevere through these setbacks. As Steve Jobs famously said, \"Real artists ship.\" And you are going to ship one successful nonprofit project after another until you feel ready to take the next step in your promising career.</p>",
|
||||
" <p class='large-p'>Your nonprofit stakeholder, your pair, and the volunteer camp counselor team are all counting on you to finish your nonprofit project. If you walk away from an unfinished nonprofit project, you'll become ineligible to ever be assigned another one.</p>",
|
||||
" <p class='large-p'>To confirm that you understand the seriousness of this commitment, we require that all campers  <a href=\"http://goo.gl/forms/ZMn96z2QqY\">sign this pledge  </a>before starting on their nonprofit projects.</p>",
|
||||
" <p class='large-p'>There will likely be times of confusion or frustration. This is normal in software development. The most important thing is that you do not give up and instead persevere through these setbacks. As Steve Jobs famously said, \"Real artists ship.\" And you are going to ship one successful nonprofit project after another until you feel ready to take the next step in your promising career.</p>",
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
@ -586,7 +600,7 @@
|
||||
"<div class='col-xs-12 col-sm-10 col-sm-offset-1'>",
|
||||
" <h3><a href=\"http://links.screenhero.com/e/c/eyJlbWFpbF9pZCI6Ik1qQTNNem9XQkNJQ1pBQUNjd0FYQVZrVEdnRkxNamtfX0JWZEdGVEpSZkVCWlRwbFpXRTBNamM0WVMxaE56SmlMVEV4WlRRdE9HUXpZUzFpWXpVNE1HRTJNalkxTldNNk1UUTJNVEEyQUE9PSIsInBvc2l0aW9uIjowLCJocmVmIjoiaHR0cDovL2RsLnNjcmVlbmhlcm8uY29tL3NtYXJ0ZG93bmxvYWQvZklYQU1UUUJBTEtQQkhQTC9TY3JlZW5oZXJvLnppcD9zb3VyY2U9d2ViIn0=\">Download for Mac</a></h3>",
|
||||
" <h3><a href=\"http://links.screenhero.com/e/c/eyJlbWFpbF9pZCI6Ik1qQTNNem9XQkNJQ1pBQUNjd0FYQVZrVEdnRkxNamtfX0JWZEdGVEpSZkVCWlRwbFpXRTBNamM0WVMxaE56SmlMVEV4WlRRdE9HUXpZUzFpWXpVNE1HRTJNalkxTldNNk1UUTJNVEEyQUE9PSIsInBvc2l0aW9uIjoxLCJocmVmIjoiaHR0cDovL2RsLnNjcmVlbmhlcm8uY29tL3NtYXJ0ZG93bmxvYWQvZklYQU1UUUJBTEtQQkhQTC9TY3JlZW5oZXJvLXNldHVwLmV4ZSJ9\"> Download for Windows</a></h3>",
|
||||
" <p>You'll use Screen Hero to pair program starting with <a href='/challenges/pair-program-on-bonfires'>http://freecodecamp.com/challenges/pair-program-on-bonfires</a></p>",
|
||||
" <p class='large-p'>You'll use Screen Hero to pair program starting with <a href='/challenges/pair-program-on-bonfires'>http://freecodecamp.com/challenges/pair-program-on-bonfires</a></p>",
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
@ -596,7 +610,7 @@
|
||||
"description": [
|
||||
"<div class='col-xs-12 col-sm-10 col-sm-offset-1'>",
|
||||
" <h3>Writing Bonfire challenges is a great way to exercise your own problem solving and testing abilities. Follow this process closely to maximize the chances of us accepting your bonfire.</h3>",
|
||||
" <p>",
|
||||
" <p class='large-p'>",
|
||||
" <ol>",
|
||||
" <li>Fork the Free Code Camp repository and <code>open seed_data/bonfires.json</code> to become familiar with the format of our bonfires.</li>",
|
||||
" <li>Regardless of your bonfire's difficulty, put it as the last bonfire in the JSON file. Change one of the numbers in the ID to ensure that your bonfire has a unique ID.</li>",
|
||||
@ -607,21 +621,21 @@
|
||||
" </p>",
|
||||
" <h3>Here is a description of each of the Bonfires' fields.</h3>",
|
||||
" <h3>Name</h3>",
|
||||
" <p>The name of your challenge. It's OK for this to be humorous but it must be brief and relevant to the task.</p>",
|
||||
" <p class='large-p'>The name of your challenge. It's OK for this to be humorous but it must be brief and relevant to the task.</p>",
|
||||
" <h3>Difficulty</h3>",
|
||||
" <p>Attempt to rate difficulty compared against existing bonfire challenges. A good proxy for the difficulty of a bonfire is how long it takes you to solve it. For every 15 minutes it takes, increase the difficulty. For example, a one-hour bonfire should probably be a 4.</p>",
|
||||
" <p class='large-p'>Attempt to rate difficulty compared against existing bonfire challenges. A good proxy for the difficulty of a bonfire is how long it takes you to solve it. For every 15 minutes it takes, increase the difficulty. For example, a one-hour bonfire should probably be a 4.</p>",
|
||||
" <h3>Description</h3>",
|
||||
" <p>Separate paragraphs with a line break. Only the first paragraph is visible prior to a user before they click the the 'More information' button.</p>",
|
||||
" <p>All necessary information must be included in the first paragraph. Write this first paragraph as succinctly as possible. Subsequent paragraphs should offer hints or details if needed.</p>",
|
||||
" <p>If your subject matter warrants deeper understanding, you may link to Wikipedia.</p>",
|
||||
" <p class='large-p'>Separate paragraphs with a line break. Only the first paragraph is visible prior to a user before they click the the 'More information' button.</p>",
|
||||
" <p class='large-p'>All necessary information must be included in the first paragraph. Write this first paragraph as succinctly as possible. Subsequent paragraphs should offer hints or details if needed.</p>",
|
||||
" <p class='large-p'>If your subject matter warrants deeper understanding, you may link to Wikipedia.</p>",
|
||||
" <h3>Challenge Seed</h3>",
|
||||
" <p>This is where you set up what will be in the editor when the camper starts the bonfire.</p>",
|
||||
" <p class='large-p'>This is where you set up what will be in the editor when the camper starts the bonfire.</p>",
|
||||
" <h3>Tests</h3>",
|
||||
" <p>These tests are what bring your challenge to life. Without them, we cannot confirm the accuracy of a user's submitted answer. Choose your tests wisely.</p>",
|
||||
" <p>Bonfire tests are written using the Chai.js assertion library. Please use the should and expect syntax for end user readability. As an example of what not do to, many of the original Bonfire challenges are written with assert syntax and many of the test cases are difficult to read.</p>",
|
||||
" <p>If your bonfire question has a lot of edge cases, you will need to write many tests for full coverage. If you find yourself writing more tests than you desire, you may consider simplifying the requirements of your bonfire challenge. For difficulty level 1 through 3, you will generally only need 2 to 4 tests.</p>",
|
||||
" <p class='large-p'>These tests are what bring your challenge to life. Without them, we cannot confirm the accuracy of a user's submitted answer. Choose your tests wisely.</p>",
|
||||
" <p class='large-p'>Bonfire tests are written using the Chai.js assertion library. Please use the should and expect syntax for end user readability. As an example of what not do to, many of the original Bonfire challenges are written with assert syntax and many of the test cases are difficult to read.</p>",
|
||||
" <p class='large-p'>If your bonfire question has a lot of edge cases, you will need to write many tests for full coverage. If you find yourself writing more tests than you desire, you may consider simplifying the requirements of your bonfire challenge. For difficulty level 1 through 3, you will generally only need 2 to 4 tests.</p>",
|
||||
" <h3>MDNlinks</h3>",
|
||||
" <p>Take a look at <code>seed_data/bonfireMDNlinks.js</code>. If any of these concepts are relevant to your bonfire, be sure to include them. If you know of an MDN article that isn't linked here, you can add it to the bonfireMDNlinks.js file before adding it to your bonfire.</p>",
|
||||
" <p class='large-p'>Take a look at <code>seed_data/bonfireMDNlinks.js</code>. If any of these concepts are relevant to your bonfire, be sure to include them. If you know of an MDN article that isn't linked here, you can add it to the bonfireMDNlinks.js file before adding it to your bonfire.</p>",
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
@ -631,21 +645,21 @@
|
||||
"description": [
|
||||
"<div class='col-xs-12 col-sm-10 col-sm-offset-1'>",
|
||||
" <h3>Free Code Camp is friendly place to learn to code. We're committed to keeping it that way.</h3>",
|
||||
" <p>All campers are required to agree with the following code of conduct. We'll enforce this code. We're expecting cooperation from all campers in ensuring a friendly environment for everybody.</p>",
|
||||
" <p class='large-p'>All campers are required to agree with the following code of conduct. We'll enforce this code. We're expecting cooperation from all campers in ensuring a friendly environment for everybody.</p>",
|
||||
" <h3>In short: be nice to your fellow campers.</h3>",
|
||||
" <h3>Remember these 3 things and your fellow campers will like you:</h3>",
|
||||
" <p>",
|
||||
" <p class='large-p'>",
|
||||
" <ol>",
|
||||
" <li>Compliment your fellow campers when they do good work. Congratulate them when they accomplish something (like finishing a nonprofit project or getting a job).</li>",
|
||||
" <li>Critique the work, not the camper doing it.</li>",
|
||||
" <li>Only argue about something if it's important to the greater discussion.</li>",
|
||||
" </ol>",
|
||||
" </p>",
|
||||
" <p>Free Code Camp should be a harassment-free experience for everyone, regardless of gender, gender identity and expression, age, sexual orientation, disability, physical appearance, body size, race, national origin, or religion (or lack thereof).</p>",
|
||||
" <p>We do not tolerate harassment of campers in any form, anywhere on Free Code Camp's online media (Slack, Twitch, etc.) or during pair programming. Harassment includes sexual language and imagery, deliberate intimidation, stalking, unwelcome sexual attention, libel, and any malicious hacking or social engineering.</p>",
|
||||
" <p>If a camper engages in harassing behavior, our team will take any action we deem appropriate, up to and including banning them from Free Code Camp.</p>",
|
||||
" <p>We want everyone to feel safe and respected. If you are being harassed or notice that someone else is being harassed, say something! Message @quincylarson, @terakilobyte and @codenonprofit in Slack (preferably with a screen shot of the offending language) so we can take fast action.</p>",
|
||||
" <p>If you have questions about this code of conduct, email us at <a href='mailto:team@freecodecamp.com'>team@freecodecamp.com</a>.</p>",
|
||||
" <p class='large-p'>Free Code Camp should be a harassment-free experience for everyone, regardless of gender, gender identity and expression, age, sexual orientation, disability, physical appearance, body size, race, national origin, or religion (or lack thereof).</p>",
|
||||
" <p class='large-p'>We do not tolerate harassment of campers in any form, anywhere on Free Code Camp's online media (Slack, Twitch, etc.) or during pair programming. Harassment includes sexual language and imagery, deliberate intimidation, stalking, unwelcome sexual attention, libel, and any malicious hacking or social engineering.</p>",
|
||||
" <p class='large-p'>If a camper engages in harassing behavior, our team will take any action we deem appropriate, up to and including banning them from Free Code Camp.</p>",
|
||||
" <p class='large-p'>We want everyone to feel safe and respected. If you are being harassed or notice that someone else is being harassed, say something! Message @quincylarson, @terakilobyte and @codenonprofit in Slack (preferably with a screen shot of the offending language) so we can take fast action.</p>",
|
||||
" <p class='large-p'>If you have questions about this code of conduct, email us at <a href='mailto:team@freecodecamp.com'>team@freecodecamp.com</a>.</p>",
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
@ -654,39 +668,39 @@
|
||||
"name": "What is the Free Code Camp Privacy Policy?",
|
||||
"description": [
|
||||
"<div class='col-xs-12 col-sm-10 col-sm-offset-1'>",
|
||||
" <p>Free Code Camp is committed to respecting the privacy of visitors to our web sites and web applications. The guidelines below explain how we protect the privacy of visitors to FreeCodeCamp.com and its features.</p>",
|
||||
" <p class='large-p'>Free Code Camp is committed to respecting the privacy of visitors to our web sites and web applications. The guidelines below explain how we protect the privacy of visitors to FreeCodeCamp.com and its features.</p>",
|
||||
" <h3>Personally Identifiable Information</h3>",
|
||||
" <p>Free Code Camp protects the identity of visitors to FreeCodeCamp.com by limiting the collection of personally identifiable information.</p>",
|
||||
" <p>Free Code Camp does not knowingly collect or solicit personally identifiable information from or about children under 13, except as permitted by law. If we discover we have received any information from a child under 13 in violation of this policy, we will delete that information immediately. If you believe Free Code Camp has any information from or about anyone under 13, please email us at <a href=\"mailto:team@freecodecamp.com\" target=\"_blank\">team@freecodecamp.com</a>.</p>",
|
||||
" <p>All personally identifiable information you provide to us is used by Free Code Camp and its team to process and manage your account, analyze the demographic of our users, or to deliver services through the site. </p>",
|
||||
" <p>If you choose to provide personally identifiable information to us, you may receive occasional emails from us that are relevant to Free Code Camp, getting a job, or learning to code in general.</p>",
|
||||
" <p>Free Code Camp may also use other third-party providers to facilitate the delivery of the services described above, and these third-party providers may be supplied with or have access to personally identifiable information for the sole purpose of providing these services, to you on behalf of Free Code Camp.</p>",
|
||||
" <p>Free Code Camp may also disclose personally identifiable information in special legal circumstances. For instance, such information may be used where it is necessary to protect our copyright or intellectual property rights, or if the law requires us to do so.</p>",
|
||||
" <p class='large-p'>Free Code Camp protects the identity of visitors to FreeCodeCamp.com by limiting the collection of personally identifiable information.</p>",
|
||||
" <p class='large-p'>Free Code Camp does not knowingly collect or solicit personally identifiable information from or about children under 13, except as permitted by law. If we discover we have received any information from a child under 13 in violation of this policy, we will delete that information immediately. If you believe Free Code Camp has any information from or about anyone under 13, please email us at <a href=\"mailto:team@freecodecamp.com\" target=\"_blank\">team@freecodecamp.com</a>.</p>",
|
||||
" <p class='large-p'>All personally identifiable information you provide to us is used by Free Code Camp and its team to process and manage your account, analyze the demographic of our users, or to deliver services through the site. </p>",
|
||||
" <p class='large-p'>If you choose to provide personally identifiable information to us, you may receive occasional emails from us that are relevant to Free Code Camp, getting a job, or learning to code in general.</p>",
|
||||
" <p class='large-p'>Free Code Camp may also use other third-party providers to facilitate the delivery of the services described above, and these third-party providers may be supplied with or have access to personally identifiable information for the sole purpose of providing these services, to you on behalf of Free Code Camp.</p>",
|
||||
" <p class='large-p'>Free Code Camp may also disclose personally identifiable information in special legal circumstances. For instance, such information may be used where it is necessary to protect our copyright or intellectual property rights, or if the law requires us to do so.</p>",
|
||||
" <h3>Anonymous Information</h3>",
|
||||
" <p>Anonymous aggregated data may be provided to other organizations we associate with for statistical purposes. For example, we may report to an organization that a certain percentage of our site's visitors are adults between the ages of 25 and 35.</p>",
|
||||
" <p class='large-p'>Anonymous aggregated data may be provided to other organizations we associate with for statistical purposes. For example, we may report to an organization that a certain percentage of our site's visitors are adults between the ages of 25 and 35.</p>",
|
||||
" <h3>Cookies and Beacons—Use by Free Code Camp; Opting Out</h3>",
|
||||
" <p>We use cookies and software logs to monitor the use of FreeCodeCamp.com and to gather non-personal information about visitors to the site. Cookies are small files that Free Code Camp transfers to the hard drives of visitors for record-keeping purposes. These monitoring systems allow us to track general information about our visitors, such as the type of browsers (for example, Firefox or Internet Explorer), the operating systems (for instance, Windows or Macintosh), or the Internet providers (for instance, Comcast) they use. This information is used for statistical and market research purposes to tailor content to usage patterns and to provide services requested by our customers. To delete these cookies, please see your browser's privacy settings.</p>",
|
||||
" <p>A beacon is an electronic file object (typically a transparent image) placed in the code of a Web page. We use third party beacons to monitor the traffic patterns of visitors from one Free Code Camp.com page to another and to improve site performance.</p>",
|
||||
" <p>None of the information we gather in this way can be used to identify any individual who visits our site.</p>",
|
||||
" <p class='large-p'>We use cookies and software logs to monitor the use of FreeCodeCamp.com and to gather non-personal information about visitors to the site. Cookies are small files that Free Code Camp transfers to the hard drives of visitors for record-keeping purposes. These monitoring systems allow us to track general information about our visitors, such as the type of browsers (for example, Firefox or Internet Explorer), the operating systems (for instance, Windows or Macintosh), or the Internet providers (for instance, Comcast) they use. This information is used for statistical and market research purposes to tailor content to usage patterns and to provide services requested by our customers. To delete these cookies, please see your browser's privacy settings.</p>",
|
||||
" <p class='large-p'>A beacon is an electronic file object (typically a transparent image) placed in the code of a Web page. We use third party beacons to monitor the traffic patterns of visitors from one Free Code Camp.com page to another and to improve site performance.</p>",
|
||||
" <p class='large-p'>None of the information we gather in this way can be used to identify any individual who visits our site.</p>",
|
||||
" <h3>Security</h3>",
|
||||
" <p>Any personally identifiable information collected through this site is stored on limited-access servers. We will maintain safeguards to protect these servers and the information they store.</p>",
|
||||
" <p class='large-p'>Any personally identifiable information collected through this site is stored on limited-access servers. We will maintain safeguards to protect these servers and the information they store.</p>",
|
||||
" <h3>Surveys</h3>",
|
||||
" <p>We may occasionally conduct on-line surveys. All surveys are voluntary and you may decline to participate.</p>",
|
||||
" <p class='large-p'>We may occasionally conduct on-line surveys. All surveys are voluntary and you may decline to participate.</p>",
|
||||
" <h3>Copyright</h3>",
|
||||
" <p>All of the content on FreeCodeCamp.com is copyrighted by Free Code Camp. If you'd like to redistribute it beyond simply sharing it through social media, please contact us at <a href=\"mailto:team@freecodecamp.com\" target=\"_blank\">team@freecodecamp.com</a>.</p>",
|
||||
" <p class='large-p'>All of the content on FreeCodeCamp.com is copyrighted by Free Code Camp. If you'd like to redistribute it beyond simply sharing it through social media, please contact us at <a href=\"mailto:team@freecodecamp.com\" target=\"_blank\">team@freecodecamp.com</a>.</p>",
|
||||
" <h3>Contacting Us</h3>",
|
||||
" <p>If you have questions about Free Code Camp, or to correct, update, or remove personally identifiable information, please email us at <a href=\"mailto:team@freecodecamp.com\" target=\"_blank\">team@freecodecamp.com</a>.</p>",
|
||||
" <p class='large-p'>If you have questions about Free Code Camp, or to correct, update, or remove personally identifiable information, please email us at <a href=\"mailto:team@freecodecamp.com\" target=\"_blank\">team@freecodecamp.com</a>.</p>",
|
||||
" <h3>Links to Other Web sites</h3>",
|
||||
" <p>Free Code Camp's sites each contain links to other Web sites. Free Code Camp is not responsible for the privacy practices or content of these third-party Web sites. We urge all FreeCodeCamp.com visitors to follow safe Internet practices: Do not supply Personally Identifiable Information to these Web sites unless you have verified their security and privacy policies.</p>",
|
||||
" <p class='large-p'>Free Code Camp's sites each contain links to other Web sites. Free Code Camp is not responsible for the privacy practices or content of these third-party Web sites. We urge all FreeCodeCamp.com visitors to follow safe Internet practices: Do not supply Personally Identifiable Information to these Web sites unless you have verified their security and privacy policies.</p>",
|
||||
" <h3>Data Retention</h3>",
|
||||
" <p>We retain your information for as long as necessary to permit us to use it for the purposes that we have communicated to you and comply with applicable law or regulations.</p>",
|
||||
" <p class='large-p'>We retain your information for as long as necessary to permit us to use it for the purposes that we have communicated to you and comply with applicable law or regulations.</p>",
|
||||
" <h3>Business Transfers</h3>",
|
||||
" <p>As we continue to develop our business, we might sell or buy subsidiaries, or business units. In such transactions, customer information generally is one of the transferred business assets but remains subject to the promises made in any pre-existing Privacy Policy (unless, of course, the customer consents otherwise). Also, in the unlikely event that Free Code Camp, or substantially all of its assets are acquired, customer information will be one of the transferred assets, and will remain subject to our Privacy Policy.</p>",
|
||||
" <p class='large-p'>As we continue to develop our business, we might sell or buy subsidiaries, or business units. In such transactions, customer information generally is one of the transferred business assets but remains subject to the promises made in any pre-existing Privacy Policy (unless, of course, the customer consents otherwise). Also, in the unlikely event that Free Code Camp, or substantially all of its assets are acquired, customer information will be one of the transferred assets, and will remain subject to our Privacy Policy.</p>",
|
||||
" <h3>Your California Privacy Rights</h3>",
|
||||
" <p>If you are a California resident, you are entitled to prevent sharing of your personal information with third parties for their own marketing purposes through a cost-free means. If you send a request to the address above, Free Code Camp will provide you with a California Customer Choice Notice that you may use to opt-out of such information sharing. To receive this notice, submit a written request to <a href=\"mailto:team@freecodecamp.com\" target=\"_blank\">team@freecodecamp.com</a>, specifying that you seek your "California Customer Choice Notice." Please allow at least thirty (30) days for a response.</p>",
|
||||
" <p class='large-p'>If you are a California resident, you are entitled to prevent sharing of your personal information with third parties for their own marketing purposes through a cost-free means. If you send a request to the address above, Free Code Camp will provide you with a California Customer Choice Notice that you may use to opt-out of such information sharing. To receive this notice, submit a written request to <a href=\"mailto:team@freecodecamp.com\" target=\"_blank\">team@freecodecamp.com</a>, specifying that you seek your "California Customer Choice Notice." Please allow at least thirty (30) days for a response.</p>",
|
||||
" <h3>Acceptance of Privacy Policy Terms and Conditions</h3>",
|
||||
" <p>By using this site, you signify your agreement to the terms and conditions of this FreeCodeCamp.com Privacy Policy. If you do not agree to these terms, please do not use this site. We reserve the right, at our sole discretion, to change, modify, add, or remove portions of this policy at any time. All amended terms automatically take effect 30 days after they are initially posted on the site. Please check this page periodically for any modifications. Your continued use of FreeCodeCamp.com following the posting of any changes to these terms shall mean that you have accepted those changes.</p>",
|
||||
" <p>If you have any questions or concerns, please send an email to <a href=\"mailto:team@freecodecamp.com\" target=\"_blank\">team@freecodecamp.com</a>.</p>",
|
||||
" <p class='large-p'>By using this site, you signify your agreement to the terms and conditions of this FreeCodeCamp.com Privacy Policy. If you do not agree to these terms, please do not use this site. We reserve the right, at our sole discretion, to change, modify, add, or remove portions of this policy at any time. All amended terms automatically take effect 30 days after they are initially posted on the site. Please check this page periodically for any modifications. Your continued use of FreeCodeCamp.com following the posting of any changes to these terms shall mean that you have accepted those changes.</p>",
|
||||
" <p class='large-p'>If you have any questions or concerns, please send an email to <a href=\"mailto:team@freecodecamp.com\" target=\"_blank\">team@freecodecamp.com</a>.</p>",
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
@ -696,7 +710,7 @@
|
||||
"description": [
|
||||
"<div class=\"col-xs-12 col-sm-10 col-sm-offset-1\">",
|
||||
" <h3>We're happy to do a quick interview for your publication or show. Here's whom you should contact about what, and how to best reach them:</h3>",
|
||||
" <p>",
|
||||
" <p class='large-p'>",
|
||||
" <ol>",
|
||||
" <li>Want to talk to about Free Code Camp's curriculum or long-term vision? Reach out to Quincy Larson. He's <a href='https://twitter.com/ossia' target='_blank'>@ossia</a> on Twitter and @quincylarson on Slack.</li>",
|
||||
" <li>Want to talk about Free Code Camp's open source codebase, infrastructure, or JavaScript in general? Talk to Nathan Leniz. He's <a href='https://twitter.com/terakilobyte' target='_blank'>@terakilobyte</a> on Twitter and @terakilobyte on Slack.</li>",
|
||||
@ -704,7 +718,7 @@
|
||||
" <li>Want to get a camper's perspective on our community? Talk with Bianca Mihai (@biancamihai on Slack and <a href='https://twitter.com/bubuslubu' target='_blank'>@bubuslubu</a> on Twitter) or Suzanne Atkinson (@adventurebear on Slack and <a href='https://twitter.com/SteelCityCoach' target='_blank'>@steelcitycoach</a> on Twitter).",
|
||||
" </ol>",
|
||||
" </p>",
|
||||
" <p>We strive to be helpful and transparent in everything we do. We'll do what we can to help you share our community with your audience.</p>",
|
||||
" <p class='large-p'>We strive to be helpful and transparent in everything we do. We'll do what we can to help you share our community with your audience.</p>",
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
@ -713,8 +727,8 @@
|
||||
"name": "How can I contribute to this guide?",
|
||||
"description": [
|
||||
"<div class=\"col-xs-12 col-sm-10 col-sm-offset-1\">",
|
||||
" <p>Contributing to our field guide is a great way to establish your history on GitHub, add to your portfolio, and help other campers. If you have a question about JavaScript or programming in general that you'd like us to add to the field guide, here are two ways to get it into the guide:</p>",
|
||||
" <p>",
|
||||
" <p class='large-p'>Contributing to our field guide is a great way to establish your history on GitHub, add to your portfolio, and help other campers. If you have a question about JavaScript or programming in general that you'd like us to add to the field guide, here are two ways to get it into the guide:</p>",
|
||||
" <p class='large-p'>",
|
||||
" <ol>",
|
||||
" <li>You can message @alex-dixon in Slack with your question.</li>",
|
||||
" <li>You can also contribute to this field guide directly via GitHub pull request, by cloning Free Code Camp's <a href='https://github.com/FreeCodeCamp/freecodecamp'>main repository</a> and modifying <a href='https://github.com/FreeCodeCamp/freecodecamp/blob/master/seed_data/field-guides.json'>field-guides.json</a>.</li>",
|
||||
|
File diff suppressed because it is too large
Load Diff
329
seed_data/future-jquery-ajax-json.json
Normal file
329
seed_data/future-jquery-ajax-json.json
Normal file
@ -0,0 +1,329 @@
|
||||
{
|
||||
"name": "jQuery, Ajax and JSON",
|
||||
"order" : 0.004,
|
||||
"challenges": [
|
||||
{
|
||||
"_id": "bad87fee1348bd9acdd08826",
|
||||
"name": "Waypoint: Learn how Script Tags and Document Ready Work",
|
||||
"difficulty": 0.072,
|
||||
"description": [
|
||||
"Test"
|
||||
],
|
||||
"tests": [
|
||||
"assert(typeof $('#target').attr('disabled') === 'undefined', 'Change the disabled attribute of the \"target\" button to false');",
|
||||
"expect($('#target')).to.exist()"
|
||||
],
|
||||
"challengeSeed": [
|
||||
"fccss",
|
||||
" $(document).ready(function() {",
|
||||
" $('#target').attr('disabled', true)",
|
||||
" });",
|
||||
"fcces",
|
||||
"<button id='target' class='btn btn-primary btn-block'>Enable this button with jQuery</button>"
|
||||
],
|
||||
"challengeType": 0
|
||||
},
|
||||
|
||||
{
|
||||
"_id": "bad87fee1348bd9aedc08826",
|
||||
"name": "Waypoint: Target Elements by Selectors Using jQuery",
|
||||
"difficulty": 0.073,
|
||||
"description": [
|
||||
|
||||
],
|
||||
"tests": [
|
||||
|
||||
],
|
||||
"challengeSeed": [
|
||||
|
||||
],
|
||||
"challengeType": 0
|
||||
},
|
||||
|
||||
{
|
||||
"_id": "bad87fee1348bd9aedb08826",
|
||||
"name": "Waypoint: Target Elements by Class Using jQuery",
|
||||
"difficulty": 0.074,
|
||||
"description": [
|
||||
|
||||
],
|
||||
"tests": [
|
||||
|
||||
],
|
||||
"challengeSeed": [
|
||||
|
||||
],
|
||||
"challengeType": 0
|
||||
},
|
||||
|
||||
{
|
||||
"_id": "bad87fee1348bd9aeda08826",
|
||||
"name": "Waypoint: Target an element by ID Using jQuery",
|
||||
"difficulty": 0.075,
|
||||
"description": [
|
||||
|
||||
],
|
||||
"tests": [
|
||||
|
||||
],
|
||||
"challengeSeed": [
|
||||
|
||||
],
|
||||
"challengeType": 0
|
||||
},
|
||||
|
||||
{
|
||||
"_id": "bad87fee1348bd9aed908826",
|
||||
"name": "Waypoint: Change the CSS of an Element Using jQuery",
|
||||
"difficulty": 0.076,
|
||||
"description": [
|
||||
|
||||
],
|
||||
"tests": [
|
||||
|
||||
],
|
||||
"challengeSeed": [
|
||||
|
||||
],
|
||||
"challengeType": 0
|
||||
},
|
||||
|
||||
{
|
||||
"_id": "bad87fee1348bd9aed808826",
|
||||
"name": "Waypoint: Disable an Element Using jQuery",
|
||||
"difficulty": 0.077,
|
||||
"description": [
|
||||
|
||||
],
|
||||
"tests": [
|
||||
|
||||
],
|
||||
"challengeSeed": [
|
||||
|
||||
],
|
||||
"challengeType": 0
|
||||
},
|
||||
|
||||
{
|
||||
"_id": "bad87fee1348bd9aed708826",
|
||||
"name": "Waypoint: Remove an Element Using jQuery",
|
||||
"difficulty": 0.078,
|
||||
"description": [
|
||||
|
||||
],
|
||||
"tests": [
|
||||
|
||||
],
|
||||
"challengeSeed": [
|
||||
|
||||
],
|
||||
"challengeType": 0
|
||||
},
|
||||
|
||||
{
|
||||
"_id": "bad87fee1348bd9aed608826",
|
||||
"name": "Waypoint: Move an Element Using jQuery",
|
||||
"difficulty": 0.079,
|
||||
"description": [
|
||||
|
||||
],
|
||||
"tests": [
|
||||
|
||||
],
|
||||
"challengeSeed": [
|
||||
|
||||
],
|
||||
"challengeType": 0
|
||||
},
|
||||
|
||||
{
|
||||
"_id": "bad87fee1348bd9aed508826",
|
||||
"name": "Waypoint: Clone an Element Using jQuery",
|
||||
"difficulty": 0.080,
|
||||
"description": [
|
||||
|
||||
],
|
||||
"tests": [
|
||||
|
||||
],
|
||||
"challengeSeed": [
|
||||
|
||||
],
|
||||
"challengeType": 0
|
||||
},
|
||||
|
||||
{
|
||||
"_id": "bad87fee1348bd9aed408826",
|
||||
"name": "Waypoint: Animate an Element Using jQuery",
|
||||
"difficulty": 0.081,
|
||||
"description": [
|
||||
|
||||
],
|
||||
"tests": [
|
||||
|
||||
],
|
||||
"challengeSeed": [
|
||||
|
||||
],
|
||||
"challengeType": 0
|
||||
},
|
||||
|
||||
{
|
||||
"_id": "bad87fee1348bd9aed308826",
|
||||
"name": "Waypoint: Target the Parent of an Element Using jQuery",
|
||||
"difficulty": 0.082,
|
||||
"description": [
|
||||
|
||||
],
|
||||
"tests": [
|
||||
|
||||
],
|
||||
"challengeSeed": [
|
||||
|
||||
],
|
||||
"challengeType": 0
|
||||
},
|
||||
|
||||
{
|
||||
"_id": "bad87fee1348bd9aed208826",
|
||||
"name": "Waypoint: Target the Children of an Element Using jQuery",
|
||||
"difficulty": 0.083,
|
||||
"description": [
|
||||
|
||||
],
|
||||
"tests": [
|
||||
|
||||
],
|
||||
"challengeSeed": [
|
||||
|
||||
],
|
||||
"challengeType": 0
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"_id": "bad87fee1348bd9aed108826",
|
||||
"name": "Waypoint: Target a Specific Child of an Element Using jQuery",
|
||||
"difficulty": 0.084,
|
||||
"description": [
|
||||
|
||||
],
|
||||
"tests": [
|
||||
|
||||
],
|
||||
"challengeSeed": [
|
||||
|
||||
],
|
||||
"challengeType": 0
|
||||
},
|
||||
|
||||
{
|
||||
"_id": "bad87fee1348bd9aed008826",
|
||||
"name": "Waypoint: Target Even Numbered Elements Using jQuery",
|
||||
"difficulty": 0.085,
|
||||
"description": [
|
||||
|
||||
],
|
||||
"tests": [
|
||||
|
||||
],
|
||||
"challengeSeed": [
|
||||
|
||||
],
|
||||
"challengeType": 0
|
||||
},
|
||||
|
||||
{
|
||||
"_id": "bad87fee1348bd9aecc08826",
|
||||
"name": "Waypoint: Read Data from an Element Using jQuery",
|
||||
"difficulty": 0.086,
|
||||
"description": [
|
||||
|
||||
],
|
||||
"tests": [
|
||||
|
||||
],
|
||||
"challengeSeed": [
|
||||
|
||||
],
|
||||
"challengeType": 0
|
||||
},
|
||||
|
||||
{
|
||||
"_id": "bad87fee1348bd9aebc08826",
|
||||
"name": "Waypoint: Get Data from an URL Using jQuery",
|
||||
"difficulty": 0.087,
|
||||
"description": [
|
||||
|
||||
],
|
||||
"tests": [
|
||||
|
||||
],
|
||||
"challengeSeed": [
|
||||
|
||||
],
|
||||
"challengeType": 0
|
||||
},
|
||||
|
||||
{
|
||||
"_id": "bad87fee1348bd9ae9c08826",
|
||||
"name": "Waypoint: Loop through JSON Data Using jQuery",
|
||||
"difficulty": 0.089,
|
||||
"description": [
|
||||
|
||||
],
|
||||
"tests": [
|
||||
|
||||
],
|
||||
"challengeSeed": [
|
||||
|
||||
],
|
||||
"challengeType": 0
|
||||
},
|
||||
|
||||
{
|
||||
"_id": "bad87fee1348bd9ae8c08826",
|
||||
"name": "Waypoint: Setup Click Events Using jQuery",
|
||||
"difficulty": 0.089,
|
||||
"description": [
|
||||
|
||||
],
|
||||
"tests": [
|
||||
|
||||
],
|
||||
"challengeSeed": [
|
||||
|
||||
],
|
||||
"challengeType": 0
|
||||
},
|
||||
{
|
||||
"_id": "bad87fee1348bd9aede08826",
|
||||
"name": "Waypoint: Use Hex Codes for Precise Colors",
|
||||
"difficulty": 0.071,
|
||||
"description": [
|
||||
|
||||
],
|
||||
"tests": [
|
||||
|
||||
],
|
||||
"challengeSeed": [
|
||||
|
||||
],
|
||||
"challengeType": 0
|
||||
},
|
||||
{
|
||||
"_id": "bad87fee1348bd9aedd08826",
|
||||
"name": "Waypoint: Use Shortened Hex Codes for Colors",
|
||||
"difficulty": 0.071,
|
||||
"description": [
|
||||
|
||||
],
|
||||
"tests": [
|
||||
|
||||
],
|
||||
"challengeSeed": [
|
||||
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -10,8 +10,6 @@
|
||||
],
|
||||
"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/",
|
||||
"stakeholderName": "Jonathan Tebeka",
|
||||
"stakeholderEmail": "jonathan@chasdeikaduri.org",
|
||||
"name": "Chasdei Kaduri",
|
||||
"endUser": "Clients, donors, and admin.",
|
||||
"approvedDeliverables": [
|
||||
@ -25,7 +23,9 @@
|
||||
"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": "http://chasdeikaduri.org/images/523455_516325865106850_1885515210_n.jpg",
|
||||
"estimatedHours": 200,
|
||||
"currentStatus": "started"
|
||||
"interestedCampers": [],
|
||||
"confirmedCampers": [],
|
||||
"currentStatus": "completed"
|
||||
},
|
||||
{
|
||||
"id": "bd7158d8c464cbafaeb4bdef",
|
||||
@ -34,8 +34,6 @@
|
||||
],
|
||||
"whatDoesNonprofitDo": "We connect simple technology with last mile communities to reduce poverty.",
|
||||
"websiteLink": "http://kopernik.info/",
|
||||
"stakeholderName": "Amber Gregory",
|
||||
"stakeholderEmail": "amber.gregory@kopernik.info",
|
||||
"name": "Kopernik",
|
||||
"endUser": "Women in rural Indonesia.",
|
||||
"approvedDeliverables": [
|
||||
@ -54,8 +52,6 @@
|
||||
],
|
||||
"whatDoesNonprofitDo": "We distribute biodegradable toothbrushes globally to children in need.",
|
||||
"websiteLink": "http://www.operationbrush.org/",
|
||||
"stakeholderName": "Dane Jonas",
|
||||
"stakeholderEmail": "DaneJonas@operationbrush.org",
|
||||
"name": "Operation Brush",
|
||||
"endUser": "Donors",
|
||||
"approvedDeliverables": [
|
||||
@ -65,7 +61,9 @@
|
||||
"logoUrl": "https://trello-attachments.s3.amazonaws.com/54d9810307b159a4d9027aa2/54d981bfe5eb145560fbb769/x/cf7f318bfe4aee631b0d0eeef272225c/logo.png",
|
||||
"imageUrl": "http://www.operationbrush.org/images/temp/hands1.png",
|
||||
"estimatedHours": 100,
|
||||
"currentStatus": "started"
|
||||
"interestedCampers": [],
|
||||
"confirmedCampers": [],
|
||||
"currentStatus": "completed"
|
||||
},
|
||||
{
|
||||
"id": "bd1325d8c464cbafaeb5bdef",
|
||||
@ -74,10 +72,8 @@
|
||||
],
|
||||
"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/",
|
||||
"stakeholderName": "Charity Kuahiwinui",
|
||||
"stakeholderEmail": "insurance@rosecityrollers.com",
|
||||
"name": "Rose City Rollers",
|
||||
"endUser": "Administrators, Coaches, and Volunteers",
|
||||
"endUser": "Roller derby administrators, coaches, and volunteers",
|
||||
"approvedDeliverables": [
|
||||
"community"
|
||||
],
|
||||
@ -92,10 +88,8 @@
|
||||
"requestedDeliverables": [
|
||||
"website"
|
||||
],
|
||||
"whatDoesNonprofitDo": "Save a Child's Heart provides urgently needed pediatric heart surgery and follow-up care for indigent children from developing countries",
|
||||
"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/",
|
||||
"stakeholderName": "Shier Ziser",
|
||||
"stakeholderEmail": "Shier_z@hotmail.com",
|
||||
"name": "Save a Child's Heart",
|
||||
"endUser": "Donors",
|
||||
"approvedDeliverables": [
|
||||
@ -112,10 +106,8 @@
|
||||
"requestedDeliverables": [
|
||||
"website"
|
||||
],
|
||||
"whatDoesNonprofitDo": "Savvy Cyber Kids enables youth to be empowered with technology by providing age appropriate resources and education.",
|
||||
"whatDoesNonprofitDo": "We empower youth with technology by providing age appropriate resources and education.",
|
||||
"websiteLink": "http://savvycyberkids.org/",
|
||||
"stakeholderName": "Ben Halpert",
|
||||
"stakeholderEmail": "info@savvycyberkids.org ",
|
||||
"name": "Savvy Cyber Kids",
|
||||
"endUser": "Donors",
|
||||
"approvedDeliverables": [
|
||||
@ -132,10 +124,8 @@
|
||||
"requestedDeliverables": [
|
||||
"other"
|
||||
],
|
||||
"whatDoesNonprofitDo": "Transcendent Pathways",
|
||||
"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/",
|
||||
"stakeholderName": "Mark Ackerley",
|
||||
"stakeholderEmail": "mackerley.music@gmail.com",
|
||||
"name": "Transcendent Pathways",
|
||||
"endUser": "Medical Facilities, Musicians",
|
||||
"approvedDeliverables": [
|
||||
@ -152,19 +142,82 @@
|
||||
"requestedDeliverables": [
|
||||
"other"
|
||||
],
|
||||
"whatDoesNonprofitDo": "Timeraiser is a volunteer matching fair, a silent art auction, and a night out on the town. The big Timeraiser twist is rather than bid money on artwork, participants bid volunteer hours. ",
|
||||
"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/",
|
||||
"stakeholderName": "Stephanie McAllister",
|
||||
"stakeholderEmail": "stephanie@timeraiser.ca",
|
||||
"name": "Timeraiser",
|
||||
"endUser": "Eventgoers",
|
||||
"endUser": "Working professionals who want to donate their time and expertise",
|
||||
"approvedDeliverables": [
|
||||
"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",
|
||||
"currentStatus": "started",
|
||||
"interestedCampers": [],
|
||||
"confirmedCampers": [],
|
||||
"estimatedHours": 100,
|
||||
"currentStatus": "completed"
|
||||
},
|
||||
{
|
||||
"id": "bd1325d8c464cbafaeb7bdef",
|
||||
"requestedDeliverables": [
|
||||
"website",
|
||||
"inventory",
|
||||
"form"
|
||||
],
|
||||
"whatDoesNonprofitDo": "We focus on raising funds to assist injured homeless animals.",
|
||||
"websiteLink": "http://www.peoplesavinganimals.org/",
|
||||
"name": "People Saving Animals",
|
||||
"endUser": "Animal shelters in Central America and people adopting pets",
|
||||
"approvedDeliverables": [
|
||||
"website",
|
||||
"inventory",
|
||||
"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",
|
||||
"estimatedHours": 300,
|
||||
"currentStatus": "started"
|
||||
},
|
||||
{
|
||||
"id": "bd1325d8c464cbafaeb6bdef",
|
||||
"requestedDeliverables": [
|
||||
"inventory",
|
||||
"form",
|
||||
"other"
|
||||
],
|
||||
"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",
|
||||
"endUser": "Government workers and independent contractors who must comply with regulations.",
|
||||
"approvedDeliverables": [
|
||||
"inventory",
|
||||
"form",
|
||||
"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",
|
||||
"estimatedHours": 200,
|
||||
"currentStatus": "started"
|
||||
},
|
||||
{
|
||||
"id": "bd1325d8c464cbafaeb6bdef",
|
||||
"requestedDeliverables": [
|
||||
"website"
|
||||
],
|
||||
"whatDoesNonprofitDo": "We strengthen the value of songwriting and independent music in Columbus, Ohio.",
|
||||
"websiteLink": "http://columbussongwritersassociation.com",
|
||||
"name": "Columbus Songwriters Association",
|
||||
"endUser": "Songwriters and their audiences in the Columbus, Ohio community.",
|
||||
"approvedDeliverables": [
|
||||
"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",
|
||||
"estimatedHours": 100,
|
||||
"currentStatus": "completed"
|
||||
}
|
||||
]
|
||||
|
@ -1,96 +1,77 @@
|
||||
require('dotenv').load();
|
||||
var Bonfire = require('../models/Bonfire.js'),
|
||||
Courseware = require('../models/Courseware.js'),
|
||||
FieldGuide = require('../models/FieldGuide.js'),
|
||||
Nonprofit = require('../models/Nonprofit.js'),
|
||||
mongoose = require('mongoose'),
|
||||
secrets = require('../config/secrets'),
|
||||
coursewares = require('./coursewares.json'),
|
||||
fieldGuides = require('./field-guides.json'),
|
||||
nonprofits = require('./nonprofits.json'),
|
||||
bonfires = require('./bonfires.json');
|
||||
var Challenge = require('../models/Challenge.js'),
|
||||
FieldGuide = require('../models/FieldGuide.js'),
|
||||
Nonprofit = require('../models/Nonprofit.js'),
|
||||
mongoose = require('mongoose'),
|
||||
secrets = require('../config/secrets'),
|
||||
fieldGuides = require('./field-guides.json'),
|
||||
nonprofits = require('./nonprofits.json'),
|
||||
fs = require('fs');
|
||||
|
||||
mongoose.connect(secrets.db);
|
||||
var challenges = fs.readdirSync(__dirname + '/challenges');
|
||||
|
||||
var counter = 0;
|
||||
var offerings = 4;
|
||||
var offerings = 2 + challenges.length;
|
||||
|
||||
var CompletionMonitor = function() {
|
||||
counter++;
|
||||
console.log('call ' + counter);
|
||||
counter++;
|
||||
console.log('call ' + counter);
|
||||
|
||||
if (counter < offerings) {
|
||||
return;
|
||||
} else {
|
||||
process.exit(0);
|
||||
}
|
||||
if (counter < offerings) {
|
||||
return;
|
||||
} else {
|
||||
process.exit(0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Bonfire.remove({}, function(err, data) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
} else {
|
||||
console.log('Deleted ', data);
|
||||
}
|
||||
Bonfire.create(bonfires, function(err, data) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
} else {
|
||||
console.log('Saved ', data);
|
||||
}
|
||||
Challenge.remove({}, function(err, data) {
|
||||
if (err) {
|
||||
console.err(err);
|
||||
} else {
|
||||
console.log('Deleted ', data);
|
||||
}
|
||||
challenges.forEach(function (file) {
|
||||
Challenge.create(require('./challenges/' + file).challenges, function (err, data) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
} else {
|
||||
console.log('Successfully parsed %s', file);
|
||||
CompletionMonitor();
|
||||
}
|
||||
});
|
||||
console.log('bonfires');
|
||||
});
|
||||
});
|
||||
|
||||
Courseware.remove({}, function(err, data) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
} else {
|
||||
console.log('Deleted ', data);
|
||||
}
|
||||
Courseware.create(coursewares, function(err, data) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
} else {
|
||||
console.log('Saved ', data);
|
||||
}
|
||||
CompletionMonitor();
|
||||
});
|
||||
console.log('coursewares');
|
||||
});
|
||||
|
||||
FieldGuide.remove({}, function(err, data) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
} else {
|
||||
console.log('Deleted ', data);
|
||||
}
|
||||
FieldGuide.create(fieldGuides, function(err, data) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
console.log(err);
|
||||
} else {
|
||||
console.log('Deleted ', data);
|
||||
console.log('Saved ', data);
|
||||
}
|
||||
FieldGuide.create(fieldGuides, function(err, data) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
} else {
|
||||
console.log('Saved ', data);
|
||||
}
|
||||
CompletionMonitor();
|
||||
});
|
||||
console.log('field guides');
|
||||
CompletionMonitor();
|
||||
});
|
||||
console.log('field guides');
|
||||
});
|
||||
|
||||
Nonprofit.remove({}, function(err, data) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
} else {
|
||||
console.log('Deleted ', data);
|
||||
}
|
||||
Nonprofit.create(nonprofits, function(err, data) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
console.log(err);
|
||||
} else {
|
||||
console.log('Deleted ', data);
|
||||
console.log('Saved ', data);
|
||||
}
|
||||
Nonprofit.create(nonprofits, function(err, data) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
} else {
|
||||
console.log('Saved ', data);
|
||||
}
|
||||
CompletionMonitor();
|
||||
});
|
||||
console.log('nonprofits');
|
||||
CompletionMonitor();
|
||||
});
|
||||
console.log('nonprofits');
|
||||
});
|
||||
|
@ -18,8 +18,8 @@ function storyLinkCleanup(cb) {
|
||||
console.log(i++);
|
||||
this.pause();
|
||||
story.storyLink = story.storyLink.
|
||||
replace(/[^a-z0-9\s]/gi, '').
|
||||
replace(/\s+/g, ' ').
|
||||
replace(/[^a-z0-9\s]/gi, '').
|
||||
toLowerCase().
|
||||
trim();
|
||||
story.save(function (err) {
|
||||
|
@ -1,9 +1,9 @@
|
||||
/*eslint-disable block-scoped-var */
|
||||
require('dotenv').load();
|
||||
var mongodb = require('mongodb'),
|
||||
User = require('../models/User.js'),
|
||||
newChallenges = require('./challengeMapping.json'),
|
||||
secrets = require('../config/secrets');
|
||||
mongoose = require('mongoose');
|
||||
var User = require('../models/User.js'),
|
||||
secrets = require('../config/secrets'),
|
||||
mongoose = require('mongoose'),
|
||||
R = require('ramda');
|
||||
|
||||
mongoose.connect(secrets.db);
|
||||
|
||||
@ -57,6 +57,7 @@ function userModelMigration(cb) {
|
||||
|
||||
stream.on('data', function (user) {
|
||||
console.log(i++);
|
||||
/*
|
||||
if (user.challengesHash) {
|
||||
this.pause();
|
||||
user.needsMigration = false;
|
||||
@ -88,6 +89,25 @@ function userModelMigration(cb) {
|
||||
user.progressTimestamps.push(bonfire.completedDate);
|
||||
});
|
||||
}
|
||||
*/
|
||||
user.needsMigration = false;
|
||||
user.completedChallenges = R.filter(function(elem) {
|
||||
return elem; // getting rid of undefined
|
||||
}, R.concat(
|
||||
user.completedCoursewares,
|
||||
user.completedBonfires.map(function(bonfire) {
|
||||
return ({
|
||||
completedDate: bonfire.completedDate,
|
||||
_id: bonfire._id,
|
||||
name: bonfire.name,
|
||||
completedWith: bonfire.completedWith,
|
||||
solution: bonfire.solution,
|
||||
githubLink: '',
|
||||
verified: false,
|
||||
challengeType: 5
|
||||
});
|
||||
})
|
||||
));
|
||||
|
||||
var self = this;
|
||||
user.save(function (err) {
|
||||
|
@ -117,7 +117,7 @@ block content
|
||||
span.ion-close-circled
|
||||
| Your name must be fewer than 15 characters.
|
||||
.form-group
|
||||
label.col-sm-3.col-sm-offset-2.control-label(for='email') Github
|
||||
label.col-sm-3.col-sm-offset-2.control-label(for='email') GitHub
|
||||
.col-sm-4
|
||||
input.form-control(type='url', name='githubProfile', id='githubProfile', autocomplete="off", ng-model='user.profile.githubProfile', placeholder='http://')
|
||||
.col-sm-4.col-sm-offset-5(ng-cloak, ng-show="profileForm.githubProfile.$error.url && !profileForm.githubProfile.$pristine")
|
||||
|
@ -150,7 +150,7 @@ block content
|
||||
td.col-xs-4= challenge.name
|
||||
td.col-xs-2= moment(challenge.completedDate, 'x').format("MMM DD, YYYY")
|
||||
td.col-xs-6
|
||||
a(href=challenge.solution) View my solution
|
||||
a(href=challenge.solution, target='_blank') View my solution
|
||||
|
||||
br
|
||||
- if (bonfires.length > 0)
|
||||
@ -164,7 +164,7 @@ block content
|
||||
for bonfire in bonfires
|
||||
tr
|
||||
td.col-xs-4
|
||||
a(href='/bonfires/' + bonfire.name)= bonfire.name
|
||||
a(href='/challenges/' + bonfire.name, target='_blank')= bonfire.name
|
||||
td.col-xs-2= moment(bonfire.completedDate, 'x').format("MMM DD, YYYY")
|
||||
td.col-xs-6
|
||||
pre.wrappable= bonfire.solution
|
||||
|
@ -1,45 +0,0 @@
|
||||
extends ../layout-wide
|
||||
block content
|
||||
script(src='/js/lib/codemirror/lib/codemirror.js')
|
||||
script(src='/js/lib/codemirror/addon/edit/closebrackets.js')
|
||||
script(src='/js/lib/codemirror/addon/edit/matchbrackets.js')
|
||||
script(src='/js/lib/codemirror/addon/lint/lint.js')
|
||||
script(src='/js/lib/codemirror/addon/lint/javascript-lint.js')
|
||||
script(src='//ajax.aspnetcdn.com/ajax/jshint/r07/jshint.js')
|
||||
script(src='/js/lib/chai/chai.js')
|
||||
link(rel='stylesheet', href='/js/lib/codemirror/lib/codemirror.css')
|
||||
link(rel='stylesheet', href='/js/lib/codemirror/addon/lint/lint.css')
|
||||
link(rel='stylesheet', href='/js/lib/codemirror/theme/monokai.css')
|
||||
link(rel="stylesheet", href="http://fonts.googleapis.com/css?family=Ubuntu+Mono")
|
||||
script(src='/js/lib/codemirror/mode/javascript/javascript.js')
|
||||
script(src='/js/lib/jailed/jailed.js')
|
||||
script(src='/js/lib/bonfire/bonfireInit.js')
|
||||
.row
|
||||
script(type="text/javascript").
|
||||
var tests = !{JSON.stringify(tests)};
|
||||
var challengeSeed = !{JSON.stringify(challengeSeed)};
|
||||
var challengeEntryPoint = !{JSON.stringify(challengeEntryPoint)};
|
||||
var title = !{JSON.stringify(title)};
|
||||
|
||||
#mainEditorPanel.col-sm-12.col-md-7.col-xs-12
|
||||
.panel.panel-primary.panel-bonfire
|
||||
.panel-heading.text-center Playground
|
||||
.panel.panel-body
|
||||
form.code
|
||||
.form-group.codeMirrorView
|
||||
textarea#codeEditor(autofocus=true)
|
||||
|
||||
|
||||
#testCreatePanel.col-sm-12.col-md-5.col-xs-12
|
||||
.panel.panel-primary.panel-bonfire
|
||||
.panel-heading.text-center Output
|
||||
.panel.panel-body
|
||||
#submitButton.btn.btn-primary.btn-big.btn-block Run code (ctrl + enter)
|
||||
br
|
||||
form.code
|
||||
.form-group.codeMirrorView
|
||||
textarea#codeOutput
|
||||
br
|
||||
ul#testSuite.list-group
|
||||
br
|
||||
script(src='/js/lib/bonfire/bonfireFramework_v0.1.2.js')
|
@ -1,45 +0,0 @@
|
||||
extends ../layout
|
||||
block content
|
||||
.row
|
||||
.col-md-offset-2.col-md-8.col-lg-offset-2.col-lg-8.text-center
|
||||
|
||||
h1 JSON generator for bonfire challenges - just fill the form out and get the correct format back
|
||||
.col-xs-12.col-sm-12.col-md-offset-1.col-md-10.col-lg-offset-1-col-lg-10
|
||||
.panel
|
||||
form.form-horizontal(method="POST", action="/bonfire-json-generator", name="bonfireInfo")
|
||||
.form-group
|
||||
label.col-sm-2.control-label(for='name') name:
|
||||
.col-sm-10
|
||||
input#name.form-control(type='text', placeholder='name', name="name")
|
||||
.form-group
|
||||
label.col-sm-2.control-label(for='difficultyField') difficulty:
|
||||
.col-sm-10
|
||||
label.radio-inline 1
|
||||
input#inlineRadio1(type='radio', name='difficulty', value='1')
|
||||
label.radio-inline 2
|
||||
input#inlineRadio2(type='radio', name='difficulty', value='2')
|
||||
label.radio-inline 3
|
||||
input#inlineRadio3(type='radio', name='difficulty', value='3')
|
||||
label.radio-inline 4
|
||||
input#inlineRadio4(type='radio', name='difficulty', value='4')
|
||||
label.radio-inline 5
|
||||
input#inlineRadio5(type='radio', name='difficulty', value='5')
|
||||
.form-group
|
||||
label.col-sm-2.control-label.wrappable(for='description') description:
|
||||
.col-sm-10
|
||||
textarea#description.form-control(name="description", rows=5, placeholder="Each \"paragraph\" needs to be separated by a line break(return key).")
|
||||
.form-group
|
||||
label.col-sm-2.control-label.wrappable(for='challengeSeed') challengeSeed:
|
||||
.col-sm-10
|
||||
textarea#challengeSeed.form-control(name="challengeSeed", rows=5)
|
||||
.form-group
|
||||
label.col-sm-2.control-label.wrappable(for='challengeEntryPoint') challenge entrypoint:
|
||||
.col-sm-10
|
||||
textarea#name.form-control(name="challengeEntryPoint", rows=1, type='text', placeholder="palindrome(\"eye\");")
|
||||
.form-group
|
||||
label.col-sm-2.control-label.wrappable(for='tests') tests:
|
||||
.col-sm-10
|
||||
textarea#tests.form-control(name="tests", rows=5, placeholder="Separate tests by a newline.")
|
||||
.form-group
|
||||
.col-sm-offset-2.col-sm-10
|
||||
input.btn.btn-default(type='submit', value="submit")
|
@ -1,44 +0,0 @@
|
||||
extends ../layout
|
||||
block content
|
||||
.row
|
||||
.col-md-offset-2.col-md-8.col-lg-offset-2.col-lg-8.text-center
|
||||
h1 Welcome to the challenge generator. Test your ideas out and see them live in bonfire!
|
||||
.col-xs-12.col-sm-12.col-md-offset-1.col-md-10.col-lg-offset-1-col-lg-10
|
||||
.panel
|
||||
form.form-horizontal(method="POST", action="/bonfire-challenge-generator", name="bonfireInfo")
|
||||
.form-group
|
||||
label.col-sm-2.control-label(for='name') name:
|
||||
.col-sm-10
|
||||
input#name.form-control(type='text', placeholder='name', name="name")
|
||||
.form-group
|
||||
label.col-sm-2.control-label(for='difficultyField') difficulty:
|
||||
.col-sm-10
|
||||
label.radio-inline 1
|
||||
input#inlineRadio1(type='radio', name='difficulty', value='1')
|
||||
label.radio-inline 2
|
||||
input#inlineRadio2(type='radio', name='difficulty', value='2')
|
||||
label.radio-inline 3
|
||||
input#inlineRadio3(type='radio', name='difficulty', value='3')
|
||||
label.radio-inline 4
|
||||
input#inlineRadio4(type='radio', name='difficulty', value='4')
|
||||
label.radio-inline 5
|
||||
input#inlineRadio5(type='radio', name='difficulty', value='5')
|
||||
.form-group
|
||||
label.col-sm-2.control-label.wrappable(for='description') description:
|
||||
.col-sm-10
|
||||
textarea#description.form-control(name="description", rows=5, placeholder="Each \"paragraph\" needs to be separated by a line break(return key).")
|
||||
.form-group
|
||||
label.col-sm-2.control-label.wrappable(for='challengeSeed') challengeSeed:
|
||||
.col-sm-10
|
||||
textarea#challengeSeed.form-control(name="challengeSeed", rows=5)
|
||||
.form-group
|
||||
label.col-sm-2.control-label.wrappable(for='challengeEntryPoint') challenge entrypoint:
|
||||
.col-sm-10
|
||||
textarea#name.form-control(name="challengeEntryPoint", rows=1, type='text', placeholder="palindrome(\"eye\");")
|
||||
.form-group
|
||||
label.col-sm-2.control-label.wrappable(for='tests') tests:
|
||||
.col-sm-10
|
||||
textarea#tests.form-control(name="tests", rows=5, placeholder="Separate tests by a newline.")
|
||||
.form-group
|
||||
.col-sm-offset-2.col-sm-10
|
||||
input.btn.btn-default(type='submit', value="submit")
|
@ -1,5 +1,11 @@
|
||||
extends ../layout
|
||||
block content
|
||||
script.
|
||||
var bonfireList = !{JSON.stringify(bonfires)};
|
||||
var waypointList = !{JSON.stringify(waypoints)};
|
||||
var ziplineList = !{JSON.stringify(ziplines)};
|
||||
var basejumpList = !{JSON.stringify(basejumps)};
|
||||
var completedChallenges = !{JSON.stringify(completedChallengeList)};
|
||||
.panel.panel-info
|
||||
.panel-heading.text-center
|
||||
h1 Challenge Map
|
||||
@ -8,7 +14,7 @@ block content
|
||||
img.img-responsive.img-center.border-radius-5(src='https://s3.amazonaws.com/freecodecamp/wide-social-banner-dino.png')
|
||||
else
|
||||
img.img-responsive.img-center.border-radius-5(src='https://s3.amazonaws.com/freecodecamp/wide-social-banner.png')
|
||||
.col-xs-12.col-md-8.col-md-offset-2
|
||||
.col-xs-12.col-md-10.col-md-offset-1
|
||||
h2.text-center
|
||||
span.text-primary #{camperCount}  
|
||||
| campers have joined our community
|
||||
@ -16,99 +22,40 @@ block content
|
||||
| since we launched  
|
||||
span.text-primary #{daysRunning}  
|
||||
| days ago.
|
||||
h2
|
||||
span.fa.fa-flag
|
||||
| Waypoints (200 hours of lessons)
|
||||
.spacer
|
||||
for challengeBlock in challengeList
|
||||
.row
|
||||
.col-xs-12.col-sm-8.col-sm-offset-2
|
||||
h3 #{challengeBlock.name}
|
||||
.row
|
||||
.col-xs-12
|
||||
ol
|
||||
for challenge in challengeBlock.challenges
|
||||
if completedChallengeList.indexOf(challenge._id) > -1
|
||||
.row
|
||||
.hidden-xs.col-sm-3.col-md-2.text-primary.ion-checkmark-circled.padded-ionic-icon.text-center.large-p.negative-10
|
||||
.col-xs-12.col-sm-9.col-md-10
|
||||
li.faded.large-p.negative-10
|
||||
a(href="/challenges/#{challenge.name}")= challenge.name
|
||||
|
||||
.col-xs-12.no-right-padding
|
||||
h3.negative-15
|
||||
ol
|
||||
for waypoint in waypoints
|
||||
if completedCoursewareList.indexOf(waypoint._id) > -1
|
||||
.row
|
||||
.hidden-xs.col-sm-3.col-md-2.text-primary.ion-checkmark-circled.padded-ionic-icon.text-center
|
||||
.col-xs-12.col-sm-9.col-md-10
|
||||
li.faded
|
||||
a(href="/challenges/#{waypoint.name}")= waypoint.name
|
||||
|
||||
else
|
||||
.row
|
||||
.hidden-xs.col-sm-3.col-md-2
|
||||
span
|
||||
.col-xs-12.col-sm-9.col-md-10
|
||||
li
|
||||
a(href="/challenges/#{waypoint.name}")= waypoint.name
|
||||
h2
|
||||
span.ion-bonfire
|
||||
| Bonfires (200 hours of JavaScript algorithm practice)
|
||||
.col-xs-12
|
||||
h3.negative-15
|
||||
ol
|
||||
for bonfire in bonfires
|
||||
if completedBonfireList.indexOf(bonfire._id) > -1
|
||||
.row
|
||||
.hidden-xs.col-sm-3.col-md-2.text-primary.ion-checkmark-circled.padded-ionic-icon.text-center
|
||||
.col-xs-12.col-sm-9.col-md-10
|
||||
li.faded
|
||||
a(href="/bonfires/#{bonfire.name}")= bonfire.name
|
||||
else
|
||||
.row
|
||||
.hidden-xs.col-sm-3.col-md-2
|
||||
span
|
||||
.col-xs-12.col-sm-9.col-md-10
|
||||
li
|
||||
a(href="/bonfires/#{bonfire.name}")= bonfire.name
|
||||
h2
|
||||
span.fa.fa-angle-double-right
|
||||
| Ziplines (200 hours of front end development)
|
||||
.col-xs-12
|
||||
h3.negative-15
|
||||
ol
|
||||
for zipline in ziplines
|
||||
if completedCoursewareList.indexOf(zipline._id) > -1
|
||||
.row
|
||||
.hidden-xs.col-sm-3.col-md-2.text-primary.ion-checkmark-circled.padded-ionic-icon.text-center
|
||||
.col-xs-12.col-sm-9.col-md-10
|
||||
li.faded
|
||||
a(href="/challenges/#{zipline.name}")= zipline.name
|
||||
else
|
||||
.row
|
||||
.hidden-xs.col-sm-3.col-md-2
|
||||
span
|
||||
.col-xs-12.col-sm-9.col-md-10
|
||||
li
|
||||
a(href="/challenges/#{zipline.name}")= zipline.name
|
||||
h2
|
||||
span.fa.fa-level-down
|
||||
| Basejumps (200 hours of full stack development)
|
||||
.col-xs-12
|
||||
h3.negative-15
|
||||
ol
|
||||
for basejump in basejumps
|
||||
if completedCoursewareList.indexOf(basejump._id) > -1
|
||||
.row
|
||||
.hidden-xs.col-sm-3.col-md-2.text-primary.ion-checkmark-circled.padded-ionic-icon.text-center
|
||||
.col-xs-12.col-sm-9.col-md-10
|
||||
li.faded
|
||||
a(href="/challenges/#{basejump.name}")= basejump.name
|
||||
else
|
||||
.row
|
||||
.hidden-xs.col-sm-3.col-md-2
|
||||
span
|
||||
.col-xs-12.col-sm-9.col-md-10
|
||||
li
|
||||
a(href="/challenges/#{basejump.name}")= basejump.name
|
||||
h2
|
||||
span.ion-ios-heart Nonprofit Projects (800 hours of real-world experience)*
|
||||
h3.negative-15
|
||||
ul
|
||||
.row
|
||||
.hidden-xs.col-sm-3.col-md-2
|
||||
span
|
||||
.col-xs-12.col-sm-9.col-md-10
|
||||
li
|
||||
a(href="/nonprofits/directory") Browse our nonprofit projects
|
||||
p * Complete all Waypoints, Bonfires, Ziplines and Basejumps to be assigned your first nonprofit project
|
||||
else
|
||||
.row
|
||||
.hidden-xs.col-sm-3.col-md-2
|
||||
span.negative-10
|
||||
.col-xs-12.col-sm-9.col-md-10
|
||||
li.large-p.negative-10
|
||||
a(href="/challenges/#{challenge.name}")= challenge.name
|
||||
h3.text-center Nonprofit Projects (800 hours of real-world experience)*
|
||||
.row
|
||||
.col-xs-12
|
||||
ul
|
||||
.row
|
||||
.hidden-xs.col-sm-3.col-md-2
|
||||
span.negative-10
|
||||
.col-xs-12.col-sm-9.col-md-10
|
||||
li.large-p.negative-10
|
||||
a(href="/nonprofits/directory") Browse our nonprofit projects
|
||||
p * Complete all Waypoints, Bonfires, Ziplines and Basejumps to be assigned your first nonprofit project
|
||||
|
||||
#announcementModal.modal(tabindex='-1')
|
||||
.modal-dialog.animated.fadeInUp.fast-animation
|
||||
|
9
views/coursewares/getstuff.jade
Normal file
9
views/coursewares/getstuff.jade
Normal file
@ -0,0 +1,9 @@
|
||||
//
|
||||
Created by nathanleniz on 5/19/15.
|
||||
|
||||
extends ../layout-wide
|
||||
block content
|
||||
script.
|
||||
var stuff = !{JSON.stringify(stuff)};
|
||||
var challengeMapWithIds = !{JSON.stringify(stuffWithIds)};
|
||||
|
@ -6,7 +6,7 @@ block content
|
||||
script(type='text/javascript', src='/js/lib/codemirror/addon/edit/matchbrackets.js')
|
||||
script(type='text/javascript', src='/js/lib/codemirror/addon/lint/lint.js')
|
||||
script(type='text/javascript', src='/js/lib/codemirror/addon/lint/javascript-lint.js')
|
||||
script(type='text/javascript', src='//ajax.aspnetcdn.com/ajax/jshint/r07/jshint.js')
|
||||
script(type='text/javascript', src='/bower_components/jshint/dist/jshint.js')
|
||||
script(type='text/javascript', src='/js/lib/chai/chai.js')
|
||||
link(rel='stylesheet', href='/js/lib/codemirror/lib/codemirror.css')
|
||||
link(rel='stylesheet', href='/js/lib/codemirror/addon/lint/lint.css')
|
||||
@ -14,9 +14,9 @@ block content
|
||||
link(rel="stylesheet", href="http://fonts.googleapis.com/css?family=Ubuntu+Mono")
|
||||
script(type='text/javascript', src='/js/lib/codemirror/mode/javascript/javascript.js')
|
||||
script(type='text/javascript', src='/js/lib/jailed/jailed.js')
|
||||
script(type='text/javascript', src='/js/lib/bonfire/bonfireInit.js')
|
||||
script(type='text/javascript', src='/js/lib/coursewares/sandbox.js')
|
||||
|
||||
.row
|
||||
.row(ng-controller="pairedWithController")
|
||||
.col-xs-12.col-sm-12.col-md-4.bonfire-top
|
||||
#testCreatePanel
|
||||
h1#bonfire-name.text-center= name
|
||||
@ -58,9 +58,6 @@ block content
|
||||
i.ion-ios-flame
|
||||
i.ion-ios-flame
|
||||
i.ion-ios-flame
|
||||
p.text-center Tips: Use 
|
||||
a(href='/field-guide/how-do-i-get-help-when-I-get-stuck') RSAP
|
||||
| . Try to pair program. Write your own code.
|
||||
.well
|
||||
.row
|
||||
.col-xs-12
|
||||
@ -73,7 +70,7 @@ block content
|
||||
#long-instructions.row.hide
|
||||
.col-xs-12
|
||||
for sentence in details
|
||||
p!= sentence
|
||||
p.wrappable!= sentence
|
||||
#MDN-links
|
||||
p Here are some helpful links:
|
||||
for link, index in MDNlinks
|
||||
@ -82,8 +79,31 @@ block content
|
||||
span.ion-arrow-up-b
|
||||
| Less information
|
||||
|
||||
if (user)
|
||||
form.form-horizontal(novalidate='novalidate', name='completedWithForm')
|
||||
.form-group.text-center
|
||||
.col-xs-12
|
||||
// extra field to distract password tools like lastpass from injecting css into our username field
|
||||
input.form-control(ng-show="false")
|
||||
input.form-control#completed-with(name="existingUser", placeholder="Your pair's username if pairing", existing-username='', ng-model="existingUser")
|
||||
.col-xs-12(ng-cloak, ng-show="completedWithForm.$error.exists && !completedWithForm.existingUser.$pristine && existingUser.length > 0")
|
||||
alert(type='danger')
|
||||
span.ion-close-circled
|
||||
| Username not found
|
||||
#submitButton.btn.btn-primary.btn-big.btn-block Run code (ctrl + enter)
|
||||
br
|
||||
if (user)
|
||||
.button-spacer
|
||||
.btn-group.input-group.btn-group-justified
|
||||
label.btn.btn-success#i-want-help
|
||||
i.fa.fa-medkit
|
||||
| Help
|
||||
label.btn.btn-success#i-want-to-pair
|
||||
i.fa.fa-user-plus
|
||||
| Pair
|
||||
label.btn.btn-success#report-issue
|
||||
i.fa.fa-bug
|
||||
| Bug
|
||||
.button-spacer
|
||||
form.code
|
||||
.form-group.codeMirrorView
|
||||
textarea#codeOutput(style='display: none;')
|
||||
@ -93,9 +113,10 @@ block content
|
||||
script(type="text/javascript").
|
||||
var tests = !{JSON.stringify(tests)};
|
||||
var challengeSeed = !{JSON.stringify(challengeSeed)};
|
||||
var passedBonfireHash = !{JSON.stringify(bonfireHash)};
|
||||
var challengeName = !{JSON.stringify(name)};
|
||||
var challenge_Id = !{JSON.stringify(challengeId)};
|
||||
var challenge_Name = !{JSON.stringify(name)};
|
||||
var started = Math.floor(Date.now());
|
||||
var challengeType = !{JSON.stringify(challengeType)};
|
||||
var _ = R;
|
||||
var dashed = !{JSON.stringify(dashedName)};
|
||||
|
||||
@ -104,36 +125,24 @@ block content
|
||||
form.code
|
||||
.form-group.codeMirrorView
|
||||
textarea#codeEditor(autofocus=true, style='display: none;')
|
||||
script(src='/js/lib/bonfire/bonfireFramework_v0.1.3.js')
|
||||
script(src='/js/lib/coursewares/coursewaresJSFramework_0.0.2.js')
|
||||
|
||||
|
||||
|
||||
#complete-bonfire-dialog.modal(tabindex='-1')
|
||||
#complete-courseware-dialog.modal(tabindex='-1')
|
||||
.modal-dialog.animated.zoomIn.fast-animation
|
||||
.modal-content
|
||||
.modal-header.challenge-list-header= compliment
|
||||
a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') ×
|
||||
.modal-body(ng-controller="pairedWithController")
|
||||
.modal-body
|
||||
.text-center
|
||||
.animated.zoomInDown.delay-half
|
||||
span.completion-icon.ion-checkmark-circled.text-primary
|
||||
- if (user)
|
||||
form.form-horizontal(novalidate='novalidate', name='completedWithForm')
|
||||
.form-group.text-center
|
||||
.col-xs-10.col-xs-offset-1.col-sm-8.col-sm-offset-2.col-md-8.col-md-offset-2.animated.fadeIn
|
||||
// extra field to distract password tools like lastpass from injecting css into our username field
|
||||
input.form-control(ng-show="false")
|
||||
input.form-control#completed-with(name="existingUser", placeholder="If you paired, enter your pair's username here", existing-username='', ng-model="existingUser", autofocus)
|
||||
.col-xs-10.col-xs-offset-1.col-sm-8.col-sm-offset-2.col-md-8.col-md-offset-2(ng-cloak, ng-show="completedWithForm.$error.exists && !completedWithForm.existingUser.$pristine && existingUser.length > 0")
|
||||
alert(type='danger')
|
||||
span.ion-close-circled
|
||||
| Username not found
|
||||
|
||||
a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block.next-bonfire-button(name='_csrf', value=_csrf, ng-disabled='completedWithForm.$invalid && existingUser.length > 0') Go to my next bonfire (ctrl + enter)
|
||||
a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block#next-courseware-button(name='_csrf', value=_csrf) Go to my next challenge (ctrl + enter)
|
||||
|
||||
|
||||
- if (user.progressTimestamps.length > 2)
|
||||
a.animated.fadeIn.btn.btn-lg.btn-block.btn-twitter(target="_blank", href="https://twitter.com/intent/tweet?text=I%20just%20#{verb}%20%40FreeCodeCamp%20Bonfire:%20#{name}&url=http%3A%2F%2Ffreecodecamp.com/bonfires/#{dashedName}&hashtags=LearnToCode, JavaScript")
|
||||
a.animated.fadeIn.btn.btn-lg.btn-block.btn-twitter(target="_blank", href="https://twitter.com/intent/tweet?text=I%20just%20#{verb}%20%40FreeCodeCamp%20Bonfire:%20#{name}&url=http%3A%2F%2Ffreecodecamp.com/challenges/#{dashedName}&hashtags=LearnToCode, JavaScript")
|
||||
i.fa.fa-twitter  
|
||||
= phrase
|
||||
- else
|
@ -5,7 +5,7 @@ block content
|
||||
script(src='/js/lib/codemirror/addon/edit/matchbrackets.js')
|
||||
script(src='/js/lib/codemirror/addon/lint/lint.js')
|
||||
script(src='/js/lib/codemirror/addon/lint/javascript-lint.js')
|
||||
script(src='//ajax.aspnetcdn.com/ajax/jshint/r07/jshint.js')
|
||||
script(src='/bower_components/jshint/dist/jshint.js')
|
||||
script(src='/js/lib/chai/chai.js')
|
||||
script(src='/js/lib/chai/chai-jquery.js')
|
||||
link(rel='stylesheet', href='/js/lib/codemirror/lib/codemirror.css')
|
||||
@ -14,7 +14,7 @@ block content
|
||||
link(rel="stylesheet", href="http://fonts.googleapis.com/css?family=Ubuntu+Mono")
|
||||
script(src='/js/lib/codemirror/mode/javascript/javascript.js')
|
||||
script(src='/js/lib/jailed/jailed.js')
|
||||
script(src='/js/lib/bonfire/bonfireInit.js')
|
||||
script(src='/js/lib/bonfire/sandbox.js')
|
||||
script(src='/js/lib/codemirror/mode/xml/xml.js')
|
||||
script(src='/js/lib/codemirror/mode/css/css.js')
|
||||
script(src='/js/lib/codemirror/mode/htmlmixed/htmlmixed.js')
|
||||
@ -43,6 +43,15 @@ block content
|
||||
| Go to my next challenge
|
||||
br
|
||||
| (ctrl + enter)
|
||||
.button-spacer
|
||||
.btn-group.input-group.btn-group-justified
|
||||
label.btn.btn-success#i-want-help
|
||||
i.fa.fa-medkit
|
||||
| Help
|
||||
label.btn.btn-success#report-issue
|
||||
i.fa.fa-bug
|
||||
| Bug
|
||||
.button-spacer
|
||||
script.
|
||||
var userLoggedIn = true;
|
||||
- else
|
||||
@ -56,9 +65,8 @@ block content
|
||||
$('#next-courseware-button').attr('disabled', 'disabled');
|
||||
var tests = !{JSON.stringify(tests)};
|
||||
var challengeSeed = !{JSON.stringify(challengeSeed)};
|
||||
var passedCoursewareHash = !{JSON.stringify(coursewareHash)};
|
||||
var challengeName = !{JSON.stringify(name)};
|
||||
var passedCoursewareName = challengeName;
|
||||
var challenge_Id = !{JSON.stringify(challengeId)};
|
||||
var challenge_Name = !{JSON.stringify(name)};
|
||||
var prodOrDev = !{JSON.stringify(environment)};
|
||||
var challengeType = !{JSON.stringify(challengeType)};
|
||||
var started = Math.floor(Date.now());
|
||||
|
@ -5,7 +5,7 @@ block content
|
||||
script(src='/js/lib/codemirror/addon/edit/matchbrackets.js')
|
||||
script(src='/js/lib/codemirror/addon/lint/lint.js')
|
||||
script(src='/js/lib/codemirror/addon/lint/javascript-lint.js')
|
||||
script(src='//ajax.aspnetcdn.com/ajax/jshint/r07/jshint.js')
|
||||
script(src='/bower_components/jshint/dist/jshint.js')
|
||||
script(src='/js/lib/chai/chai.js')
|
||||
link(rel='stylesheet', href='/js/lib/codemirror/lib/codemirror.css')
|
||||
link(rel='stylesheet', href='/js/lib/codemirror/addon/lint/lint.css')
|
||||
@ -13,7 +13,7 @@ block content
|
||||
link(rel="stylesheet", href="http://fonts.googleapis.com/css?family=Ubuntu+Mono")
|
||||
script(src='/js/lib/codemirror/mode/javascript/javascript.js')
|
||||
script(src='/js/lib/jailed/jailed.js')
|
||||
script(src='/js/lib/bonfire/bonfireInit.js')
|
||||
script(src='/js/lib/coursewares/sandbox.js')
|
||||
.row
|
||||
.col-xs-12.col-sm-12.col-md-4.bonfire-top
|
||||
#testCreatePanel
|
||||
@ -30,12 +30,24 @@ block content
|
||||
#long-instructions.row.hide
|
||||
.col-xs-12
|
||||
for sentence in details
|
||||
p!= sentence
|
||||
p.wrappable!= sentence
|
||||
#less-info.btn.btn-primary.btn-block.btn-primary-ghost
|
||||
span.ion-arrow-up-b
|
||||
| Less information
|
||||
#submitButton.btn.btn-primary.btn-big.btn-block Run code (ctrl + enter)
|
||||
br
|
||||
.button-spacer
|
||||
if (user)
|
||||
.btn-group.input-group.btn-group-justified
|
||||
label.btn.btn-success#i-want-help
|
||||
i.fa.fa-medkit
|
||||
| Help
|
||||
label.btn.btn-success#i-want-to-pair
|
||||
i.fa.fa-user-plus
|
||||
| Pair
|
||||
label.btn.btn-success#report-issue
|
||||
i.fa.fa-bug
|
||||
| Bug
|
||||
.spacer
|
||||
form.code
|
||||
.form-group.codeMirrorView
|
||||
textarea#codeOutput(style='display: none;')
|
||||
@ -45,10 +57,9 @@ block content
|
||||
script(type="text/javascript").
|
||||
var tests = !{JSON.stringify(tests)};
|
||||
var challengeSeed = !{JSON.stringify(challengeSeed)};
|
||||
var passedCoursewareHash = !{JSON.stringify(coursewareHash)};
|
||||
var challengeName = !{JSON.stringify(name)};
|
||||
var challenge_Id = !{JSON.stringify(challengeId)};
|
||||
var challenge_Name = !{JSON.stringify(name)};
|
||||
var challengeType = !{JSON.stringify(challengeType)};
|
||||
var passedCoursewareName = challengeName;
|
||||
var started = Math.floor(Date.now());
|
||||
|
||||
.col-xs-12.col-sm-12.col-md-8
|
||||
@ -56,7 +67,7 @@ block content
|
||||
form.code
|
||||
.form-group.codeMirrorView
|
||||
textarea#codeEditor(autofocus=true, style='display: none;')
|
||||
script(src='/js/lib/coursewares/coursewaresJSFramework_0.0.1.js')
|
||||
script(src='/js/lib/coursewares/coursewaresJSFramework_0.0.2.js')
|
||||
#complete-courseware-dialog.modal(tabindex='-1')
|
||||
.modal-dialog.animated.zoomIn.fast-animation
|
||||
.modal-content
|
||||
|
@ -11,8 +11,7 @@ block content
|
||||
.col-xs-3.col-sm-1.col-md-2.padded-ionic-icon.text-center
|
||||
input(type='checkbox' class='challenge-list-checkbox')
|
||||
.col-xs-9.col-sm-11.col-md-10
|
||||
li
|
||||
.step-text!= step
|
||||
li.step-text.wrappable!= step
|
||||
.col-xs-12.col-sm-12.col-md-8
|
||||
.embed-responsive.embed-responsive-16by9
|
||||
iframe.embed-responsive-item(src='//player.vimeo.com/video/#{video}')
|
||||
@ -21,19 +20,23 @@ block content
|
||||
a.btn.btn-primary.btn-big.btn-block#completed-courseware I've completed this challenge (ctrl + enter)
|
||||
script.
|
||||
var userLoggedIn = true;
|
||||
.button-spacer
|
||||
.btn-group.input-group.btn-group-justified
|
||||
.btn.btn-success.btn-big#i-want-help-editorless
|
||||
i.fa.fa-medkit
|
||||
| Get help
|
||||
.btn.btn-success.btn-big#report-issue
|
||||
i.fa.fa-bug
|
||||
| Report a bug
|
||||
.button-spacer
|
||||
- else
|
||||
a.btn.btn-big.signup-btn.btn-block(href='/login') Sign in so you can save your progress
|
||||
script.
|
||||
var userLoggedIn = false;
|
||||
br
|
||||
.button-spacer
|
||||
|
||||
script(type="text/javascript").
|
||||
var tests = !{JSON.stringify(tests)};
|
||||
var passedCoursewareHash = !{JSON.stringify(coursewareHash)};
|
||||
var challengeName = !{JSON.stringify(name)};
|
||||
var passedCoursewareName = challengeName;
|
||||
var started = Math.floor(Date.now());
|
||||
var challengeType = !{JSON.stringify(challengeType)};
|
||||
|
||||
var controlEnterHandler = function(e) {
|
||||
$('body').unbind('keypress');
|
||||
if (e.ctrlKey && e.keyCode == 13) {
|
||||
@ -76,3 +79,7 @@ block content
|
||||
h1 #{name}
|
||||
script.
|
||||
$('body').bind('keypress', controlEnterHandler);
|
||||
script.
|
||||
var challenge_Id = !{JSON.stringify(challengeId)};
|
||||
var challenge_Name = !{JSON.stringify(name)};
|
||||
var challengeType = !{JSON.stringify(challengeType)};
|
||||
|
@ -11,14 +11,25 @@ block content
|
||||
.col-xs-3.col-sm-1.col-md-2.padded-ionic-icon.text-center
|
||||
input(type='checkbox' class='challenge-list-checkbox')
|
||||
.col-xs-9.col-sm-11.col-md-10
|
||||
li
|
||||
.step-text!= step
|
||||
li.step-text.wrappable!= step
|
||||
.col-xs-12.col-sm-12.col-md-8
|
||||
.embed-responsive.embed-responsive-16by9
|
||||
iframe.embed-responsive-item(src='//player.vimeo.com/video/#{video}')
|
||||
br
|
||||
- if (user)
|
||||
a.btn.btn-primary.btn-lg.btn-block#completed-zipline-or-basejump I've completed this challenge (ctrl + enter)
|
||||
a.btn.btn-primary.btn-big.btn-block#completed-zipline-or-basejump I've completed this challenge (ctrl + enter)
|
||||
.button-spacer
|
||||
.btn-group.input-group.btn-group-justified
|
||||
.btn.btn-success.btn-big#i-want-help-editorless
|
||||
i.fa.fa-medkit
|
||||
| Help
|
||||
.btn.btn-success.btn-big#i-want-to-pair
|
||||
i.fa.fa-user-plus
|
||||
| Pair
|
||||
.btn.btn-success.btn-big#report-issue
|
||||
i.fa.fa-bug
|
||||
| Bug
|
||||
.button-spacer
|
||||
script.
|
||||
var userLoggedIn = true;
|
||||
- else
|
||||
@ -27,9 +38,8 @@ block content
|
||||
var userLoggedIn = false;
|
||||
br
|
||||
script(type="text/javascript").
|
||||
var passedCoursewareHash = !{JSON.stringify(coursewareHash)};
|
||||
var challengeName = !{JSON.stringify(name)};
|
||||
var passedCoursewareName = challengeName;
|
||||
var challenge_Id = !{JSON.stringify(challengeId)};
|
||||
var challenge_Name = !{JSON.stringify(name)};
|
||||
var started = Math.floor(Date.now());
|
||||
var challengeType = !{JSON.stringify(challengeType)};
|
||||
var controlEnterHandler = function (e) {
|
||||
|
24
views/field-guide/all-articles.jade
Normal file
24
views/field-guide/all-articles.jade
Normal file
@ -0,0 +1,24 @@
|
||||
extends ../layout
|
||||
block content
|
||||
.col-xs-12.col-sm-12.col-md-12
|
||||
.panel.panel-info
|
||||
.panel-heading.text-center Read our Field Guide in any order
|
||||
.panel-body
|
||||
.col-xs-12.col-md-10.col-md-offset-1
|
||||
.col-xs-12.no-right-padding
|
||||
h3
|
||||
ol
|
||||
each fieldGuide in allFieldGuideNamesAndIds
|
||||
if completedFieldGuides.indexOf(fieldGuide.id) > -1
|
||||
.row
|
||||
.hidden-xs.col-sm-3.col-md-2.text-primary.ion-checkmark-circled.padded-ionic-icon.text-center
|
||||
.col-xs-12.col-sm-9.col-md-10
|
||||
li.faded
|
||||
a(href="/field-guide/#{fieldGuide.name}")= fieldGuide.name
|
||||
else
|
||||
.row
|
||||
.hidden-xs.col-sm-3.col-md-2
|
||||
span
|
||||
.col-xs-12.col-sm-9.col-md-10
|
||||
li
|
||||
a(href="/field-guide/#{fieldGuide.name}")= fieldGuide.name
|
@ -7,26 +7,17 @@ block content
|
||||
h1= title
|
||||
.panel-body
|
||||
div!= description
|
||||
.spacer
|
||||
.spacer
|
||||
.spacer
|
||||
.col-xs-12.col-sm-6.col-sm-offset-3
|
||||
.spacer
|
||||
.text-center
|
||||
if user && user.uncompletedFieldGuides.length > 0
|
||||
.next-field-guide-button.btn.btn-primary.btn-big.btn-block Next article (ctrl + enter)
|
||||
.ten-pixel-break
|
||||
#showAllButton.btn.btn-info.btn-big.btn-block Show me all articles
|
||||
a.btn.btn-info.btn-big.btn-block(href='/field-guide/all-articles') Show me all articles
|
||||
if !user
|
||||
.ten-pixel-break
|
||||
a.btn.btn-big.signup-btn.btn-block(href="/login") Start learning to code (it's free)
|
||||
a.btn.btn-big.signup-btn.btn-block(href='/login') Start learning to code (it's free)
|
||||
.spacer
|
||||
#show-all-dialog.modal(tabindex='-1')
|
||||
.modal-dialog.animated.fadeInUp.fast-animation
|
||||
.modal-content
|
||||
.modal-header.all-list-header Field Guide Articles
|
||||
a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') ×
|
||||
.modal-body
|
||||
include ../partials/field-guide
|
||||
#fieldGuideId.hidden= fieldGuideId
|
||||
script.
|
||||
$(document).ready(function() {
|
||||
|
@ -6,14 +6,15 @@ block content
|
||||
.panel.panel-info
|
||||
.panel-heading.text-center Nonprofits We Help
|
||||
.panel-body
|
||||
for nonprofit in nonprofits
|
||||
.spacer
|
||||
.row
|
||||
.col-xs-12.col-sm-3
|
||||
img.img-responsive(src=nonprofit.logoUrl)
|
||||
.col-xs-12.col-sm-9
|
||||
h2.negative-15= nonprofit.name
|
||||
h3.negative-15= nonprofit.whatDoesNonprofitDo
|
||||
a.text-center.btn.btn-primary.btn-lg(href='/nonprofits/' + nonprofit.name.toLowerCase().replace(/\s/g, '-')) Read more
|
||||
.spacer
|
||||
.spacer
|
||||
.col-xs-12.col-sm-12.col-md-10.col-md-offset-1
|
||||
for nonprofit in nonprofits
|
||||
.spacer
|
||||
.row
|
||||
.col-xs-12.col-sm-3
|
||||
img.img-responsive.img-center(src=nonprofit.logoUrl)
|
||||
.col-xs-12.col-sm-9
|
||||
h2.negative-15= nonprofit.name
|
||||
h3.negative-15= nonprofit.whatDoesNonprofitDo
|
||||
a.text-center.btn.btn-primary.btn-lg(href='/nonprofits/' + nonprofit.name.toLowerCase().replace(/\s/g, '-')) Read more
|
||||
.spacer
|
||||
.spacer
|
||||
|
@ -61,21 +61,14 @@ block content
|
||||
.text-center
|
||||
a.btn.btn-primary.btn-big.btn-block.disabled(href='/nonprofits/interested-in-nonprofit/#{dashedName}') I'm interested in building this project *
|
||||
p * Complete all our Bonfires, Ziplines, and Basejumps to unlock this.
|
||||
#showAllButton.btn.btn-info.btn-big.btn-block Show all Nonprofit Projects
|
||||
a.btn.btn-info.btn-big.btn-block(href='/nonprofits/directory') Show all Nonprofit Projects
|
||||
if (buttonActive)
|
||||
.col-xs-12.col-sm-8.col-sm-offset-2
|
||||
.text-center
|
||||
a.btn.btn-primary.btn-big.btn-block(href='/nonprofits/interested-in-nonprofit/#{dashedName}') I'm interested in building this project
|
||||
#showAllButton.btn.btn-info.btn-big.btn-block Show all Nonprofit Projects
|
||||
a.btn.btn-info.btn-big.btn-block(href='/nonprofits/directory') Show all Nonprofit Projects
|
||||
.row
|
||||
.col-xs-12.text-center
|
||||
if !user
|
||||
a.btn.btn-cta.signup-btn.btn-primary(href="/login") Start learning to code (it's free)
|
||||
.spacer
|
||||
#show-all-dialog.modal(tabindex='-1')
|
||||
.modal-dialog.animated.fadeInUp.fast-animation
|
||||
.modal-content
|
||||
.modal-header.all-list-header Nonprofit Projects
|
||||
a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') ×
|
||||
.modal-body
|
||||
include ../partials/nonprofits
|
||||
.spacer
|
||||
|
@ -1,7 +1,7 @@
|
||||
.fcc-footer
|
||||
.col-xs-12.hidden-xs.hidden-sm
|
||||
a.ion-speakerphone(href='http://blog.freecodecamp.com', target='_blank') Blog
|
||||
a.ion-social-github(href="http://github.com/freecodecamp", target='_blank') Github
|
||||
a.ion-social-github(href="http://github.com/freecodecamp", target='_blank') GitHub
|
||||
a.ion-social-twitch-outline(href="/twitch")  Twitch
|
||||
a.ion-social-facebook(href="/field-guide/how-can-i-find-other-free-code-camp-campers-in-my-city") Facebook
|
||||
a.ion-social-twitter(href="http://twitter.com/freecodecamp", target='_blank') Twitter
|
||||
|
@ -15,7 +15,7 @@ nav.navbar.navbar-default.navbar-fixed-top.nav-height
|
||||
|
||||
if user
|
||||
li
|
||||
a(href='/challenges') Next Challenge
|
||||
a(href='/challenges') Learn
|
||||
li
|
||||
a(href='/map') Map
|
||||
if (user && user.sentSlackInvite)
|
||||
@ -27,7 +27,9 @@ nav.navbar.navbar-default.navbar-fixed-top.nav-height
|
||||
li
|
||||
a(href='/news') News
|
||||
li
|
||||
a(href='/field-guide') Field Guide
|
||||
a(href='/field-guide') Guide
|
||||
li.hidden-xs.hidden-sm
|
||||
a(href='/jobs') Jobs
|
||||
if !user
|
||||
li      
|
||||
li
|
||||
|
@ -31,7 +31,7 @@ script(src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.2/moment.min.js")
|
||||
script.
|
||||
window.moment || document.write('<script src="/bower_components/moment/min/moment.min.js"><\/script>');
|
||||
|
||||
// Leave alone below
|
||||
// Leave the below lines alone!
|
||||
script(src="/js/main.js")
|
||||
|
||||
script(src="/bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js")
|
||||
@ -45,6 +45,7 @@ link(rel="stylesheet" type="text/css" href="/bower_components/cal-heatmap/cal-he
|
||||
link(rel='stylesheet', href='/bower_components/font-awesome/css/font-awesome.min.css')
|
||||
|
||||
link(rel='stylesheet', href='/css/main.css')
|
||||
// End **REQUIRED** includes
|
||||
|
||||
include meta
|
||||
title #{title} | Free Code Camp
|
||||
|
28
views/resources/jobs-form.jade
Normal file
28
views/resources/jobs-form.jade
Normal file
@ -0,0 +1,28 @@
|
||||
html.
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<!--Add the title of your typeform below-->
|
||||
<title>nonprofit-projects</title>
|
||||
<!--CSS styles that ensure your typeform takes up all the available screen space (DO NOT EDIT!)-->
|
||||
<style type="text/css">
|
||||
html{
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
iframe{
|
||||
position: absolute;
|
||||
left:0;
|
||||
right:0;
|
||||
bottom:0;
|
||||
top:0;
|
||||
border:0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<iframe id="typeform-full" width="100%" height="100%" frameborder="0" src="https://freecodecamp.typeform.com/to/Wkfsts"></iframe>
|
||||
<script type="text/javascript" src="https://s3-eu-west-1.amazonaws.com/share.typeform.com/embed.js"></script>
|
||||
</body>
|
||||
</html>
|
16
views/resources/jobs.jade
Normal file
16
views/resources/jobs.jade
Normal file
@ -0,0 +1,16 @@
|
||||
extends ../layout-wide
|
||||
block content
|
||||
.row
|
||||
.col-xs-12.col-sm-8.col-sm-offset-2.text-center
|
||||
h2 We want all our campers to get awesome software engineer jobs (
|
||||
a(href='https://www.linkedin.com/groups?viewMembers=&gid=6966827&sik=1432338555021' target='_blank') and many already have
|
||||
| ).
|
||||
h3.hidden-xs.hidden-sm This is a small sampling of the 1,000s of junior software engineer jobs. Learn about the  
|
||||
a(href='http://blog.freecodecamp.com/2014/10/the-real-reason-to-learn-mean-stack.html') the job market in aggregate
|
||||
| .
|
||||
.spacer
|
||||
a.btn.btn-primary.btn-big(href='/jobs-form') My organization is hiring software engineers
|
||||
.spacer
|
||||
.embed-responsive.embed-responsive-4by3.hidden-xs.hidden-sm
|
||||
iframe.embed-responsive-item(src="http://freecodecamp.simply-partner.com" scrolling="no")
|
||||
.spacer
|
@ -39,13 +39,6 @@ urlset(xmlns="http://www.sitemaps.org/schemas/sitemap/0.9")
|
||||
changefreq daily
|
||||
priority= 0.5
|
||||
|
||||
each bonfire in bonfires
|
||||
url
|
||||
loc #{appUrl}/bonfires/#{bonfire.replace(/\s/g, '-')}
|
||||
lastmod= now
|
||||
changefreq weekly
|
||||
priority= 0.5
|
||||
|
||||
each challenge in challenges
|
||||
url
|
||||
loc #{appUrl}/challenges/#{challenge.replace(/\s/g, '-')}
|
||||
|
61
views/resources/test.css
Normal file
61
views/resources/test.css
Normal file
@ -0,0 +1,61 @@
|
||||
.themeCustom a.link:link, .themeCustom a.link:visited, .themeCustom a:link, .themeCustom a:visited {
|
||||
color: #0066cc;
|
||||
}
|
||||
|
||||
.themeCustom .sh_header_search .well {
|
||||
background: #dedede;
|
||||
}
|
||||
|
||||
.themeCustom .sh_header_search .header_wrapper {
|
||||
border-bottom-color: #cccccc;
|
||||
}
|
||||
|
||||
.themeCustom .column-left {
|
||||
background-color: #dedede;
|
||||
}
|
||||
|
||||
.themeCustom .column-left .filters .handle {
|
||||
background-color: #dedede;
|
||||
}
|
||||
|
||||
.themeCustom .column-left .filters .handle:hover {
|
||||
background-color: #cccccc;
|
||||
}
|
||||
|
||||
.themeCustom .column-left .recent_searches, .themeCustom .column-left .search_tools, .themeCustom .column-left .search_links, .themeCustom .column-left .sort_jobs {
|
||||
border-top-color: #dedede;
|
||||
}
|
||||
|
||||
.themeCustom #search_title .text-highlight {
|
||||
color: #444444;
|
||||
}
|
||||
|
||||
.themeCustom .inline-filters {
|
||||
background: #dedede;
|
||||
}
|
||||
|
||||
.themeCustom input[type=radio]:checked + label > span, .themeCustom .sort_jobs input[type=radio]:checked + label > span, .themeCustom .social-network-logins input[type=radio]:checked + label > span {
|
||||
background-color: #444444;
|
||||
border-color: #444444;
|
||||
}
|
||||
|
||||
.themeCustom .filters .filter ul li a, .themeCustom #c_expired a, .themeCustom .result a, .themeCustom .expand_search a, .themeCustom .simplyhired-intl a, .themeCustom .filters .filter ul li a:visited, .themeCustom #c_expired a:visited, .themeCustom .result a:visited, .themeCustom .expand_search a:visited, .themeCustom .simplyhired-intl a:visited, .themeCustom .job h2 {
|
||||
color: #0066cc;}
|
||||
|
||||
.sh.theme-base .btn-sh2 {
|
||||
background-color: #999999;
|
||||
}
|
||||
|
||||
.sh.theme-base .sh_header_search .skin-search-promo .btn-large{
|
||||
background-color: #999999;
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.sh .job .new {
|
||||
background-color: #999999;
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.sh .job .partner-exclusive {
|
||||
background-color: #F15A22;
|
||||
}
|
@ -1,16 +1,17 @@
|
||||
.row
|
||||
.col-xs-12.col-sm-9
|
||||
.input-group
|
||||
input#searchArea.big-text-field.field-responsive.form-control(type='text', placeholder='Search our links')
|
||||
span.input-group-btn
|
||||
button#searchbutton.btn.btn-big.btn-primary.btn-responsive(type='button') Search
|
||||
.visible-xs
|
||||
.button-spacer
|
||||
.col-xs-12.col-sm-3
|
||||
span
|
||||
a.btn.btn-primary.btn-big.btn-block.btn-responsive(href='/stories/submit' class="#{ page === 'hot' ? '' : 'hidden' }") Submit
|
||||
span
|
||||
a.btn.btn-success.btn-big.btn-block.btn-responsive(href='/news/' class="#{ (page !== 'hot') ? '' : 'hidden' }") All
|
||||
.visible-xs
|
||||
.button-spacer
|
||||
.col-xs-12.col-sm-9
|
||||
.input-group
|
||||
input#searchArea.big-text-field.field-responsive.form-control(type='text', placeholder='Search our links')
|
||||
span.input-group-btn
|
||||
button#searchbutton.btn.btn-big.btn-primary.btn-responsive(type='button') Search
|
||||
|
||||
.spacer
|
||||
.row
|
||||
.col-xs-12.col-sm-8.col-sm-offset-2.well
|
||||
|
Reference in New Issue
Block a user