Merge pull request #51 from FreeCodeCamp/bonfire

Bonfire
This commit is contained in:
Quincy Larson
2015-01-27 22:04:17 -08:00
32 changed files with 1387 additions and 597 deletions

119
app.js
View File

@ -208,16 +208,26 @@ app.get('/deploy-a-website', resourcesController.deployAWebsite);
app.get('/gmail-shortcuts', resourcesController.gmailShortcuts);
app.get('/control-shortcuts', resourcesController.controlShortcuts);
app.get('/control-shortcuts', resourcesController.deployAWebsite);
app.get('/stats', resourcesController.stats);
app.get('/stats', function(req, res) {
res.redirect(301, '/learn-to-code');
});
app.get(
'/pair-program-with-team-viewer',
resourcesController.pairProgramWithTeamViewer
);
app.get('/learn-to-code', resourcesController.about);
app.get('/about', resourcesController.about);
app.get('/login', userController.getLogin);
app.post('/login', userController.postLogin);
app.get('/logout', userController.logout);
app.get('/about', function(req, res) {
res.redirect(301, '/learn-to-code');
});
app.get('/signin', userController.getSignin);
app.get('/login', function(req, res) {
res.redirect(301, '/signin');
});
app.post('/signin', userController.postSignin);
app.get('/signout', userController.signout);
app.get('/logout', function(req, res) {
res.redirect(301, '/signout');
});
app.get('/forgot', userController.getForgot);
app.post('/forgot', userController.postForgot);
app.get('/reset/:token', userController.getReset);
@ -225,7 +235,7 @@ app.post('/reset/:token', userController.postReset);
app.get('/email-signup', userController.getEmailSignup);
app.get('/email-signin', userController.getEmailSignin);
app.post('/email-signup', userController.postEmailSignup);
app.post('/email-signin', userController.postLogin);
app.post('/email-signin', userController.postSignin);
app.get('/nonprofits', contactController.getNonprofitsForm);
app.post('/nonprofits', contactController.postNonprofitsForm);
@ -255,14 +265,93 @@ app.get(
);
app.all('/account', passportConf.isAuthenticated);
app.get('/account/api', userController.getAccountAngular);
app.get('/bonfire', bonfireController.index);
/**
* Bonfire related routes
*/
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(
'/bonfire/:bonfireNumber',
bonfireController.returnBonfire
'/bonfires/:bonfireName',
bonfireController.returnIndividualBonfire
);
app.get('/bonfire', function(req, res) {
res.redirect(301, '/playground');
});
app.post('/completed-bonfire/', function (req, res) {
var isCompletedWith = req.body.bonfireInfo.completedWith || undefined;
var isCompletedDate = Math.round(+new Date() / 1000);
var bonfireHash = req.body.bonfireInfo.bonfireHash;
var isSolution = req.body.bonfireInfo.solution;
// TODO
debug(isCompletedWith, 'Is completed with');
if (isCompletedWith) {
var paired = User.find({"profile.username": isCompletedWith}).limit(1);
paired.exec(function(err, pairedWith) {
if (err) {
return err;
} else {
var index = req.user.uncompletedBonfires.indexOf(bonfireHash);
if (index > -1) {
req.user.uncompletedBonfires.splice(index,1)
}
pairedWith = pairedWith.pop();
//debug('This is paired with', Object.keys(pairedWith));
debug('This is paired with\'s uncompleted bonfires array', pairedWith.uncompletedBonfires);
index = pairedWith.uncompletedBonfires.indexOf(bonfireHash);
if (index > -1) {
pairedWith.uncompletedBonfires.splice(index,1)
}
pairedWith.completedBonfires.push({
_id: bonfireHash,
completedWith: req.user._id,
completedDate: isCompletedDate,
solution: isSolution
})
req.user.completedBonfires.push({
_id: bonfireHash,
completedWith: pairedWith._id,
completedDate: isCompletedDate,
solution: isSolution
})
req.user.save();
pairedWith.save();
res.redirect('/bonfires');
}
})
} else {
req.user.completedBonfires.push({
_id: bonfireHash,
completedWith: null,
completedDate: isCompletedDate,
solution: isSolution
})
var index = req.user.uncompletedBonfires.indexOf(bonfireHash);
if (index > -1) {
req.user.uncompletedBonfires.splice(index,1)
}
req.user.save();
res.redirect('/bonfires');
}
});
// Unique Check API route
app.get('/api/checkUniqueUsername/:username', userController.checkUniqueUsername);
app.get('/api/checkExistingUsername/:username', userController.checkExistingUsername);
app.get('/api/checkUniqueEmail/:email', userController.checkUniqueEmail);
app.get('/account', userController.getAccount);
app.post('/account/profile', userController.postUpdateProfile);
@ -280,14 +369,14 @@ app.get('/account/unlink/:provider', userController.getOauthUnlink);
app.post('/completed-challenge', function (req, res) {
req.user.challengesHash[parseInt(req.body.challengeNumber)] =
Math.round(+new Date() / 1000);
var ch = req.user.challengesHash;
var p = 0;
for (var k in ch) {
if (ch[k] > 0) {
p += 1;
var timestamp = req.user.challengesHash;
var points = 0;
for (var key in timestamp) {
if (timestamp[key] > 0) {
points += 1;
}
}
req.user.points = p;
req.user.points = points;
req.user.save();
});

View File

@ -1,78 +1,232 @@
var _ = require('lodash'),
debug = require('debug')('freecc:cntr:bonfires'),
Bonfire = require('./../models/Bonfire');
Bonfire = require('./../models/Bonfire'),
User = require('./../models/User'),
resources = require('./resources');
/**
* Bonfire controller
*/
var highestBonfireNumber = 1;
var highestBonfireNumber = resources.numberOfBonfires();
exports.index = function(req, res) {
res.render('bonfire/bonfire.jade', {
title: 'Learn to code with Bonfire'
});
res.render('bonfire/show.jade', {
completedWith: null,
title: 'Bonfire Playground',
name: 'Bonfire Playground',
difficulty: 0,
brief: 'Feel free to play around!',
details: '',
tests: [],
challengeSeed: '',
challengeEntryPoint: '',
cc: req.user ? req.user.bonfiresHash : undefined,
points: req.user ? req.user.points : undefined,
verb: resources.randomVerb(),
phrase: resources.randomPhrase(),
compliments: resources.randomCompliment(),
bonfires: [],
bonfireHash: 'test'
Bonfire.find({}, null, { sort: { bonfireNumber: 1 } }, function(err, c) {
});
};
exports.returnNextBonfire = function(req, res, next) {
// TODO
//var tempUser = false;
if (!req.user) {
res.redirect('bonfires/meet-bonfire');
//tempUser = true;
//req.user = new User();
}
var currentTime = parseInt(+new Date() / 1000)
if (currentTime - req.user.lastContentSync > 86400) {
req.user.lastContentSync = currentTime;
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, bonfire) {
if (err) {
debug('bonfire err: ', err);
next(err);
}
nameString = bonfire[0].name.toLowerCase().replace(/\s/g, '-');
return res.redirect('/bonfires/' + nameString);
//res.render('bonfire/show', {
// completedWith: null,
// title: bonfire[bonfireNumber].name,
// name: bonfire[bonfireNumber].name,
// difficulty: +bonfire[bonfireNumber].difficulty,
// brief: bonfire[bonfireNumber].description[0],
// details: bonfire[bonfireNumber].description.slice(1),
// tests: bonfire[bonfireNumber].tests,
// challengeSeed: bonfire[bonfireNumber].challengeSeed,
// challengeEntryPoint: bonfire[bonfireNumber].challengeEntryPoint,
// cc: req.user ? req.user.bonfiresHash : undefined,
// points: req.user ? req.user.points : undefined,
// verb: resources.randomVerb(),
// phrase: resources.randomPhrase(),
// compliments: resources.randomCompliment(),
// bonfires: bonfire,
// bonfireHash: bonfire[bonfireNumber]._id
//});
});
};
exports.returnIndividualBonfire = function(req, res, next) {
var bonfireName = req.params.bonfireName;
bonfireName = bonfireName.replace(/\-/g, ' ');
var bonfireNumber = 0;
Bonfire.find({"name" : new RegExp(bonfireName, 'i')}, function(err, bonfire) {
if (err) {
next(err);
}
if (bonfire.length < 1) {
debug('Full Bonfire', bonfire);
req.flash('errors', {
msg: "404: We couldn't find a bonfire with that name. Please double check the name."
});
return res.redirect('/bonfires/meet-bonfire')
} else {
res.render('bonfire/show', {
completedWith: null,
title: bonfire[bonfireNumber].name,
name: bonfire[bonfireNumber].name,
difficulty: +bonfire[bonfireNumber].difficulty,
brief: bonfire[bonfireNumber].description[0],
details: bonfire[bonfireNumber].description.slice(1),
tests: bonfire[bonfireNumber].tests,
challengeSeed: bonfire[bonfireNumber].challengeSeed,
challengeEntryPoint: bonfire[bonfireNumber].challengeEntryPoint,
cc: !!req.user,
points: req.user ? req.user.points : undefined,
verb: resources.randomVerb(),
phrase: resources.randomPhrase(),
compliment: resources.randomCompliment(),
bonfires: bonfire,
bonfireHash: bonfire[bonfireNumber]._id
});
}
});
};
exports.returnBonfire = function(req, res, next) {
var bonfireNumber = parseInt(req.params.bonfireNumber) || 0;
var verbs = [
'ACED',
'NAILED',
'ROCKED',
'SCORCHED',
'DEVASTATED',
'OWNED',
'CRUSHED',
'CONQUERED',
'KILLED',
'SHREDDED',
'ANNIHILATED',
'NUKED'
];
var phrases = [
"Shout it from on top of a mountain",
"Tell everyone and their dogs",
"Show them. Show them all!",
"Inspire your friends",
"Tell the world of your greatness",
"Look accomplished on social media",
"Share news of your grand endeavor",
"Establish your alibi for the past two hours",
"Prove to mom that computers aren't just for games"
];
if (bonfireNumber > highestBonfireNumber) { bonfireNumber = 0; }
Bonfire.find({}, null, { sort: { bonfireNumber: 1 } }, function(err, bonfire) {
debug(bonfire[bonfireNumber].challengeEntryPoint);
if (err) {
debug('bonfire err: ', err);
next(err);
}
res.render('bonfire/show', {
title: bonfire[bonfireNumber].name,
name: bonfire[bonfireNumber].name,
number: bonfire[bonfireNumber].bonfireNumber,
difficulty: bonfire[bonfireNumber].difficulty,
description: bonfire[bonfireNumber].description,
publicTests: bonfire[bonfireNumber].publicTests,
privateTests: bonfire[bonfireNumber].privateTests,
challengeSeed: bonfire[bonfireNumber].challengeSeed,
challengeEntryPoint: bonfire[bonfireNumber].challengeEntryPoint,
challengeEntryPointNegate: bonfire[bonfireNumber].challengeEntryPointNegate,
//cc: req.user ? req.user.bonfiresHash : undefined,
//points: req.user ? req.user.points : undefined,
//verb: verbs[Math.floor(Math.random() * verbs.length)],
//phrase: phrases[Math.floor(Math.random() * phrases.length)],
bonfires: bonfire
});
/**
* Bonfire generator
*/
exports.returnGenerator = function(req, res) {
res.render('bonfire/generator', {
title: null,
name: null,
difficulty: null,
brief: null,
details: null,
tests: null,
challengeSeed: null,
challengeEntryPoint: 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;
}
/**
*
*/
exports.testBonfire = function(req, res) {
var bonfireName = req.body.name,
bonfireTests = req.body.tests,
bonfireDifficulty = req.body.difficulty,
bonfireDescription = req.body.description,
bonfireEntryPoint = req.body.challengeEntryPoint,
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,
difficulty: +bonfireDifficulty,
brief: bonfireDescription[0],
details: bonfireDescription.slice(1),
tests: bonfireTests,
challengeSeed: bonfireChallengeSeed,
challengeEntryPoint: bonfireEntryPoint,
cc: req.user ? req.user.bonfiresHash : undefined,
points: req.user ? req.user.points : 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,
bonfireEntryPoint = req.body.challengeEntryPoint,
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,
challengeEntryPoint: bonfireEntryPoint,
challengeSeed: bonfireChallengeSeed,
tests: bonfireTests
};
res.send(response);
}

View File

@ -4,56 +4,13 @@
*/
var _ = require('lodash'),
debug = require('debug')('freecc:cntr:challenges'),
Challenge = require('./../models/Challenge');
Challenge = require('./../models/Challenge'),
resources = require('./resources');
var highestChallengeNumber = 53;
exports.returnChallenge = function(req, res, next) {
var challengeNumber = parseInt(req.params.challengeNumber) || 0;
var verbs = [
'ACED',
'NAILED',
'ROCKED',
'SCORCHED',
'DEVASTATED',
'OWNED',
'CRUSHED',
'CONQUERED',
'KILLED',
'SHREDDED',
'ANNIHILATED',
'NUKED'
];
var compliments = [
"You've got the power!",
"Nicely done!",
"Rock and roll!",
"High five!",
"Bravo!",
"Encore!",
"Challenge destroyed!",
"Power level 9000!",
"Most efficient!",
"Party on Wayne!",
"You've got the touch!",
"You're on fire!",
"Don't hurt 'em, Hammer!",
"The town is now red",
"To the nines!",
"Nothing but net!",
"Even grumpy cat is impressed"
];
var phrases = [
"Shout it from on top of a mountain",
"Tell everyone and their dogs",
"Show them. Show them all!",
"Inspire your friends",
"Tell the world of your greatness",
"Look accomplished on social media",
"Share news of your grand endeavor",
"Establish your alibi for the past two hours",
"Prove to mom that computers aren't just for games"
];
if (challengeNumber > highestChallengeNumber) { challengeNumber = 0; }
Challenge.find({}, null, { sort: { challengeNumber: 1 } }, function(err, c) {
if (err) {
@ -69,8 +26,9 @@ exports.returnChallenge = function(req, res, next) {
number: challengeNumber,
cc: req.user ? req.user.challengesHash : undefined,
points: req.user ? req.user.points : undefined,
verb: verbs[Math.floor(Math.random() * verbs.length)],
phrase: phrases[Math.floor(Math.random() * phrases.length)],
verb: resources.randomVerb(),
phrase: resources.randomPhrase(),
compliment: resources.randomCompliment(),
challenges: c
});
});

View File

@ -4,8 +4,10 @@ var User = require('../models/User'),
steps = resources.steps,
secrets = require('./../config/secrets'),
Challenge = require('./../models/Challenge'),
bonfires = require('../seed_data/bonfires.json');
Client = require('node-rest-client').Client,
client = new Client();
client = new Client(),
debug = require('debug')('freecc:cntr:bonfires');
/**
* GET /
@ -13,161 +15,195 @@ var User = require('../models/User'),
*/
module.exports = {
privacy: function privacy(req, res) {
res.render('resources/privacy', {
title: 'Privacy'
});
},
stats: function stats(req, res) {
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));
client.get('https://trello.com/1/boards/BA3xVpz9/cards?key=' + secrets.trello.key, function(trello, response) {
var nonprofitProjects = (trello && trello.length) || 15;
User.count({'points': {'$gt': 2}}, function(err, c3) { if (err) { debug('User err: ', err); next(err); }
User.count({'points': {'$gt': 9}}, function(err, c10) { if (err) { debug('User err: ', err); next(err); }
User.count({'points': {'$gt': 29}}, function(err, c30) { if (err) { debug('User err: ', err); next(err); }
User.count({'points': {'$gt': 53}}, function(err, all) { if (err) { debug('User err: ', err); next(err); }
res.render('resources/stats', {
title: 'Free Code Camp Stats:',
daysRunning: daysRunning,
nonprofitProjects: nonprofitProjects,
c3: c3,
c10: c10,
c30: c30,
all: all
});
});
});
privacy: function privacy(req, res) {
res.render('resources/privacy', {
title: 'Privacy'
});
});
});
},
},
deployAWebsite: function deployAWebsite(req, res) {
res.render('resources/deploy-a-website', {
title: 'Deploy a Dynamic Website in 7 Minutes'
});
},
nonprofitProjectInstructions: function nonprofitProjectInstructions(req, res) {
res.render('resources/nonprofit-project-instructions', {
title: 'Nonprofit Project Instructions'
});
},
gmailShortcuts: function gmailShortcuts(req, res) {
res.render('resources/gmail-shortcuts', {
title: 'These Gmail Shortcuts will save you Hours'
});
},
controlShortcuts: function controlShortcuts(req, res) {
res.render('resources/control-shortcuts', {
title: 'These Control Shortcuts will save you Hours'
});
},
chromebook: function chromebook(req, res) {
res.render('resources/chromebook', {
title: 'Win a Chromebook'
});
},
jqueryExercises: function jqueryExercises(req, res) {
res.render('resources/jquery-exercises', {
title: 'jQuery Exercises'
});
},
livePairProgramming: function(req, res) {
res.render('resources/live-pair-programming', {
title: 'Live Pair Programming'
});
},
javaScriptInYourInbox: function(req, res) {
res.render('resources/javascript-in-your-inbox', {
title: 'JavaScript in your Inbox'
});
},
pairProgramWithTeamViewer: function(req, res) {
Challenge.find({}, null, { sort: { challengeNumber: 1 } }, function(err, c) {
if (err) {
debug('Challenge err: ', err);
next(err);
}
res.render('resources/pair-program-with-team-viewer', {
title: 'Challenge: Pair Program with Team Viewer',
name: 'Pair Program with Team Viewer',
video: '',
time: 30,
steps: steps,
cc: req.user ? req.user.challengesHash : undefined,
points: req.user ? req.user.points : undefined,
challenges: c
});
});
},
about: function(req, res) {
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));
client.get('https://trello.com/1/boards/BA3xVpz9/cards?key=' + secrets.trello.key, function(trello, res2) {
client.get('https://www.googleapis.com/blogger/v3/blogs/2421288658305323950/posts?key=' + secrets.blogger.key, function(blogger, res3) {
var nonprofitProjects = trello.length || 15;
var blog = JSON.parse(blogger);
User.count({'points': {'$gt': 2}}, function (err, c3) {
if (err) {
debug('User err: ', err);
next(err);
}
User.count({'points': {'$gt': 9}}, function (err, c10) {
if (err) {
debug('User err: ', err);
next(err);
}
User.count({'points': {'$gt': 29}}, function (err, c30) {
if (err) {
debug('User err: ', err);
next(err);
}
User.count({'points': {'$gt': 53}}, function (err, all) {
if (err) {
debug('User err: ', err);
next(err);
}
res.render('resources/about', {
title: 'About Free Code Camp and Our Team of Volunteers',
daysRunning: daysRunning,
nonprofitProjects: nonprofitProjects,
c3: c3,
c10: c10,
c30: c30,
all: all,
blog1Title: blog["items"][0]["title"],
blog1Link: blog["items"][0]["url"],
blog2Title: blog["items"][1]["title"],
blog2Link: blog["items"][1]["url"],
blog3Title: blog["items"][2]["title"],
blog3Link: blog["items"][2]["url"],
blog4Title: blog["items"][3]["title"],
blog4Link: blog["items"][3]["url"],
blog5Title: blog["items"][4]["title"],
blog5Link: blog["items"][4]["url"]
stats: function stats(req, res) {
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));
client.get('https://trello.com/1/boards/BA3xVpz9/cards?key=' + secrets.trello.key, function(trello, response) {
var nonprofitProjects = (trello && trello.length) || 15;
User.count({'points': {'$gt': 2}}, function(err, c3) { if (err) { debug('User err: ', err); next(err); }
User.count({'points': {'$gt': 9}}, function(err, c10) { if (err) { debug('User err: ', err); next(err); }
User.count({'points': {'$gt': 29}}, function(err, c30) { if (err) { debug('User err: ', err); next(err); }
User.count({'points': {'$gt': 53}}, function(err, all) { if (err) { debug('User err: ', err); next(err); }
res.render('resources/stats', {
title: 'Free Code Camp Stats:',
daysRunning: daysRunning,
nonprofitProjects: nonprofitProjects,
c3: c3,
c10: c10,
c30: c30,
all: all
});
});
});
});
});
});
});
});
});
});
}
},
deployAWebsite: function deployAWebsite(req, res) {
res.render('resources/deploy-a-website', {
title: 'Deploy a Dynamic Website in 7 Minutes'
});
},
nonprofitProjectInstructions: function nonprofitProjectInstructions(req, res) {
res.render('resources/nonprofit-project-instructions', {
title: 'Nonprofit Project Instructions'
});
},
gmailShortcuts: function gmailShortcuts(req, res) {
res.render('resources/gmail-shortcuts', {
title: 'These Gmail Shortcuts will save you Hours'
});
},
controlShortcuts: function controlShortcuts(req, res) {
res.render('resources/control-shortcuts', {
title: 'These Control Shortcuts will save you Hours'
});
},
chromebook: function chromebook(req, res) {
res.render('resources/chromebook', {
title: 'Win a Chromebook'
});
},
jqueryExercises: function jqueryExercises(req, res) {
res.render('resources/jquery-exercises', {
title: 'jQuery Exercises'
});
},
livePairProgramming: function(req, res) {
res.render('resources/live-pair-programming', {
title: 'Live Pair Programming'
});
},
javaScriptInYourInbox: function(req, res) {
res.render('resources/javascript-in-your-inbox', {
title: 'JavaScript in your Inbox'
});
},
pairProgramWithTeamViewer: function(req, res) {
Challenge.find({}, null, { sort: { challengeNumber: 1 } }, function(err, c) {
if (err) {
debug('Challenge err: ', err);
next(err);
}
res.render('resources/pair-program-with-team-viewer', {
title: 'Challenge: Pair Program with Team Viewer',
name: 'Pair Program with Team Viewer',
video: '',
time: 30,
steps: steps,
cc: req.user ? req.user.challengesHash : undefined,
points: req.user ? req.user.points : undefined,
challenges: c
});
});
},
about: function(req, res) {
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));
client.get('https://trello.com/1/boards/BA3xVpz9/cards?key=' + secrets.trello.key, function(trello, res2) {
client.get('https://www.googleapis.com/blogger/v3/blogs/2421288658305323950/posts?key=' + secrets.blogger.key, function(blogger, res3) {
var nonprofitProjects = trello.length || 15;
var blog = JSON.parse(blogger);
User.count({'points': {'$gt': 2}}, function (err, c3) {
if (err) {
debug('User err: ', err);
next(err);
}
User.count({'points': {'$gt': 9}}, function (err, c10) {
if (err) {
debug('User err: ', err);
next(err);
}
User.count({'points': {'$gt': 29}}, function (err, c30) {
if (err) {
debug('User err: ', err);
next(err);
}
User.count({'points': {'$gt': 53}}, function (err, all) {
if (err) {
debug('User err: ', err);
next(err);
}
res.render('resources/learn-to-code', {
title: 'About Free Code Camp and Our Team of Volunteers',
daysRunning: daysRunning,
nonprofitProjects: nonprofitProjects,
c3: c3,
c10: c10,
c30: c30,
all: all,
blog1Title: blog["items"][0]["title"],
blog1Link: blog["items"][0]["url"],
blog2Title: blog["items"][1]["title"],
blog2Link: blog["items"][1]["url"],
blog3Title: blog["items"][2]["title"],
blog3Link: blog["items"][2]["url"],
blog4Title: blog["items"][3]["title"],
blog4Link: blog["items"][3]["url"],
blog5Title: blog["items"][4]["title"],
blog5Link: blog["items"][4]["url"]
});
});
});
});
});
});
});
},
randomPhrase: function() {
var phrases = resources.phrases;
return phrases[Math.floor(Math.random() * phrases.length)];
},
randomVerb: function() {
var verbs = resources.verbs;
return verbs[Math.floor(Math.random() * verbs.length)];
},
randomCompliment: function() {
var compliments = resources.compliments;
return compliments[Math.floor(Math.random() * compliments.length)];
},
numberOfBonfires: function() {
return bonfires.length - 1;
},
allBonfireIds: function() {
return 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;
})
}
};

View File

@ -144,5 +144,101 @@
"You can complete CoderByte problems while you continue to work through Free Code Camp's challenges.",
"Be sure to pair program on these challenges, and remember to apply the RSAP methodology.",
"Click the button below to return to the Pair Programming challenge, then mark it complete."
],
"verbs": [
"aced",
"nailed",
"rocked",
"scorched",
"devastated",
"destroyed",
"owned",
"crushed",
"conquered",
"killed",
"shredded",
"annihilated",
"nuked",
"smashed",
"decimated",
"demolished",
"devoured",
"pulvarized",
"banished",
"throttled",
"blew away",
"roundhoused",
"tangoed",
"wrangled",
"shot down",
"scarfed",
"grappled",
"incinerated"
],
"compliments": [
"You've got the power!",
"Nicely done!",
"Rock and roll!",
"High five!",
"Bravo!",
"Yes!",
"Swoosh!",
"There is no try",
"Done and done!",
"You make this look easy",
"Terminated",
"We have liftoff!",
"To infinity and beyond!",
"Encore!",
"Challenge destroyed!",
"Power level 9000!",
"Most efficient!",
"Party on, Wayne!",
"You've got the touch!",
"You're on fire!",
"Don't hurt 'em, Hammer!",
"The town is now red",
"To the nines!",
"Nothing but net!",
"Grumpy cat approves",
"The world rejoices",
"That's the way it's done!",
"You rock!",
"Woo-hoo!",
"We knew you could do it",
"Hyper Combo Finish!",
"Nothing but net!",
"Boom-shakalaka!",
"You're a shooting star!",
"You're unstoppable!",
"Way cool!",
"You're king of the world!",
"Walk on that sunshine!",
"Keep on trucking!",
"Off the charts!",
"There is no spoon",
"Cranked it up to 11!",
"Escape velocity reached!",
"You make this look easy!",
"Passed with flying colors!",
"One step closer...",
"You've got this!",
"Happy happy joy joy!",
"Tomorrow, the world!",
"Here's looking at you, Code!",
"It's alive. It's alive!"
],
"phrases": [
"Shout it from on top of a mountain",
"Tell everyone and their dogs",
"Show them. Show them all!",
"Inspire your friends",
"Tell the world of your greatness",
"Look accomplished on social media",
"Share news of your grand endeavor",
"Establish your alibi for the past two hours",
"Prove to mom that computers aren't just for games",
"With coding power comes sharing responsibility",
"Have you told your friends of your coding powers?"
]
}
}

View File

@ -12,23 +12,23 @@ var _ = require('lodash'),
//TODO(Berks): Refactor to use module.exports = {} pattern.
/**
* GET /login
* Login page.
* GET /signin
* Siginin page.
*/
exports.getLogin = function(req, res) {
exports.getSignin = function(req, res) {
if (req.user) return res.redirect('/');
res.render('account/login', {
res.render('account/signin', {
title: 'Free Code Camp Login'
});
};
/**
* POST /login
* POST /signin
* Sign in using email and password.
*/
exports.postLogin = function(req, res, next) {
exports.postSignin = function(req, res, next) {
req.assert('email', 'Email is not valid').isEmail();
req.assert('password', 'Password cannot be blank').notEmpty();
@ -36,14 +36,14 @@ exports.postLogin = function(req, res, next) {
if (errors) {
req.flash('errors', errors);
return res.redirect('/login');
return res.redirect('/signin');
}
passport.authenticate('local', function(err, user, info) {
if (err) return next(err);
if (!user) {
req.flash('errors', { msg: info.message });
return res.redirect('/login');
return res.redirect('/signin');
}
req.logIn(user, function(err) {
if (err) return next(err);
@ -54,11 +54,11 @@ exports.postLogin = function(req, res, next) {
};
/**
* GET /logout
* GET /signout
* Log out.
*/
exports.logout = function(req, res) {
exports.signout = function(req, res) {
req.logout();
res.redirect('/');
};
@ -76,7 +76,7 @@ exports.getEmailSignin = function(req, res) {
};
/**
* GET /email-signin
* GET /signin
* Signup page.
*/
@ -146,7 +146,7 @@ exports.getAccount = function(req, res) {
console.error('Challenge err: ', err);
next(err);
}
res.render('account/profile', {
res.render('account/account', {
title: 'Manage your Free Code Camp Account',
challenges: c,
ch: req.user.challengesHash,
@ -184,6 +184,22 @@ exports.checkUniqueUsername = function(req, res) {
}
});
};
/**
* Existing username check
*/
exports.checkExistingUsername = function(req, res) {
User.count({'profile.username': req.params.username.toLowerCase()}, function (err, data) {
if (data == 1) {
debug('sending false back')
return res.send(true);
} else {
debug('sending true back')
return res.send(false);
}
});
};
/**
* Unique email check API Call
*/

View File

@ -5,7 +5,7 @@ var gulp = require('gulp'),
sync = require('browser-sync'),
reload = sync.reload,
inject = require('gulp-inject'),
reloadDelay = 3000;
reloadDelay = 1000;
var paths = {
server: './app.js',

View File

@ -8,20 +8,16 @@ var secrets = require('../config/secrets');
var bonfireSchema = new mongoose.Schema({
name: {
type: String,
unique: true
},
difficulty: Number,
difficulty: String,
description: Array,
publicTests: Array,
privateTests: Array,
tests: Array,
challengeSeed: String,
bonfireNumber: Number,
challengeEntryPoint: String,
challengeEntryPointNegate: String
});
module.exports = mongoose.model('Bonfire', bonfireSchema);

View File

@ -3,11 +3,8 @@ var secrets = require('../config/secrets');
var bonfireCompletionSchema = new mongoose.Schema({
dateCompleted: Number,
completedWith: String,
bonfireNumber: {
bonfireNumber: Number,
bonfireId: String
},
completedWith: ObjectId,
bonfireHash: ObjectId,
solution: String
});

View File

@ -353,7 +353,12 @@ var userSchema = new mongoose.Schema({
},
resetPasswordToken: String,
resetPasswordExpires: Date,
bonfires: Array
uncompletedBonfires: Array,
completedBonfires: Array,
lastContentSync: {
type: Number,
default: 0
}
});
/**

View File

@ -2,8 +2,9 @@
@import "lib/bootstrap-social/bootstrap-social";
@import "lib/ionicons/ionicons";
@import "lib/animate.min.less";
@import "lib/bootstrap/variables";
@import url(http://fonts.googleapis.com/css?family=Lato:300);
//fonts.googleapis.com/css?family=Lato:300);
@import url(http://fonts.googleapis.com/css?family=Lato:400);
@import url(http://fonts.googleapis.com/css?family=Inconsolata);
@ -28,11 +29,19 @@ html {
min-height: 100%;
}
body {
body.full-screen-body-background {
background-color: #eeeeee;
}
body.top-and-bottom-margins {
padding-top: 80px;
margin-bottom: 60px;
}
body.no-top-and-bottom-margins {
margin: 70px 20px 50px 20px;
}
h1, h2 {
font-weight: 400;
}
@ -205,6 +214,11 @@ ul {
animation-duration: 0.5s;
}
.slow-animation {
-webkit-animation-duration: 1.5s;
animation-duration: 1.5s;
}
.disabled {
pointer-events: none;
cursor: default;
@ -247,6 +261,10 @@ ul {
.navbar {
white-space: nowrap;
border: none;
@media (min-width: 767px) {
padding-left: 30px;
padding-right: 30px;
}
}
.panel-body {
@ -505,6 +523,7 @@ thead {
text-align: center;
margin-bottom: -30px;
border-radius: 5px 5px 0px 0px;
padding-left: 50px;
}
.closing-x {
@ -531,22 +550,6 @@ thead {
}
}
form.code span {
font-size: 14px;
font-family: "Ubuntu Mono";
padding-bottom: 0px;
margin-bottom: 0px;
height: auto;
}
#mainEditorPanel .panel-body {
padding-bottom: 0px;
}
div.CodeMirror-scroll {
padding-bottom: 100px;
}
.embed-responsive-twitch-chat {
padding-bottom: 117%;
}
@ -569,13 +572,78 @@ div.CodeMirror-scroll {
text-size: 250px;
}
.bonfire-instructions p {
padding: 0;
}
.bonfire-instructions {
margin-bottom: 2px;
margin-bottom: 5px;
}
/**
* Bonfire styling
*/
form.code span {
font-size: 18px;
font-family: "Ubuntu Mono";
padding-bottom: 0px;
margin-bottom: 0px;
height: 100%;
}
.CodeMirror-linenumber {
font-size: 18px;
font-family: "Ubuntu Mono";
}
#mainEditorPanel {
height: 100%;
}
.big-error-icon {
font-size: 40px;
color: @brand-danger;
}
.big-success-icon {
font-size: 40px;
color: @brand-primary;
}
.test-output {
font-size: 15px;
font-family: "Ubuntu Mono";
}
#mainEditorPanel .panel-body {
padding-bottom: 0px;
}
.panel-bonfire {
height: 100%
}
div.CodeMirror-scroll {
padding-bottom: 30px;
}
.test-vertical-center {
margin-top: 15px;
}
.cm-s-monokai.CodeMirror {
border-radius: 5px;
}
.bonfire-flames {
margin-top: -20px;
margin-bottom: -2px;
}
.bonfire-top {
margin-top: -30px;
}
//uncomment this to see the dimensions of all elements outlined in red
//* {
// border-color: red;

View File

@ -7,7 +7,6 @@ var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("codeEditor")
lint: true,
matchBrackets: true,
autoCloseBrackets: true,
cursorHeight: 1,
scrollbarStyle: 'null',
lineWrapping: true,
gutters: ["CodeMirror-lint-markers"],
@ -20,13 +19,13 @@ var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("codeEditor")
}
});
var editor = myCodeMirror;
editor.setSize("100%", "auto");
// 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\n' +
' by using the keywords assert and expect */\n\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' +
@ -35,7 +34,9 @@ var nonChallengeValue = '/*Welcome to Bonfire, Free Code Camp\'s future CoderByt
'}\n' +
'expect(test()).to.be.a("array");\n\n' +
'assert.deepEqual(test(), [1,4,9]);\n\n' +
'test();';
'var foo = test();\n' +
'foo.should.be.a("array");\n\n' +
'test();\n';
var codeOutput = CodeMirror.fromTextArea(document.getElementById("codeOutput"), {
lineNumbers: false,
@ -45,9 +46,9 @@ var codeOutput = CodeMirror.fromTextArea(document.getElementById("codeOutput"),
lineWrapping: true
});
codeOutput.setValue('/**\n' +
' * Your output will go here. Console.log() -type statements\n' +
' * will appear in your browser\'s javascript console.\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;
@ -58,10 +59,8 @@ var editorValue;
var challengeSeed = challengeSeed || null;
var publicTests = publicTests || [];
var privateTests = privateTests || [];
var tests = tests || [];
var challengeEntryPoint = challengeEntryPoint || null;
var challengeEntryPointNegate = challengeEntryPointNegate || null;
if (challengeSeed !== null) {
@ -101,11 +100,15 @@ $('#submitButton').on('click', function () {
});
function bonfireExecute() {
tests = null;
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
if (challengeEntryPoint) {
userJavaScript = challengeEntryPoint + ' ' + userJavaScript;
}
submit(userJavaScript, function(cls, message) {
if (cls) {
codeOutput.setValue(message.error);
@ -118,24 +121,16 @@ function bonfireExecute() {
});
}
var replaceQuotesInTests = function() {
tests.forEach(function(elt, ix, arr) {
arr[ix].text = arr[ix].text.replace(/\"/g,'\'');
});
};
var tests;
var userTests;
var testSalt = Math.random();
var scrapeTests = function(userJavaScript) {
for (var i = 0; i < publicTests.length; i++) {
userJavaScript += '\n' + publicTests[i];
}
for (var i = 0; i < privateTests.length; i++) {
userJavaScript += '\n' + privateTests[i];
// insert tests from mongo
for (var i = 0; i < tests.length; i++) {
userJavaScript += '\n' + tests[i];
}
var counter = 0;
@ -143,17 +138,16 @@ var scrapeTests = function(userJavaScript) {
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);
userJavaScript = userJavaScript.substring(0, match.index) + replacement + userJavaScript.substring(match.index + match[0].length);
if (!tests) tests = [];
tests.push({"text": match[0], "line": counter, "err": null});
if (!userTests) {
userTests= [];
}
userTests.push({"text": match[0], "line": counter, "err": null});
counter++;
match = regex.exec(userJavaScript);
}
if (tests) replaceQuotesInTests();
return userJavaScript;
};
@ -164,30 +158,23 @@ function removeComments(userJavaScript) {
function removeLogs(userJavaScript) {
return userJavaScript.replace(/(console\.[\w]+\s*\(.*\;)/g, '');
return userJavaScript;
}
var pushed = false;
var createTestDisplay = function() {
if (pushed) {
tests.pop();
userTests.pop();
}
for (var i = 0; i < tests.length;i++) {
var test = tests[i];
var testDoc = document.createElement("li");
$(testDoc)
.addClass('list-group-item')
.addClass('well img-rounded')
.addClass('well-sm')
for (var i = 0; i < userTests.length;i++) {
var test = userTests[i];
var testDoc = document.createElement("div");
if (test.err != null) {
$(testDoc)
.html(test.text + "\n" + test.err)
.css("background-color", 'rgba(255,0,0,.2)')
.prependTo($('#testSuite'));
.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'>" + 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(test.text)
.css('background-color', 'rgba(0,255,0,.2)')
.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'));
}
};
@ -201,28 +188,39 @@ var reassembleTest = function(test, data) {
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 && tests.length > 0) {
tests = [{text:"Program Execution Failure", err: "No tests were run."}];
if (err && userTests.length > 0) {
userTests= [{text:"Program Execution Failure", err: "No user tests were run."}];
createTestDisplay();
} else if (tests) {
tests.push(false);
} else if (userTests) {
userTests.push(false);
pushed = true;
tests.forEach(function(test, ix, arr){
userTests.forEach(function(test, ix, arr){
try {
if (test) {
console.log();
var output = eval(reassembleTest(test, data));
}
} catch(error) {
allTestsPassed = false;
arr[ix].err = error.name + ":" + error.message;
} finally {
} finally {
if (!test) {
createTestDisplay();
}
}
});
}
};
if (allTestsPassed) {
allTestsPassed = false;
showCompletion();
}
};
function showCompletion() {
$('#complete-bonfire-dialog').modal('show');
}

View File

@ -1,6 +1,6 @@
/* Based on Sublime Text's Monokai theme */
.cm-s-monokai.CodeMirror {background: #272822; color: #f8f8f2; border-radius: 5px; height: auto;}
.cm-s-monokai.CodeMirror {background: #272822; color: #f8f8f2; height: auto;}
.cm-s-monokai div.CodeMirror-selected {background: #49483E !important;}
.cm-s-monokai .CodeMirror-gutters {background: #272822; border-right: 0px;}
.cm-s-monokai .CodeMirror-guttermarker { color: white; }

View File

@ -1,46 +1,96 @@
$(document).ready(function() {
var CSRF_HEADER = 'X-CSRF-Token';
var CSRF_HEADER = 'X-CSRF-Token';
var setCSRFToken = function(securityToken) {
jQuery.ajaxPrefilter(function(options, _, xhr) {
if (!xhr.crossDomain) {
xhr.setRequestHeader(CSRF_HEADER, securityToken);
}
var setCSRFToken = function(securityToken) {
jQuery.ajaxPrefilter(function(options, _, xhr) {
if (!xhr.crossDomain) {
xhr.setRequestHeader(CSRF_HEADER, securityToken);
}
});
};
setCSRFToken($('meta[name="csrf-token"]').attr('content'));
$('.start-challenge').on('click', function() {
$(this).parent().remove();
$('.challenge-content')
.removeClass('hidden-element')
.addClass('animated fadeInDown');
});
};
setCSRFToken($('meta[name="csrf-token"]').attr('content'));
$('.completed-challenge').on('click', function() {
$('#complete-challenge-dialog').modal('show');
// Only post to server if there is an authenticated user
if ($('.signup-btn-nav').length < 1) {
l = location.pathname.split('/');
cn = l[l.length - 1];
$.ajax({
type: 'POST',
data: {challengeNumber: cn},
url: '/completed-challenge/'
});
}
});
$('.start-challenge').on('click', function() {
$(this).parent().remove();
$('.challenge-content')
.removeClass('hidden-element')
.addClass('animated fadeInDown');
});
$('.completed-challenge').on('click', function() {
$('#complete-dialog').modal('show');
// Only post to server if there is an authenticated user
if ($('.signup-btn-nav').length < 1) {
l = location.pathname.split('/');
cn = l[l.length - 1];
$.ajax({
type: 'POST',
data: {challengeNumber: cn},
url: '/completed-challenge/'
});
}
});
$('.all-challenges').on('click', function() {
$('#all-challenges-dialog').modal('show');
});
function completedBonfire(didCompleteWith, bonfireSolution, thisBonfireHash) {
$('#complete-bonfire-dialog').modal('show');
// Only post to server if there is an authenticated user
if ($('.signup-btn-nav').length < 1) {
$.ajax({
type: 'POST',
data: {
bonfireInfo: {
completedWith : didCompleteWith,
solution: bonfireSolution,
bonfireHash: thisBonfireHash
}
},
url: '/completed-bonfire/'
$('.next-button').on('click', function() {
l = location.pathname.split('/');
window.location = '/challenges/' + (parseInt(l[l.length - 1]) + 1);
});
});
//$.post( '/completed-bonfire', function( data ) {
// window.location = '/bonfires';
//});
}
}
$('.all-challenges').on('click', function() {
$('#all-challenges-dialog').modal('show');
});
$('.all-bonfires').on('click', function() {
$('#all-bonfires-dialog').modal('show');
});
$('.next-challenge-button').on('click', function() {
l = location.pathname.split('/');
window.location = '/challenges/' + (parseInt(l[l.length - 1]) + 1);
});
$('.next-bonfire-button').on('click', function() {
var bonfireSolution = myCodeMirror.getValue();
var thisBonfireHash = passedBonfireHash || null;
var didCompleteWith = $('#completed-with').val() || null;
completedBonfire(didCompleteWith, bonfireSolution, thisBonfireHash);
window.location = '/bonfires';
});
// Bonfire instructions functions
$('#more-info').on('click', function() {
$('#brief-instructions').hide();
$('#long-instructions').show().removeClass('hide');
});
$('#less-info').on('click', function() {
$('#brief-instructions').show();
$('#long-instructions').hide();
});
});
var profileValidation = angular.module('profileValidation',['ui.bootstrap']);
@ -58,6 +108,12 @@ profileValidation.controller('profileValidationController', ['$scope', '$http',
}
]);
profileValidation.controller('pairedWithController', ['$scope',
function($scope) {
$scope.existingUser = null;
}
]);
profileValidation.controller('emailSignUpController', ['$scope',
function($scope) {
@ -102,6 +158,31 @@ profileValidation.directive('uniqueUsername', function($http) {
}
}
});
// TODO: FIX THIS
profileValidation.directive('existingUsername', 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 {
ngModel.$setPristine();
}
if (element.val()) {
$http.get("/api/checkExistingUsername/" + element.val() + ' ').success(function (data) {
if (element.val() == scope.existingUsername) {
ngModel.$setValidity('exists', false);
} else if (data) {
ngModel.$setValidity('exists', true);
}
});
}
});
}
}
});
profileValidation.directive('uniqueEmail', function($http) {
return {

View File

@ -1,44 +1,66 @@
[
{
"name": "Palindrome Tester",
"difficulty": 1,
"_id" : "ad7123c8c441eddfaeb5bdef",
"name": "Meet Bonfire",
"difficulty": "0",
"description": [
"Your job is to determine if a provided string is a palindrome.",
"The definition of a palindrome can be found at http://en.wikipedia.org/wiki/Palindrome.",
"Strings will be passed in with varying formats, such as \"racecar\", \"RaceCar\", and \"race CAR\" among others.",
"Return true if the string is a palindrome, otherwise false"
"Click the button below for further instructions.",
"Your goal is to fix the failing test.",
"First, run all the tests by clickin \"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."
],
"publicTests": [
"tests": [
"expect(meetBonfire(\"test\")).to.be.a(\"boolean\");",
"expect(meetBonfire(\"test\")).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\nreturn false;\n}\n\n",
"challengeEntryPoint": "meetBonfire(\"You can do this!\");"
},
{
"_id" : "aaa48de84e1ecc7c742e1124",
"name": "Check for Palindromes",
"difficulty": "1",
"description": [
"Return 'true' if a given string is a palindrome.",
"A palindrome is a word or sentence that's spelled the same way both forward and backward, ignoring punctuation and case.",
"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.",
"Return true if the string is a palindrome. Otherwise, return false."
],
"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);"
],
"privateTests": [
"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",
"challengeEntryPoint": "palindrome(\"eye\");",
"bonfireNumber": 1,
"challengeEntryPointNegate" : "palindrome\\([^str].*\\;"
"challengeEntryPoint": "palindrome(\"eye\");"
},
{
"_id" : "aff0395860f5d3034dc0bfc9",
"name": "Validate US Telephone Numbers",
"difficulty": 3,
"difficulty": "3",
"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 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."
],
"publicTests": [
"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);"
],
"privateTests": [
"assert.deepEqual(telephoneCheck(\"123**&!!asdf#\"), false);",
"assert.deepEqual(telephoneCheck(\"55555555\"), false);",
"assert.deepEqual(telephoneCheck(\"(6505552368)\"), false);",
"assert.deepEqual(telephoneCheck(\"2 (757) 622-7382\"), false);",
@ -52,9 +74,97 @@
"assert.deepEqual(telephoneCheck(\"2(757)622-7382\"), false);"
],
"challengeSeed": "function telephoneCheck(str) {\n // Good luck!\n return true;\n}\n\n",
"challengeEntryPoint": "telephoneCheck(\"555-555-5555\");",
"bonfireNumber": 2,
"challengeEntryPointNegate" : "palindrome\\([^str].*\\;"
"challengeEntryPoint": "telephoneCheck(\"555-555-5555\");"
},
{
"_id": "a202eed8fc186c8434cb6d61",
"name": "Reverse a String",
"difficulty": "1",
"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."
],
"challengeEntryPoint": "reverseString('hello');",
"challengeSeed": "function reverseString(str) {\n return str;\r\n}"
},
{
"_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",
"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}",
"challengeEntryPoint": "factorialize(5);"
},
{
"_id": "a26cbbe9ad8655a977e1ceb5",
"name": "Find the Longest Word in a String",
"difficulty": "1",
"description": [
"Return the length of the longest word in the provided sentence.",
"Your response should be a number."
],
"challengeEntryPoint": "findLongestWord('The quick brown fox jumped over the lazy dog');",
"challengeSeed": "function findLongestWord(str) {\n return str.length;\r\n}",
"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);"
]
},
{
"_id": "a3566b1109230028080c9345",
"name": "Sum All Numbers in a Range",
"difficulty": "2",
"description": [
"We'll pass you an array of two numbers. Return the sum those two numbers and all numbers between them.",
"The lowest number will not always come first."
],
"challengeEntryPoint": "sumAll([1, 4]);",
"challengeSeed": "function sumAll(arr) {\n return(1);\r\n}",
"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);"
]
},
{
"_id": "ab6137d4e35944e21037b769",
"name": "Title Case a Sentence",
"difficulty": "1",
"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'."
],
"challengeEntryPoint": "titleCase(\"I'm a little tea pot\")",
"challengeSeed": "function titleCase(str) {\n return str;\r\n}",
"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\");"
]
}
]

View File

@ -1,8 +1,7 @@
/*
"aaa48de84e1ecc7c742e1124"
"ff0395860f5d3034dc0bfc94"
"7123c8c441eddfaeb5bdef0d"
"c3a4d278b9e760a0ffe8321f"
"aceca143b92049a4392a859e"
"ce9394f67d413734758e27e4"
"1369953ef6f03098cb60e2f7"

View File

@ -1,4 +1,4 @@
extends ../layout
extends ../layout-wide
block content
script(src='/js/lib/codemirror/lib/codemirror.js')
script(src='/js/lib/codemirror/addon/edit/closebrackets.js')
@ -15,9 +15,15 @@ block content
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 Bonfire Playground
.panel-heading.text-center Playground
.panel.panel-body
form.code
.form-group.codeMirrorView

View File

@ -0,0 +1,45 @@
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", placeholder="Separate sentences by exactly one space only. Do not add in line breaks.")
.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")

View File

@ -0,0 +1,44 @@
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", placeholder="Separate sentences by exactly one space only. Do not add in line breaks.")
.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")

View File

@ -1,4 +1,4 @@
extends ../layout
extends ../layout-wide
block content
script(src='/js/lib/codemirror/lib/codemirror.js')
@ -18,33 +18,123 @@ block content
.row
#mainEditorPanel.col-sm-12.col-md-7.col-xs-12
.panel.panel-primary.panel-bonfire
.panel-heading.text-center #{name} (Level #{difficulty} bonfire)
.panel.panel-body
.well
.text-justify.bonfire-instructions
for sentence in description
p.bonfire-instructions!= sentence
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(type="text/javascript").
var publicTests = !{JSON.stringify(publicTests)};
var privateTests = !{JSON.stringify(privateTests)};
var challengeSeed = !{JSON.stringify(challengeSeed)};
var challengeEntryPoint = !{JSON.stringify(challengeEntryPoint)};
var challengeEntryPointNegate = !{JSON.stringify(challengeEntryPointNegate)};
script(src='/js/lib/bonfire/bonfireFramework.js')
.col-xs-12.col-sm-12.col-md-4.bonfire-top
#testCreatePanel
h2.text-center= name
h2.text-center.bonfire-flames
if (difficulty == "0")
i.ion-ios-flame-outline
i.ion-ios-flame-outline
i.ion-ios-flame-outline
i.ion-ios-flame-outline
i.ion-ios-flame-outline
if (difficulty == "1")
i.ion-ios-flame
i.ion-ios-flame-outline
i.ion-ios-flame-outline
i.ion-ios-flame-outline
i.ion-ios-flame-outline
if (difficulty == "2")
i.ion-ios-flame
i.ion-ios-flame
i.ion-ios-flame-outline
i.ion-ios-flame-outline
i.ion-ios-flame-outline
if (difficulty == "3")
i.ion-ios-flame
i.ion-ios-flame
i.ion-ios-flame
i.ion-ios-flame-outline
i.ion-ios-flame-outline
if (difficulty == "4")
i.ion-ios-flame
i.ion-ios-flame
i.ion-ios-flame
i.ion-ios-flame
i.ion-ios-flame-outline
if (difficulty == "5")
i.ion-ios-flame
i.ion-ios-flame
i.ion-ios-flame
i.ion-ios-flame
i.ion-ios-flame
.well
.row.text-center
row.text-center
.col-xs-12
.bonfire-instructions
= brief
#brief-instructions.col-xs-12
button#more-info.btn.btn-info
span.ion-help-circled
| More information
#long-instructions.row.text-center.hide
.col-xs-12
.bonfire-instructions
for sentence in details
p!= sentence
button#less-info.btn.btn-info
span.ion-help-circled
| Less information
#submitButton.btn.btn-primary.btn-big.btn-block Run code (ctrl + enter)
br
form.code
.form-group.codeMirrorView
textarea#codeOutput
br
#testSuite
br
script(type="text/javascript").
var tests = !{JSON.stringify(tests)};
var challengeSeed = !{JSON.stringify(challengeSeed)};
var challengeEntryPoint = !{JSON.stringify(challengeEntryPoint)};
var passedBonfireHash = !{JSON.stringify(bonfireHash)};
.col-xs-12.col-sm-12.col-md-8
#mainEditorPanel
form.code
.form-group.codeMirrorView
textarea#codeEditor(autofocus=true)
script(src='/js/lib/bonfire/bonfireFramework.js')
#complete-bonfire-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")
.text-center
.animated.zoomInDown.delay-half
span.landing-icon.ion-checkmark-circled.text-primary
- if (cc)
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-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, aria-hidden='true', ng-disabled='completedWithForm.$invalid && existingUser.length > 0') Take me to my next challenge
- if (points && points > 2)
a.animated.fadeIn.btn.btn-lg.btn-block.btn-twitter(href="https://twitter.com/intent/tweet?text=I%20just%20#{verb}%20%40FreeCodeCamp%20Challenge%20%23#{number}:%20#{name}&url=http%3A%2F%2Ffreecodecamp.com/bonfires/#{number}&hashtags=learntocode, javascript" target="_blank")
i.fa.fa-twitter &nbsp;
= phrase
- else
a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress
#all-bonfires-dialog.modal(tabindex='-1')
.modal-dialog.animated.fadeInUp.fast-animation
.modal-content
.modal-header.challenge-list-header Bonfires
a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') ×
.modal-body
include ../partials/bonfires

View File

@ -16,19 +16,19 @@ block content
.btn.btn-primary.btn-big.btn-block.completed-challenge I've completed this challenge
.ten-pixel-break
.btn.btn-success.btn-big.btn-block.all-challenges Show me all the challenges
#complete-dialog.modal(tabindex='-1')
#complete-challenge-dialog.modal(tabindex='-1')
.modal-dialog.animated.zoomIn.fast-animation
.modal-content
.modal-header.challenge-list-header Nicely done!
.modal-header.challenge-list-header= compliment
a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') ×
.modal-body
.text-center
.animated.zoomInDown.delay-half
span.landing-icon.ion-checkmark-circled.text-primary
- if (cc)
a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block.next-button(name='_csrf', value=_csrf, aria-hidden='true') Take me to my next challenge
a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block.next-challenge-button(name='_csrf', value=_csrf, aria-hidden='true') Take me to my next challenge
- if (points && points > 2)
a.animated.fadeIn.btn.btn-lg.btn-block.btn-twitter(href="https://twitter.com/intent/tweet?text=I%20just%20#{verb}%20Free%20Code%20Camp%20Challenge%20%23#{number}:%20#{name}&url=http%3A%2F%2Ffreecodecamp.com/challenges/#{number}&hashtags=learntocode, javascript" target="_blank")
a.animated.fadeIn.btn.btn-lg.btn-block.btn-twitter(href="https://twitter.com/intent/tweet?text=I%20just%20#{verb}%20%40FreeCodeCamp%20Challenge%20%23#{number}:%20#{name}&url=http%3A%2F%2Ffreecodecamp.com/challenges/#{number}&hashtags=learntocode, javascript" target="_blank")
i.fa.fa-twitter &nbsp;
= phrase
- else

33
views/layout-wide.jade Normal file
View File

@ -0,0 +1,33 @@
doctype html
html(ng-app='profileValidation', lang='en')
head
script(src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js")
script(src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.min.js")
script(src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.0/ui-bootstrap-tpls.min.js")
link(rel='shortcut icon', href='//s3.amazonaws.com/freecodecamp/favicon.ico')
link(rel='stylesheet', href='//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css')
link(rel='stylesheet', href='//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css')
link(rel='stylesheet', href='//code.ionicframework.com/ionicons/2.0.0/css/ionicons.min.css')
include partials/meta
title #{title} | Free Code Camp
meta(charset='utf-8')
meta(http-equiv='X-UA-Compatible', content='IE=edge')
meta(name='viewport', content='width=device-width, initial-scale=1.0')
meta(name='csrf-token', content=_csrf)
!= css('main')
body.no-top-and-bottom-margins.full-screen-body-background
include partials/navbar-wide
include partials/flash
block content
include partials/footer
!= js('application')
script.
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-55446531-1', 'auto');
ga('require', 'displayfeatures');
ga('send', 'pageview');
script(src="//cdn.optimizely.com/js/999692993.js")

View File

@ -16,14 +16,13 @@ html(ng-app='profileValidation', lang='en')
meta(name='csrf-token', content=_csrf)
!= css('main')
body
include partials/navbar
body.top-and-bottom-margins
include partials/navbar-narrow
.container
include partials/flash
block content
include partials/footer
!= js('application')
!= js('application')
script.
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),

View File

@ -1 +1,7 @@
//TODO: STUFF
h3
ol(start='0')
for bonfire in bonfires
li
a(href="/bonfires/#{bonfire.bonfireNumber}", class="#{ (cc && cc[bonfire.bonfireNumber] > 0) ? 'strikethrough' : '' }") #{bonfire.name}
| &nbsp; (Level #{bonfire.difficulty})
a.btn.btn-lg.btn-primary.btn-block(href="/done-with-first-100-hours", class="#{ ((cc && cc[53] === 0) || (!cc)) ? 'disabled' : '' }") I'm done with all the challenges!

View File

@ -15,4 +15,6 @@
| &nbsp;
a.ion-information-circled(title="About Free Code Camp", href="/learn-to-code")
| &nbsp;
a.ion-locked(title="Free Code Camp's Privacy Policy", href="/privacy")
a.ion-locked(title="Free Code Camp's Privacy Policy", href="/privacy")
| &nbsp;
a.ion-code-working(title="Bonfire Coding Playground", href="/playground")

View File

@ -0,0 +1,3 @@
nav.navbar.navbar-default.navbar-fixed-top.nav-height
.container
include ./navbar

View File

@ -0,0 +1,2 @@
nav.navbar.navbar-default.navbar-fixed-top.nav-height
include ./navbar

View File

@ -1,46 +1,44 @@
nav.navbar.navbar-default.navbar-fixed-top.nav-height
.container
.navbar-header
button.navbar-toggle(type='button', data-toggle='collapse', data-target='.navbar-collapse')
.navbar-header
button.navbar-toggle(type='button', data-toggle='collapse', data-target='.navbar-collapse')
span.sr-only Toggle navigation
span.icon-bar
span.icon-bar
span.icon-bar
a.navbar-brand(href='/')
a.navbar-brand(href='/')
img.img-responsive.nav-logo(src='https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg', alt='learn to code javascript at Free Code Camp logo')
.collapse.navbar-collapse
ul.nav.navbar-nav.navbar-right.hamburger-dropdown
.collapse.navbar-collapse
ul.nav.navbar-nav.navbar-right.hamburger-dropdown
- if (!cc)
li
a(href='/challenges/0') Challenges
li
a(href='/challenges/0') Challenges
- else
li
a(href='/') Challenges
li
a(href='/') Challenges
- if (!cc || (cc && cc[1] < 1))
li
a(href='/challenges/1') Chat
li
a(href='/challenges/1') Chat
- else
li
a(href='http://chat.freecodecamp.com' target='_blank') Chat
li
a(href='http://chat.freecodecamp.com' target='_blank') Chat
- if (!cc || (cc && cc[2] < 1))
li
a(href='/challenges/2') Forum
li
a(href='/challenges/2') Forum
- else
li
a(href='http://forum.freecodecamp.com' target='_blank') Forum
li
a(href='http://forum.freecodecamp.com' target='_blank') Forum
li
a(href='/bonfire') Bonfire
li &nbsp; &nbsp; &nbsp;
a(href='/bonfires') Bonfires
if !user
li
a.btn.signup-btn.signup-btn-nav(href='/login') Sign in
li &nbsp; &nbsp; &nbsp;
li
a.btn.signup-btn.signup-btn-nav(href='/login') Sign in
else
li
a(href='/account') [&nbsp;#{user.points}&nbsp;]
li
a(href='/account') [&nbsp;#{user.points}&nbsp;]
.hidden-xs
if user.profile.picture
a(href='/account')
img.profile-picture.float-right(src='#{user.profile.picture}')
else
a(href='/account')
img.profile-picture.float-right(src='#{user.gravatar(60)}')
if user.profile.picture
a(href='/account')
img.profile-picture.float-right(src='#{user.profile.picture}')
else
a(href='/account')
img.profile-picture.float-right(src='#{user.gravatar(60)}')

View File

@ -1,91 +1,50 @@
doctype html
html(ng-app='profileValidation', lang='en')
head
script(src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js")
script(src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.min.js")
script(src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.0/ui-bootstrap-tpls.min.js")
link(rel='shortcut icon', href='//s3.amazonaws.com/freecodecamp/favicon.ico')
link(rel='stylesheet', href='//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css')
link(rel='stylesheet', href='//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css')
link(rel='stylesheet', href='//code.ionicframework.com/ionicons/2.0.0/css/ionicons.min.css')
include ../partials/meta
title #{title} | Free Code Camp
meta(charset='utf-8')
meta(http-equiv='X-UA-Compatible', content='IE=edge')
meta(name='viewport', content='width=device-width, initial-scale=1.0')
meta(name='csrf-token', content=_csrf)
!= css('main')
body
block content
include ../partials/navbar
.panel.panel-primary
.panel-heading.landing-panel-heading.text-center Live Pair Programming
.panel-body
.landing-panel-body.text-center
h2 We live pair program every Tuesday from 9 pm to 10 pm EST (Eastern Standard Time).
h2 Our next session will be January 27th, 2015 at 9 p.m. EST!
h2 Join the discussion in our &nbsp;
a(href="chat.freecodecamp.com", target="_blank") FreeCodeCamp chat room.
h2 Watch the live stream below or on our &nbsp;
a(href="http://twitch.tv/freecodecamp", target='_blank') Twitch.tv channel
| .
.row
.col-md-8.col-xs-12
.embed-responsive.embed-responsive-16by9
iframe(src='http://www.twitch.tv/freecodecamp/embed', frameborder='0', scrolling='no')
.col-md-4.col-xs-12
.visible-sm.visible-xs
.embed-responsive.embed-responsive-16by9
iframe(src='http://www.twitch.tv/freecodecamp/chat?popout=', frameborder='0', scrolling='no')
.visible-md.visible-lg
.embed-responsive.embed-responsive-twitch-chat
iframe(src='http://www.twitch.tv/freecodecamp/chat?popout=', frameborder='0', scrolling='no')
extends ../layout-wide
block content
include ../partials/navbar-wide
.panel
.panel-body
.landing-panel-body.text-center
h1 Live Pair Programming
h2 We live pair program every Tuesday from 9 pm to 10 pm EST (Eastern Standard Time).
h2 Our next session will be January 27th, 2015 at 9 p.m. EST!
h2 Watch the live stream below or on our &nbsp;
a(href="http://twitch.tv/freecodecamp", target='_blank') Twitch.tv channel
| .
.row
.col-md-8.col-xs-12
.embed-responsive.embed-responsive-16by9
iframe(src='http://www.twitch.tv/freecodecamp/embed', frameborder='0', scrolling='no')
.col-md-4.col-xs-12
.visible-sm.visible-xs
.embed-responsive.embed-responsive-16by9
iframe(src='http://www.twitch.tv/freecodecamp/chat?popout=', frameborder='0', scrolling='no')
.visible-md.visible-lg
.embed-responsive.embed-responsive-twitch-chat
iframe(src='http://www.twitch.tv/freecodecamp/chat?popout=', frameborder='0', scrolling='no')
br
.panel.panel-primary
.panel-heading.landing-panel-heading.text-center Previous Live Pair Programming Sessions
.panel-body
.landing-panel-body.text-center
.col-xs-12
.embed-responsive.embed-responsive-16by9.big-break
iframe.embed-responsive-item(src='//www.youtube.com/embed/_BErpDdmBOw')
h3.wrappable link: &nbsp;
a(href="http://www.youtube.com/watch/_BErpDdmBOw") http://www.youtube.com/watch/_BErpDdmBOw
.embed-responsive.embed-responsive-16by9.big-break
iframe.embed-responsive-item(src='//www.youtube.com/embed/Fn9HMn79KH0')
h3.wrappable link: &nbsp;
a(href="http://www.youtube.com/watch/Fn9HMn79KH0") http://www.youtube.com/watch/Fn9HMn79KH0
.embed-responsive.embed-responsive-16by9.big-break
iframe.embed-responsive-item(src='//www.youtube.com/embed/S7iRBZJwOAs')
h3.wrappable link: &nbsp;
a(href="http://www.youtube.com/watch/S7iRBZJwOAs") http://www.youtube.com/watch/S7iRBZJwOAs
.embed-responsive.embed-responsive-16by9.big-break
iframe.embed-responsive-item(src='//www.youtube.com/embed/BHNRg39ZblE')
h3.wrappable link: &nbsp;
a(href="http://www.youtube.com/watch/BHNRg39ZblE") http://www.youtube.com/watch/BHNRg39ZblE
.embed-responsive.embed-responsive-16by9.big-break
iframe.embed-responsive-item(src='//www.youtube.com/embed/YDfkHlDmehA')
h3.wrappable link: &nbsp;
a(href="http://www.youtube.com/watch/YDfkHlDmehA") http://www.youtube.com/watch/YDfkHlDmehA
h3 Got 3 minutes? Learn to code with us!
a.btn.btn-cta.signup-btn.btn-primary(href="/login") Start learning to code (it's free)
br
br
include ../partials/footer
!= js('application')
script.
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date();
a = s.createElement(o),
m = s.getElementsByTagName(o)[0];
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
ga('create', 'UA-55446531-1', 'auto');
ga('require', 'displayfeatures');
ga('send', 'pageview');
script(src="//cdn.optimizely.com/js/999692993.js")
h1 Previous Live Pair Programming Sessions
.col-xs-12
.embed-responsive.embed-responsive-16by9.big-break
iframe.embed-responsive-item(src='//www.youtube.com/embed/_BErpDdmBOw')
h3.wrappable link: &nbsp;
a(href="http://www.youtube.com/watch/_BErpDdmBOw") http://www.youtube.com/watch/_BErpDdmBOw
.embed-responsive.embed-responsive-16by9.big-break
iframe.embed-responsive-item(src='//www.youtube.com/embed/Fn9HMn79KH0')
h3.wrappable link: &nbsp;
a(href="http://www.youtube.com/watch/Fn9HMn79KH0") http://www.youtube.com/watch/Fn9HMn79KH0
.embed-responsive.embed-responsive-16by9.big-break
iframe.embed-responsive-item(src='//www.youtube.com/embed/S7iRBZJwOAs')
h3.wrappable link: &nbsp;
a(href="http://www.youtube.com/watch/S7iRBZJwOAs") http://www.youtube.com/watch/S7iRBZJwOAs
.embed-responsive.embed-responsive-16by9.big-break
iframe.embed-responsive-item(src='//www.youtube.com/embed/BHNRg39ZblE')
h3.wrappable link: &nbsp;
a(href="http://www.youtube.com/watch/BHNRg39ZblE") http://www.youtube.com/watch/BHNRg39ZblE
.embed-responsive.embed-responsive-16by9.big-break
iframe.embed-responsive-item(src='//www.youtube.com/embed/YDfkHlDmehA')
h3.wrappable link: &nbsp;
a(href="http://www.youtube.com/watch/YDfkHlDmehA") http://www.youtube.com/watch/YDfkHlDmehA
h3 Got 3 minutes? Learn to code with us!
a.btn.btn-cta.signup-btn.btn-primary(href="/login") Start learning to code (it's free)
br
br