From 6ea5f5c8954eb42c386a27f45ac1dc3e98e725d4 Mon Sep 17 00:00:00 2001 From: Nathan Leniz Date: Wed, 21 Jan 2015 21:32:13 -0500 Subject: [PATCH 01/12] Preparing for bonfire challenges, create Bonfire model, BonfireCompletion model, update bonfire controller, create initial bonfire seed data --- controllers/bonfire.js | 127 +++--- controllers/challenges.js | 4 +- models/Bonfire.js | 19 +- models/BonfireCompletion.js | 15 + models/User.js | 744 ++++++++++++++++++------------------ seed_data/bonfires.json | 225 +++++++++++ 6 files changed, 698 insertions(+), 436 deletions(-) create mode 100644 models/BonfireCompletion.js create mode 100644 seed_data/bonfires.json diff --git a/controllers/bonfire.js b/controllers/bonfire.js index c19f410364..88930d0e6b 100644 --- a/controllers/bonfire.js +++ b/controllers/bonfire.js @@ -1,68 +1,75 @@ var _ = require('lodash'), -debug = require('debug')('freecc:cntr:bonfires'); -// bonfire = require('./../models/Bonfire'); + debug = require('debug')('freecc:cntr:bonfires'), + Bonfire = require('./../models/Bonfire'); /** * Bonfire controller */ + +var highestBonfireNumber = 10; + exports.index = function(req, res) { - res.render('bonfire/bonfire.jade', { - title: 'Learn to code with Bonfire' - }); - //Bonfire.find({}, null, { sort: { bonfireNumber: 1 } }, function(err, c) { - // if (err) { - // debug('bonfire err: ', err); - // next(err); - // } - //}); + res.render('bonfire/bonfire.jade', { + title: 'Learn to code with Bonfire' + }); + + Bonfire.find({}, null, { sort: { bonfireNumber: 1 } }, function(err, c) { + if (err) { + debug('bonfire err: ', err); + next(err); + } + }); }; -//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 > 53) { bonfireNumber = 0; } -// Bonfire.find({}, null, { sort: { bonfireNumber: 1 } }, function(err, c) { -// if (err) { -// debug('bonfire err: ', err); -// next(err); -// } -// res.render('bonfires/show', { -// //title: 'bonfire: ' + c[bonfireNumber].name, -// //name: c[bonfireNumber].name, -// //video: c[bonfireNumber].video, -// //time: c[bonfireNumber].time, -// //steps: c[bonfireNumber].steps, -// //number: bonfireNumber, -// //categories: c[bonfireNumber].category, -// //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: c -// }); -// }); -//}; \ No newline at end of file +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, c) { + if (err) { + debug('bonfire err: ', err); + next(err); + } + + res.render('bonfires/show', { + title: 'bonfire: ' + c[bonfireNumber].name, + name: c[bonfireNumber].name, + number: bonfireNumber, + difficulty: c[bonfireNumber].difficulty, + description: c[bonfireNumber].description, + publicTests: c[bonfireNumber].publicTests, + privateTests: c[bonfireNumber].privateTests, + challengeSeed: c[bonfireNumber].challengeSeed, + + 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: c + }); + }); +}; \ No newline at end of file diff --git a/controllers/challenges.js b/controllers/challenges.js index e686fc8b39..96170f433b 100644 --- a/controllers/challenges.js +++ b/controllers/challenges.js @@ -6,6 +6,8 @@ var _ = require('lodash'), debug = require('debug')('freecc:cntr:challenges'), Challenge = require('./../models/Challenge'); +var highestChallengeNumber = 53; + exports.returnChallenge = function(req, res, next) { var challengeNumber = parseInt(req.params.challengeNumber) || 0; var verbs = [ @@ -33,7 +35,7 @@ exports.returnChallenge = function(req, res, next) { "Establish your alibi for the past two hours", "Prove to mom that computers aren't just for games" ]; - if (challengeNumber > 53) { challengeNumber = 0; } + if (challengeNumber > highestChallengeNumber) { challengeNumber = 0; } Challenge.find({}, null, { sort: { challengeNumber: 1 } }, function(err, c) { if (err) { debug('Challenge err: ', err); diff --git a/models/Bonfire.js b/models/Bonfire.js index 10360c40c0..328417da3e 100644 --- a/models/Bonfire.js +++ b/models/Bonfire.js @@ -1,14 +1,27 @@ var mongoose = require('mongoose'); var secrets = require('../config/secrets'); +/** + * + * @type {exports.Schema} + */ + +new Schema({ _id: String }) +var ObjectId = require('mongoose').Types.ObjectId; +var myObjectId = ObjectId.fromString('myhexstring'); var bonfireSchema = new mongoose.Schema({ + name: { type: String, unique: true }, - link: String, - time: String, - bonfireNumber: Number + difficulty: Number, + description: Array, + publicTests: Array, + privateTests: Array, + challengeSeed: String, + bonfireNumber: Number, + number: Number }); module.exports = mongoose.model('Bonfire', bonfireSchema); diff --git a/models/BonfireCompletion.js b/models/BonfireCompletion.js new file mode 100644 index 0000000000..67ff2bb0e9 --- /dev/null +++ b/models/BonfireCompletion.js @@ -0,0 +1,15 @@ +var mongoose = require('mongoose'); +var secrets = require('../config/secrets'); + +var bonfireCompletionSchema = new mongoose.Schema({ + dateCompleted: Number, + camper1: String, + camper2: String, + bonfireNumber: { + bonfireNumber: Number, + bonfireId: ObjectId + }, + solution: String +}); + +module.exports = mongoose.model('BonfireCompletion', bonfireCompletionSchema); diff --git a/models/User.js b/models/User.js index ab217b2ad7..3b821416fe 100644 --- a/models/User.js +++ b/models/User.js @@ -3,356 +3,356 @@ var crypto = require('crypto'); var mongoose = require('mongoose'); var userSchema = new mongoose.Schema({ - email: { - type: String, - lowercase: true, - unique: true, - trim: true, - sparse: true - }, - password: String, - facebook: String, - twitter: String, - google: String, - github: String, - linkedin: String, - tokens: Array, - points: { - type: Number, - default: 0 - }, - challengesCompleted: { type: Array, default: [] }, - challengesHash: { - 0: { - type: Number, - default: 0 - }, - 1: { - type: Number, - default: 0 - }, - 2: { - type: Number, - default: 0 - }, - 3: { - type: Number, - default: 0 - }, - 4: { - type: Number, - default: 0 - }, - 5: { - type: Number, - default: 0 - }, - 6: { - type: Number, - default: 0 - }, - 7: { - type: Number, - default: 0 - }, - 8: { - type: Number, - default: 0 - }, - 9: { - type: Number, - default: 0 - }, - 10: { - type: Number, - default: 0 - }, - 11: { - type: Number, - default: 0 - }, - 12: { - type: Number, - default: 0 - }, - 13: { - type: Number, - default: 0 - }, - 14: { - type: Number, - default: 0 - }, - 15: { - type: Number, - default: 0 - }, - 16: { - type: Number, - default: 0 - }, - 17: { - type: Number, - default: 0 - }, - 18: { - type: Number, - default: 0 - }, - 19: { - type: Number, - default: 0 - }, - 20: { - type: Number, - default: 0 - }, - 21: { - type: Number, - default: 0 - }, - 22: { - type: Number, - default: 0 - }, - 23: { - type: Number, - default: 0 - }, - 24: { - type: Number, - default: 0 - }, - 25: { - type: Number, - default: 0 - }, - 26: { - type: Number, - default: 0 - }, - 27: { - type: Number, - default: 0 - }, - 28: { - type: Number, - default: 0 - }, - 29: { - type: Number, - default: 0 - }, - 30: { - type: Number, - default: 0 - }, - 31: { - type: Number, - default: 0 - }, - 32: { - type: Number, - default: 0 - }, - 33: { - type: Number, - default: 0 - }, - 34: { - type: Number, - default: 0 - }, - 35: { - type: Number, - default: 0 - }, - 36: { - type: Number, - default: 0 - }, - 37: { - type: Number, - default: 0 - }, - 38: { - type: Number, - default: 0 - }, - 39: { - type: Number, - default: 0 - }, - 40: { - type: Number, - default: 0 - }, - 41: { - type: Number, - default: 0 - }, - 42: { - type: Number, - default: 0 - }, - 43: { - type: Number, - default: 0 - }, - 44: { - type: Number, - default: 0 - }, - 45: { - type: Number, - default: 0 - }, - 46: { - type: Number, - default: 0 - }, - 47: { - type: Number, - default: 0 - }, - 48: { - type: Number, - default: 0 - }, - 49: { - type: Number, - default: 0 - }, - 50: { - type: Number, - default: 0 - }, - 51: { - type: Number, - default: 0 - }, - 52: { - type: Number, - default: 0 - }, - 53: { - type: Number, - default: 0 - }, - 54: { - type: Number, - default: 0 - }, - 55: { - type: Number, - default: 0 - }, - 56: { - type: Number, - default: 0 - }, - 57: { - type: Number, - default: 0 - }, - 58: { - type: Number, - default: 0 - }, - 59: { - type: Number, - default: 0 - } - }, - profile: { - username: { - type: String, - unique: true, - sparse: true, - lowercase: true, - trim: true - }, - bio: { - type: String, - defaults: '' - }, - name: { - type: String, - default: '' - }, - gender: { - type: String, - default: '' - }, - location: { - type: String, - default: '' - }, - picture: { - type: String, - default: '' - }, - linkedinProfile: { - type: String, - default: '' - }, - githubProfile: { - type: String, - default: '' - }, - coderbyteProfile: { - type: String, - default: '' - }, - codepenProfile: { - type: String, - default: '' - }, - twitterHandle: { - type: String, - default: '' - } - }, - portfolio: { - website1Link: { - type: String, - default: '' - }, - website1Title: { - type: String, - default: '' - }, - website1Image: { - type: String, - default: '' - }, - website2Link: { - type: String, - default: '' - }, - website2Title: { - type: String, - default: '' - }, - website2Image: { - type: String, - default: '' - }, - website3Link: { - type: String, - default: '' - }, - website3Title: { - type: String, - default: '' - }, - website3Image: { - type: String, - default: '' - } - }, - resetPasswordToken: String, - resetPasswordExpires: Date + email: { + type: String, + lowercase: true, + unique: true, + trim: true, + sparse: true + }, + password: String, + facebook: String, + twitter: String, + google: String, + github: String, + linkedin: String, + tokens: Array, + points: { + type: Number, + default: 0 + }, + challengesCompleted: { type: Array, default: [] }, + challengesHash: { + 0: { + type: Number, + default: 0 + }, + 1: { + type: Number, + default: 0 + }, + 2: { + type: Number, + default: 0 + }, + 3: { + type: Number, + default: 0 + }, + 4: { + type: Number, + default: 0 + }, + 5: { + type: Number, + default: 0 + }, + 6: { + type: Number, + default: 0 + }, + 7: { + type: Number, + default: 0 + }, + 8: { + type: Number, + default: 0 + }, + 9: { + type: Number, + default: 0 + }, + 10: { + type: Number, + default: 0 + }, + 11: { + type: Number, + default: 0 + }, + 12: { + type: Number, + default: 0 + }, + 13: { + type: Number, + default: 0 + }, + 14: { + type: Number, + default: 0 + }, + 15: { + type: Number, + default: 0 + }, + 16: { + type: Number, + default: 0 + }, + 17: { + type: Number, + default: 0 + }, + 18: { + type: Number, + default: 0 + }, + 19: { + type: Number, + default: 0 + }, + 20: { + type: Number, + default: 0 + }, + 21: { + type: Number, + default: 0 + }, + 22: { + type: Number, + default: 0 + }, + 23: { + type: Number, + default: 0 + }, + 24: { + type: Number, + default: 0 + }, + 25: { + type: Number, + default: 0 + }, + 26: { + type: Number, + default: 0 + }, + 27: { + type: Number, + default: 0 + }, + 28: { + type: Number, + default: 0 + }, + 29: { + type: Number, + default: 0 + }, + 30: { + type: Number, + default: 0 + }, + 31: { + type: Number, + default: 0 + }, + 32: { + type: Number, + default: 0 + }, + 33: { + type: Number, + default: 0 + }, + 34: { + type: Number, + default: 0 + }, + 35: { + type: Number, + default: 0 + }, + 36: { + type: Number, + default: 0 + }, + 37: { + type: Number, + default: 0 + }, + 38: { + type: Number, + default: 0 + }, + 39: { + type: Number, + default: 0 + }, + 40: { + type: Number, + default: 0 + }, + 41: { + type: Number, + default: 0 + }, + 42: { + type: Number, + default: 0 + }, + 43: { + type: Number, + default: 0 + }, + 44: { + type: Number, + default: 0 + }, + 45: { + type: Number, + default: 0 + }, + 46: { + type: Number, + default: 0 + }, + 47: { + type: Number, + default: 0 + }, + 48: { + type: Number, + default: 0 + }, + 49: { + type: Number, + default: 0 + }, + 50: { + type: Number, + default: 0 + }, + 51: { + type: Number, + default: 0 + }, + 52: { + type: Number, + default: 0 + }, + 53: { + type: Number, + default: 0 + }, + 54: { + type: Number, + default: 0 + }, + 55: { + type: Number, + default: 0 + }, + 56: { + type: Number, + default: 0 + }, + 57: { + type: Number, + default: 0 + }, + 58: { + type: Number, + default: 0 + }, + 59: { + type: Number, + default: 0 + } + }, + profile: { + username: { + type: String, + unique: true, + sparse: true, + lowercase: true, + trim: true + }, + bio: { + type: String, + defaults: '' + }, + name: { + type: String, + default: '' + }, + gender: { + type: String, + default: '' + }, + location: { + type: String, + default: '' + }, + picture: { + type: String, + default: '' + }, + linkedinProfile: { + type: String, + default: '' + }, + githubProfile: { + type: String, + default: '' + }, + coderbyteProfile: { + type: String, + default: '' + }, + codepenProfile: { + type: String, + default: '' + }, + twitterHandle: { + type: String, + default: '' + } + }, + portfolio: { + website1Link: { + type: String, + default: '' + }, + website1Title: { + type: String, + default: '' + }, + website1Image: { + type: String, + default: '' + }, + website2Link: { + type: String, + default: '' + }, + website2Title: { + type: String, + default: '' + }, + website2Image: { + type: String, + default: '' + }, + website3Link: { + type: String, + default: '' + }, + website3Title: { + type: String, + default: '' + }, + website3Image: { + type: String, + default: '' + } + }, + resetPasswordToken: String, + resetPasswordExpires: Date }); /** @@ -360,19 +360,19 @@ var userSchema = new mongoose.Schema({ */ userSchema.pre('save', function(next) { - var user = this; + var user = this; - if (!user.isModified('password')) { return next(); } + if (!user.isModified('password')) { return next(); } - bcrypt.genSalt(5, function(err, salt) { - if (err) { return next(err); } + bcrypt.genSalt(5, function(err, salt) { + if (err) { return next(err); } - bcrypt.hash(user.password, salt, null, function(err, hash) { - if (err) { return next(err); } - user.password = hash; - next(); + bcrypt.hash(user.password, salt, null, function(err, hash) { + if (err) { return next(err); } + user.password = hash; + next(); + }); }); - }); }); /** @@ -380,10 +380,10 @@ userSchema.pre('save', function(next) { */ userSchema.methods.comparePassword = function(candidatePassword, cb) { - bcrypt.compare(candidatePassword, this.password, function(err, isMatch) { - if (err) { return cb(err); } - cb(null, isMatch); - }); + bcrypt.compare(candidatePassword, this.password, function(err, isMatch) { + if (err) { return cb(err); } + cb(null, isMatch); + }); }; /** @@ -391,18 +391,18 @@ userSchema.methods.comparePassword = function(candidatePassword, cb) { */ userSchema.methods.gravatar = function(size) { - if (!size) { size = 200; } + if (!size) { size = 200; } - if (!this.email) { - return 'https://gravatar.com/avatar/?s=' + size + '&d=retro'; - } + if (!this.email) { + return 'https://gravatar.com/avatar/?s=' + size + '&d=retro'; + } - var md5 = crypto - .createHash('md5') - .update(this.email) - .digest('hex'); + var md5 = crypto + .createHash('md5') + .update(this.email) + .digest('hex'); - return 'https://gravatar.com/avatar/' + md5 + '?s=' + size + '&d=retro'; + return 'https://gravatar.com/avatar/' + md5 + '?s=' + size + '&d=retro'; }; module.exports = mongoose.model('User', userSchema); diff --git a/seed_data/bonfires.json b/seed_data/bonfires.json new file mode 100644 index 0000000000..6c43f02e31 --- /dev/null +++ b/seed_data/bonfires.json @@ -0,0 +1,225 @@ +{ + "name": "Palindrome Tester", + "difficulty": 1, // should be a range from 1-5 + "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" + ], + "publicTests": [ + "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(\"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" +} + +/* +"aaa48de84e1ecc7c742e1124" +"ff0395860f5d3034dc0bfc94" +"7123c8c441eddfaeb5bdef0d" +"c3a4d278b9e760a0ffe8321f" +"aceca143b92049a4392a859e" +"ce9394f67d413734758e27e4" +"1369953ef6f03098cb60e2f7" +"fa229986db0716662e63163a" +"0a6207dfc9ac12f223b4e686" +"2e538b339cbcb7437e61d71f" +"21de1104b8ea7c6a382442d9" +"0aa3497514cb1d8a0ed04933" +"3a45068415f5a20a5d4a2039" +"6a73ec9b86f0e742f6c6ea76" +"06dc21940748badcdb29561e" +"0f2341ef36740b5c2b9d830c" +"dc4cc7ce1fd0418859b10e0b" +"1fcda9b5e0bf502c8b770374" +"482879c42188cde1f9ad3d8f" +"3d680bd03fd291028af57f4f" +"6b444fe5aa97359238bd3c0d" +"72d6ad274e72ffcd399e05cb" +"e864a710647bb6883c9ec617" +"024dcd8cc0178de7daa4f59f" +"ded24fb937a3fd60dc624677" +"9ad4c3b2aebe7282e973e5df" +"d16c66ecc656c82899a2d427" +"ee3e4bf39b840609dd88f5af" +"9a10d27eb6ab6f5030bdbcd9" +"b4cca5ecdeca1eebc0dc4183" +"ccdf1ef407864df62b03331e" +"1baa0329f02e41a5517b11a6" +"b5b33e5ecf6c02a5780ac419" +"84b690f53cd6cbbbf4a361f5" +"4e3b1b9d41ff11bdf3722ffe" +"1fd45e64c43cd640abcf8a76" +"c8bd32cdd943c88fb8a74934" +"9e5440269d09b71f07002333" +"5080016b8b68f40f7476c341" +"f762d45cc870d9f18c6b7024" +"cf21358ab1245c7033504b42" +"41eff7cb0f2fd8ec9e0cbf68" +"a344c63de6a00feea5c541e0" +"7ab3c18c0815d7b1f02e8768" +"a6f36e4387e2e1e25af4e000" +"9064af1431c1ff3aaa15a0d6" +"50946066aaba43a294155ab5" +"70e82e77857317d6936ecdcc" +"dc644dc20d5b02ffd7c8cc94" +"92af1e9f1813619d820dec4d" +"9d4a077fdaaa24b78a54cee9" +"cfd5fa7aea14fb294bd4f5ff" +"068541b6c5130ca541d6c05c" +"39f4d1f12142d583b0318265" +"4a201b8fa69d11cb669dca8c" +"6fa6bba2e334dd2c9e5a6911" +"30ff082b6a28558f16743fea" +"afed31c4dc2ddf056e263acb" +"b2431ecf36f0b780959aa03d" +"54e42938ab6fa923a5fbfbff" +"48d50e3ff5e96f152d912ebf" +"6c7aad2ee996132f76630c05" +"2705f0482774977fa9b5c7bc" +"c09d6682c7a144d9afd4bfab" +"1a0a30c55dd9bc2fff4e2aac" +"30c22b502e80afd144d79120" +"8f882989bbc98c68b6c7347e" +"888bf771b63a5f64e6b696ed" +"959aa13a2e6439fd5d29c5fe" +"d03d311ca64bf59a2404dcd0" +"7a650f3e4308a097d7883b1f" +"54c207808ac349fa34ed24a9" +"3cb12e3ea31fe15ba9d234e5" +"0d9f8123e52f791ae172f627" +"387518b1bb96bd918e7d0b91" +"27198d8918c9802ac0b06a58" +"7a519a552f723c6b1fdc9389" +"4240096651a50f888765ed60" +"8ba94f78cc44cfb82b3678d2" +"1cf7c3bda6ec7952923bc90f" +"cd54811e976edbc798a87c24" +"e4ee17912f5d7d80d41dc52d" +"572346dd1874a0c749c3a031" +"cf700031502680580ff25980" +"7054518832e5c7efde04a58c" +"7716c6b6a3dcc9c5df79a262" +"f4d1084c692f5a07c25a1b47" +"817b80892a78fc6f83eab4eb" +"ae0e0adda6d063d3fd2c9499" +"33184c427ecaab77b5332521" +"c6c4da707e3eed987eb65ba6" +"40f9801913c0cb9800960bf7" +"af11cf78e8340f172ba76bbe" +"c1daea28b5996b8e8800e300" +"7312b3234b5f2f50887597b9" +"3e4361c5356b30f8ce833268" +"e6fc8827b9aa96fc91035ac2" +"11658fe51b23319533c72106" +"34207fe236870fd855392ef6" +"dc970a2b17aa1432d180d078" +"2f1686ad711b5ac3d98905b5" +"ed20f4bf782e10ec26c7b3b1" +"cf4d6241df36b0bbcea401e2" +"97e414eb00338bd7bd5d1b31" +"bcfebb743729d4fc51b0db49" +"52782c1eaa15e050ac748b18" +"57f65a6cd2eb0a2745fc90ee" +"fcc569e80808c6cd84c839cc" +"2447f8e0e3ccfd895a619695" +"600687fe6332b2e2b20d6a84" +"0f8a972361baddb3ac64b6d9" +"f768594ab352cf8e2282b615" +"3163b25e25b0d6859df17751" +"c73d68f0cf77aa113337fcde" +"cc16163137f13f70decbcb5c" +"4adbf6c7ac2004ee8ae20f55" +"c2779f78a0e57dcee471cefd" +"bf44903cd2fca4ae4daf0818" +"ca8013372d58365e21bd0428" +"e308901ca272ad447dca965a" +"ec8cefe29832cd726185119f" +"36bf51da3f32b1e9550f3b15" +"aefff6dffdf534a6c9601f70" +"ce237971a71127f9ce747232" +"99f4d97fae16ccbeb8c26d46" +"c9f6480328ec4b63b1034826" +"ce10bb6e80b09533cb21c9a5" +"311a54aaf062b29422ac0b02" +"b2073bec873b295c04e9fb7e" +"7b7d94035d63c9c0598b242b" +"e19e9a0487f1bd3eabdb777c" +"eeafe5169a2afd9ce3979698" +"96c7a1f9fb73468fdb770034" +"77e607be2498160d3ceeff60" +"c784fa6b1fd7d9aedb05b607" +"a76319bca87e0b57bc79064f" +"a08db36785c51e5b92a6e92f" +"0933ab4a366d57fd1f1c0a48" +"17663f17a835cfe0bca64f4a" +"aee8323d1de634fc42c11d90" +"682044caf09a068e26c11cab" +"1346fdbe3c6fcb808b99cdf6" +"26fd8f47fe4791e2dd07b2e0" +"b1da27dd129216c2ead2e162" +"618adebe192e896eb1501708" +"2628d9eeb38db68c0b255a75" +"1fb78eda5deb8972cc357a9b" +"2fdebb85a401de75bb580a02" +"c59eae24bee36f63c938723d" +"fb66b55d5617e27ca64836a3" +"55994022872e01fd41d8ec7b" +"53ae83b5490e1cf55625ff3d" +"c44975deeb67b96e6cc37eb5" +"94c64d5ff48ca6487f5e0b07" +"e34e7c1a3d70678955a5df8e" +"6426d30a923dec6377132c47" +"d67811849354ded9d34c9ece" +"01e7ae81207cfd230cb02747" +"e24558477f94bcdd82f16ebe" +"4370f6dcc2f53bd5abed7899" +"679b1145cd3072fbcd513bcb" +"4dafd3fd84e7a337ef3e9933" +"2aca3d41cb148603b4a2d70b" +"5e5aa8c960d024109543c577" +"c5f5f313c8a7056bbcdb7639" +"a7b2aaa4cf85fce98cdeb314" +"e556c0d14bc0ce9cc7bde0ca" +"922a8284880a7c879d846f90" +"b146cf2fbf206ca48687e9b6" +"fbdc52bb7c7620bd4508e5a3" +"23d79a262a81459e75576cc2" +"a26721706d3b9f971cef3ce6" +"fb3801ed1b056a3ab4bbfdc1" +"d5cafae617f1485826de335c" +"e9650dfc8b570f9d33381012" +"453c804c7ce82e83305cd751" +"3eaab01bdd1393be8d461777" +"2b6d9ddd4754b71d92ed31b7" +"2338e9af6acab9fcf5327f6a" +"588e7405c30c346ed2ea5e44" +"eec8837994054fb2043b6166" +"0877406795956ca9eb13fea1" +"1dea30e852067eec48a24035" +"ee716ce45ea812167ed2497a" +"9621d5aeaf8de9b2f58977bd" +"e9bb838723083bac7f83d602" +"ef64da08bbe787891d47c31b" +"e01b6616cc6cf7819172f7f3" +"17c821c34fca587daec981fc" +"d0c4b7153dcb3e6af47bcd98" +"5188eb00680051c35cd6e0f0" +"9fc7b68e736a1f4931226ad8" +"b5eac897471f125224a3e594" +"c1d0f890a02c85a9320f96d5" +"7e3b1ca1b1b1e990367f0cc2" +"bff5ff77174c43f7c681e0bd" +"ddeb794121937d07a887c9e6" +"9db902e930f25fbacc125087" +"4f82d277b47ae9c98095f068" +"24f999491fa46cd194c7fd35" +*/ \ No newline at end of file From 74291d2299d931cc2d32b28b9317e079f0b5c34e Mon Sep 17 00:00:00 2001 From: Nathan Leniz Date: Wed, 21 Jan 2015 23:54:59 -0500 Subject: [PATCH 02/12] More bonfire improvements. Removed redundant console statements, improved test scraping, comment scraping included, better reset behavior --- models/Bonfire.js | 7 +- models/BonfireCompletion.js | 5 +- models/User.js | 3 +- public/js/lib/bonfire/bonfireFramework.js | 193 +++++++++ .../bonfire/{bonfire.js => bonfireInit.js} | 7 +- public/js/lib/bonfire/framework.js | 378 ------------------ .../{plugin_v0.1.1.js => plugin_v0.1.2.js} | 0 seed_data/bonfires.json | 47 ++- seed_data/seed_challenges.js | 21 +- views/bonfire/bonfire.jade | 4 +- 10 files changed, 250 insertions(+), 415 deletions(-) create mode 100644 public/js/lib/bonfire/bonfireFramework.js rename public/js/lib/bonfire/{bonfire.js => bonfireInit.js} (88%) delete mode 100644 public/js/lib/bonfire/framework.js rename public/js/lib/bonfire/{plugin_v0.1.1.js => plugin_v0.1.2.js} (100%) diff --git a/models/Bonfire.js b/models/Bonfire.js index 328417da3e..f7213c5872 100644 --- a/models/Bonfire.js +++ b/models/Bonfire.js @@ -6,9 +6,9 @@ var secrets = require('../config/secrets'); * @type {exports.Schema} */ -new Schema({ _id: String }) -var ObjectId = require('mongoose').Types.ObjectId; -var myObjectId = ObjectId.fromString('myhexstring'); +//new Schema({ _id: String }) +//var ObjectId = require('mongoose').Types.ObjectId; +//var myObjectId = ObjectId.fromString('myhexstring'); var bonfireSchema = new mongoose.Schema({ name: { @@ -21,7 +21,6 @@ var bonfireSchema = new mongoose.Schema({ privateTests: Array, challengeSeed: String, bonfireNumber: Number, - number: Number }); module.exports = mongoose.model('Bonfire', bonfireSchema); diff --git a/models/BonfireCompletion.js b/models/BonfireCompletion.js index 67ff2bb0e9..671c7ff4d9 100644 --- a/models/BonfireCompletion.js +++ b/models/BonfireCompletion.js @@ -3,11 +3,10 @@ var secrets = require('../config/secrets'); var bonfireCompletionSchema = new mongoose.Schema({ dateCompleted: Number, - camper1: String, - camper2: String, + completedWith: String, bonfireNumber: { bonfireNumber: Number, - bonfireId: ObjectId + bonfireId: String }, solution: String }); diff --git a/models/User.js b/models/User.js index 3b821416fe..582bd551e5 100644 --- a/models/User.js +++ b/models/User.js @@ -352,7 +352,8 @@ var userSchema = new mongoose.Schema({ } }, resetPasswordToken: String, - resetPasswordExpires: Date + resetPasswordExpires: Date, + bonfires: Array }); /** diff --git a/public/js/lib/bonfire/bonfireFramework.js b/public/js/lib/bonfire/bonfireFramework.js new file mode 100644 index 0000000000..68ad16b0be --- /dev/null +++ b/public/js/lib/bonfire/bonfireFramework.js @@ -0,0 +1,193 @@ +var widgets = []; +var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("codeEditor"), { + lineNumbers: true, + mode: "javascript", + theme: 'monokai', + runnable: true, + lint: true, + matchBrackets: true, + autoCloseBrackets: true, + cursorHeight: 0.85, + scrollbarStyle: 'null', + lineWrapping: true, + gutters: ["CodeMirror-lint-markers"], + onKeyEvent: doLinting, + extraKeys : { + "Ctrl-Enter" : function() { + bonfireExecute(); + return false; + } + } +}); +var editor = myCodeMirror; +myCodeMirror.setValue('/*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' + +'test();'); +//myCodeMirror.setSize("100%", "100%"); + +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. Console.log() -type statements\n' + + ' * will appear in your browser\'s 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 doLinting = function () { + 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 + })); + } + }); +}; + +var replaceQuotesInTests = function() { + tests.forEach(function(elt, ix, arr) { + arr[ix].text = arr[ix].text.replace(/\"/g,'\''); + }); +}; + +var tests; +var testSalt = Math.random(); + +var scrapeTests = function(userJavaScript) { + var counter = 0; + var regex = new RegExp(/(expect(\s+)?\(.*\;)|(assert(\s+)?\(.*\;)|(assert\.\w.*\;)/); + 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 (!tests) tests = []; + tests.push({"text": match[0], "line": counter, "err": null}); + counter++; + match = regex.exec(userJavaScript); + } + if (tests) replaceQuotesInTests(); + 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, ''); +} + +$('#submitButton').on('click', function () { + bonfireExecute(); +}); + +function bonfireExecute() { + tests = null; + $('#codeOutput').empty(); + var userJavaScript = myCodeMirror.getValue(); + userJavaScript = removeComments(userJavaScript); + userJavaScript = scrapeTests(userJavaScript); + 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 pushed = false; +var createTestDisplay = function() { + if (pushed) { + tests.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') + if (test.err != null) { + $(testDoc) + .html(test.text + "\n" + test.err) + .css("background-color", 'rgba(255,0,0,.2)') + .prependTo($('#testSuite')); + } else { + $(testDoc) + .html(test.text) + .css('background-color', 'rgba(0,255,0,.2)') + .appendTo($('#testSuite')); + } + }; +}; +var assert = chai.assert; +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) { + pushed = false; + $('#testSuite').children().remove(); + if (err && tests) { + tests = [{text:"Program Execution Failure", err: "No tests were run."}]; + createTestDisplay(); + } else if (tests) { + tests.push(false); + pushed = true; + tests.forEach(function(test, ix, arr){ + try { + if (test) { + var output = eval(reassembleTest(test, data)); + } + } catch(error) { + console.log(error); + arr[ix].err = error.name + ":" + error.message; + console.log(arr); + } finally { + if (!test) { + //window.setTimeout(function() {createTestDisplay()},2000); + createTestDisplay(); + } + } + }); + } +}; \ No newline at end of file diff --git a/public/js/lib/bonfire/bonfire.js b/public/js/lib/bonfire/bonfireInit.js similarity index 88% rename from public/js/lib/bonfire/bonfire.js rename to public/js/lib/bonfire/bonfireInit.js index 19be8fb116..ee885599f9 100644 --- a/public/js/lib/bonfire/bonfire.js +++ b/public/js/lib/bonfire/bonfireInit.js @@ -46,6 +46,7 @@ var api = { reset(); } else { print(null, data); + reset(); } } }; @@ -66,18 +67,20 @@ var requests; // (re)initializes the plugin var reset = function() { requests = 0; - plugin = new jailed.Plugin(path+'plugin_v0.1.1.js', api); + plugin = new jailed.Plugin(path+'plugin_v0.1.2.js', api); plugin.whenDisconnected( function() { // give some time to handle the last responce setTimeout( function() { endLoading(); - codeOutput.setValue('Infinite loop detected!'); + console.log("resetting on fatal plugin error"); + codeOutput.setValue('Infinite loop or fatal error!'); reset(); }, 10); }); }; + // initialize everything var plugin = null; diff --git a/public/js/lib/bonfire/framework.js b/public/js/lib/bonfire/framework.js deleted file mode 100644 index 441cfe9305..0000000000 --- a/public/js/lib/bonfire/framework.js +++ /dev/null @@ -1,378 +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, - cursorHeight: 0.85, - scrollbarStyle: 'null', - lineWrapping: true, - gutters: ["CodeMirror-lint-markers"], - onKeyEvent: doLinting, - extraKeys : { - "Ctrl-Enter" : function() { - bonfireExecute(); - return false; - } - } -}); -var editor = myCodeMirror; -myCodeMirror.setValue('/*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' + -'test();'); -//myCodeMirror.setSize("100%", "100%"); - -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. Console.log() -type statements\n' + - ' * will appear in your browser\'s 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 doLinting = function () { - 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 - })); - } - }); -}; - -var replaceQuotesInTests = function() { - tests.forEach(function(elt, ix, arr) { - arr[ix].text = arr[ix].text.replace(/\"/g,'\''); - }); -}; - -var tests; -var testSalt = Math.random(); - -var scrapeTests = function(userJavaScript) { - var counter = 0; - var regex = new RegExp(/(expect(\s+)?\(.*\;)|(assert(\s+)?\(.*\;)|(assert\.\w.*\;)/); - 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 (!tests) tests = []; - tests.push({"text": match[0], "line": counter, "err": null}); - counter++; - match = regex.exec(userJavaScript); - } - replaceQuotesInTests(); - return userJavaScript; -}; - -$('#submitButton').on('click', function () { - bonfireExecute(); -}); - -function bonfireExecute() { - tests = undefined; - $('#codeOutput').empty(); - var userJavaScript = myCodeMirror.getValue(); - userJavaScript = scrapeTests(userJavaScript); - submit(userJavaScript, function(cls, message) { - if (cls) { - codeOutput.setValue(message.error); - runTests('Error', null); - } else { - codeOutput.setValue(message.output); - runTests(null, message); - } - }); -} - -var pushed = false; -var createTestDisplay = function() { - if (pushed) { - tests.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') - if (test.err != null) { - $(testDoc) - .html(test.text + "\n" + test.err) - .css("background-color", 'rgba(255,0,0,.2)') - .prependTo($('#testSuite')); - } else { - $(testDoc) - .html(test.text) - .css('background-color', 'rgba(0,255,0,.2)') - .appendTo($('#testSuite')); - } - }; -}; -var assert = chai.assert; -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) { - pushed = false; - $('#testSuite').children().remove(); - if (err && tests) { - tests = [{text:"Program Execution Failure", err: "No tests were run."}]; - createTestDisplay(); - } else if (tests) { - tests.push(false); - pushed = true; - tests.forEach(function(test, ix, arr){ - try { - if (test) { - var output = eval(reassembleTest(test, data)); - } - } catch(error) { - console.log(error); - arr[ix].err = error.name + ":" + error.message; - console.log(arr); - } finally { - if (!test) { - //window.setTimeout(function() {createTestDisplay()},2000); - createTestDisplay(); - } - } - }); - } -}; - - -// var assert = chai.assert; -// var testResults = []; -// $('#runTests').on('click', function () { -// clearTestOutput(); -// var testCaseList = [], -// jsCode = myCodeMirror.getValue(); -// getTestSuite().each(function () { -// testCaseList.push([$(this).data("input"), $(this).data("output"), $(this)]); -// }); -// testCaseList.forEach(function (input) { -// var testCode = jsCode + "\n\n" + input[0] + ";"; -// //TODO use plugin for this with the rest as a callback? -// var output = eval(testCode); -// testEquality(output, input); -// }); -// // some timeout here? -// if (testResults.length === testCaseList.length) { -// var sum = testResults.reduce(function (a, b) { -// return a + b -// }); -// prependTestOutput("======Testing========\n" + Math.round(100 * sum / testResults.length) + "% tests passed\n"); -// } -// }); -// var testEquality = function (output, input) { -// try { -// switch (typeof output) { -// case 'object': -// assert.deepEqual(output, input[1]); -// break; -// case 'string': -// assert(output.localeCompare(input[1])); -// break -// default: -// assert.equal(output, input[1]); -// } -// appendTestOutput("\n" + createTestString(input[0], input[1]) + "\nTest passed!\n"); -// input[2].css("background-color", "rgba(0,255,0,.2)"); -// testResults.push(1); -// } catch (err) { -// input[2].css("background-color", "rgba(255,0,0,.2)"); -// appendTestOutput(createTestString(input[0], input[1])); -// appendTestOutput("Test failed: \nOutput was: " + output + "\nType of output was: " + (typeof output)); -// testResults.push(0); -// } -// }; -//$('#sideBySide').on('click', function () { -// var main = $('#mainEditorPanel'); -// if (main.hasClass('col-md-12')) { -// replaceColClz(main, 'md', 12, 6); -// replaceColClz(main, 'sm', 12, 6); -// $(this).text("Original Layout") -// } else { -// replaceColClz(main, 'md', 6, 12); -// replaceColClz(main, 'sm', 6, 12); -// $(this).text("Tests side by side") -// } -//}); -//var replaceColClz = function (elt, size, oldVal, newVal) { -// elt.removeClass('col-' + size + '-' + oldVal); -// elt.addClass('col-' + size + '-' + newVal); -//}; -//var getTestSuite = function () { -// return $('#testSuite').find('li'); -//}; -//var clearTestOutput = function () { -// testOutput.setValue(""); -//}; -var appendTestOutput = function (msg) { - writeToTest(msg, CodeMirror.Pos(editor.lastLine())); -}; -var prependTestOutput = function (msg) { - writeToTest(msg, CodeMirror.Pos(editor.firstLine())); -}; -var writeToTest = function (msg, location) { - testOutput.replaceRange("\n" + msg, location); -}; -//$('#addTest').on('click', function () { -// var functionName = $('#testFunctionName option:selected').text(); -// var inputs = []; -// var output; -// $('#testInputs').find('input').each(function () { -// if ($(this).val() != null && $(this).val().length !== 0) { -// inputs.push($(this).val()); -// } else { -// //var keepGoing = prompt("You have submitted a test with empty input. Enter yes to continue."); -// if (/yes/.test(keepGoing.toLowerCase())) { -// inputs.push($(this).val()); -// } else { -// return; -// } -// } -// }); -// output = $('#testOutputs').find('input').val(); -// var functionCall = functionName + "(" + inputs.join(",") + ")"; -// var test = document.createElement("li"); -// $(test) -// .addClass('list-group-item') -// .addClass('well') -// .addClass('well-sm') -// .attr({"data-input": functionCall, "data-output": output}) -// .html(createTestString(functionCall, output)) -// .appendTo($('#testSuite')); -// var closeLink = document.createElement('i'); -// var closeSpan = document.createElement('span'); -// $(closeSpan) -// .addClass("glyphicon glyphicon-remove-sign") -// //.css("float", "right") -// .click(function () { -// //var input = prompt("This will remove the test permanently.\n If you want to do this, type delete"); -// if (/delete/.test(input.toLowerCase())) { -// $(this).parent().remove(); -// } -// }).appendTo($(test)); -// //blank out the form -// $("#testCreateForm").find("input[type=text]").val(""); -//}); -//var createTestString = function (inputs, output) { -// return "Input: " + inputs + "\nExpect:" + output; -//}; -//var testOutput = CodeMirror.fromTextArea(document.getElementById("testOutput"), { -// lineNumbers: false, -// mode: "javascript", -// theme: 'monokai', -// readOnly: 'nocursor' -//}); -//testOutput.setSize("100%", 200); -//var createOptions = function (re, code) { -// var m = re.exec(code); -// while (m != null) { -// var functionName = m[1]; -// if (functionName !== undefined) { -// var option = document.createElement('option'); -// $(option) -// .html(functionName) -// .attr({"data-args": m[2]}) -// .appendTo($('#testFunctionName')); -// } -// m = re.exec(code); -// } -//}; -// $('#testFunctionName').on('change', function () { -// $('#testInputs').children().remove(); -// $('#testOutputs').children().remove(); -// var args = $('#testFunctionName option:selected').data("args"); -// var argArray = args.split(","); -// argArray.forEach(function (arg) { -// if (arg.length > 0) { -// createInputField('#testInputs', arg); -// } -// }); -// createInputField('#testOutputs', 'Expected output'); -// }); -// var createInputField = function (className, arg) { -// var inputDiv = document.createElement('div'); -// $(inputDiv) -// .addClass("control-group") -// .appendTo($(className)); -// var inputLabel = document.createElement('label'); -// $(inputLabel) -// .attr("for", "inputs") -// .html(arg) -// .addClass("col-xs-4 control-label") -// .appendTo($(inputDiv)); -// var textDiv = document.createElement('div'); -// $(textDiv) -// .addClass("col-xs-8 controls") -// .appendTo($(inputDiv)); -// var inputArea = document.createElement('input'); -// $(inputArea) -// .attr("type", "text") -// .addClass("form-control") -// .appendTo($(inputDiv)); -// $(document.createElement("br")).appendTo($(textDiv)); -// }; -// $('#testFunctionName').on('focus', function () { -// $('#testFunctionName').children().remove(); -// var blankOpt = document.createElement("option"); -// $(blankOpt).addClass("selected").appendTo($('#testFunctionName')); -// var re = /function\s+(\w+)\s*\(([\w\s,]*)\)/g; -// var code = myCodeMirror.getValue(); -// createOptions(re, code); -// re = /var (\w+)\s*=\s*function\s*\(([\s\w,]*)\)/g; -// createOptions(re, code); -// }); -// $('#hideTestCreate').on('click', function () { -// var testForm = $("#testCreateForm"); -// if (testForm.is(":visible")) { -// testForm.hide(); -// $(this).text("Create more tests"); -// } else { -// testForm.show(); -// $(this).text("Hide test creation dialogue") -// } -// }); \ No newline at end of file diff --git a/public/js/lib/bonfire/plugin_v0.1.1.js b/public/js/lib/bonfire/plugin_v0.1.2.js similarity index 100% rename from public/js/lib/bonfire/plugin_v0.1.1.js rename to public/js/lib/bonfire/plugin_v0.1.2.js diff --git a/seed_data/bonfires.json b/seed_data/bonfires.json index 6c43f02e31..a6bd8e2f0f 100644 --- a/seed_data/bonfires.json +++ b/seed_data/bonfires.json @@ -1,25 +1,28 @@ -{ - "name": "Palindrome Tester", - "difficulty": 1, // should be a range from 1-5 - "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" - ], - "publicTests": [ - "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(\"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" -} +[ + { + "name": "Palindrome Tester", + "difficulty": 1, // should be a range from 1-5 + "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" + ], + "publicTests": [ + "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(\"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", + "bonfireNumber": 1 + } +] /* "aaa48de84e1ecc7c742e1124" diff --git a/seed_data/seed_challenges.js b/seed_data/seed_challenges.js index 1d0ab0760d..54b9f619bd 100644 --- a/seed_data/seed_challenges.js +++ b/seed_data/seed_challenges.js @@ -1,8 +1,10 @@ require('dotenv').load(); var Challenge = require('../models/Challenge.js'), + Bonfire = require('../models/Bonfire.js'), mongoose = require('mongoose'), secrets = require('../config/secrets'), - challenges = require('./challenges.json'); + challenges = require('./challenges.json'), + bonfires = require('./bonfires.json'); mongoose.connect(secrets.db); @@ -16,8 +18,21 @@ Challenge.remove({}, function(err, data) { if (err) { console.log(err); } else { - console.log('Saved ', data); + console.log('Saved ', data); + } + }); +}); +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); } - process.exit(0); }); }); diff --git a/views/bonfire/bonfire.jade b/views/bonfire/bonfire.jade index 2d29a40a04..2619a1a693 100644 --- a/views/bonfire/bonfire.jade +++ b/views/bonfire/bonfire.jade @@ -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/bonfire.js') + script(src='/js/lib/bonfire/bonfireInit.js') .row #mainEditorPanel.col-sm-12.col-md-7.col-xs-12 .panel.panel-primary.panel-bonfire @@ -36,4 +36,4 @@ block content br ul#testSuite.list-group br - script(src='/js/lib/bonfire/framework.js') \ No newline at end of file + script(src='/js/lib/bonfire/bonfireFramework.js') \ No newline at end of file From 4026ae1c75ebd65338b5a35335c205f062c78fac Mon Sep 17 00:00:00 2001 From: Nathan Leniz Date: Thu, 22 Jan 2015 00:38:39 -0500 Subject: [PATCH 03/12] Cleaning up framework --- public/js/lib/bonfire/bonfireFramework.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/public/js/lib/bonfire/bonfireFramework.js b/public/js/lib/bonfire/bonfireFramework.js index 68ad16b0be..e92455de1e 100644 --- a/public/js/lib/bonfire/bonfireFramework.js +++ b/public/js/lib/bonfire/bonfireFramework.js @@ -7,7 +7,7 @@ var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("codeEditor") lint: true, matchBrackets: true, autoCloseBrackets: true, - cursorHeight: 0.85, + cursorHeight: 1, scrollbarStyle: 'null', lineWrapping: true, gutters: ["CodeMirror-lint-markers"], @@ -22,7 +22,8 @@ var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("codeEditor") var editor = myCodeMirror; myCodeMirror.setValue('/*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' + +'Note that you can also write tests using Chai.js\n' + +' 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' + @@ -32,7 +33,6 @@ myCodeMirror.setValue('/*Welcome to Bonfire, Free Code Camp\'s future CoderByte 'expect(test()).to.be.a("array");\n\n' + 'assert.deepEqual(test(), [1,4,9]);\n\n' + 'test();'); -//myCodeMirror.setSize("100%", "100%"); var codeOutput = CodeMirror.fromTextArea(document.getElementById("codeOutput"), { lineNumbers: false, @@ -50,7 +50,7 @@ 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 doLinting = function () { +function doLinting () { editor.operation(function () { for (var i = 0; i < widgets.length; ++i) editor.removeLineWidget(widgets[i]); @@ -179,12 +179,9 @@ var runTests = function(err, data) { var output = eval(reassembleTest(test, data)); } } catch(error) { - console.log(error); arr[ix].err = error.name + ":" + error.message; - console.log(arr); } finally { if (!test) { - //window.setTimeout(function() {createTestDisplay()},2000); createTestDisplay(); } } From 99dcbd16e51c188554f5690462041285af136a9d Mon Sep 17 00:00:00 2001 From: Nathan Leniz Date: Thu, 22 Jan 2015 03:03:37 -0500 Subject: [PATCH 04/12] Adding should BDD to bonfire --- public/js/lib/bonfire/bonfireFramework.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/public/js/lib/bonfire/bonfireFramework.js b/public/js/lib/bonfire/bonfireFramework.js index e92455de1e..93518ca501 100644 --- a/public/js/lib/bonfire/bonfireFramework.js +++ b/public/js/lib/bonfire/bonfireFramework.js @@ -84,7 +84,7 @@ var testSalt = Math.random(); var scrapeTests = function(userJavaScript) { var counter = 0; - var regex = new RegExp(/(expect(\s+)?\(.*\;)|(assert(\s+)?\(.*\;)|(assert\.\w.*\;)/); + var regex = new RegExp(/(expect(\s+)?\(.*\;)|(assert(\s+)?\(.*\;)|(assert\.\w.*\;)|(.*\.should\..*\;)/); var match = regex.exec(userJavaScript); while (match != null) { var replacement = '//' + counter + testSalt; @@ -107,7 +107,8 @@ function removeComments(userJavaScript) { } function removeLogs(userJavaScript) { - return userJavaScript.replace(/(console\.[\w]+\s*\(.*\;)/g, ''); + //return userJavaScript.replace(/(console\.[\w]+\s*\(.*\;)/g, ''); + return userJavaScript; } $('#submitButton').on('click', function () { @@ -159,6 +160,8 @@ var createTestDisplay = function() { }; var assert = chai.assert; var expect = chai.expect; +var should = chai.should(); +console.log(should); var reassembleTest = function(test, data) { var lineNum = test.line; var regexp = new RegExp("\/\/" + lineNum + testSalt); From 094b93714840e5353458350a1e45cff919ccbc5e Mon Sep 17 00:00:00 2001 From: Nathan Leniz Date: Thu, 22 Jan 2015 11:59:55 -0500 Subject: [PATCH 05/12] Incremental steps towards building the bonfire challenge views --- README.md | 2 +- controllers/bonfire.js | 1 + models/Bonfire.js | 2 +- seed_data/bonfires.json | 1 + seed_data/{seed_challenges.js => seed.js} | 0 views/bonfire/show.jade | 39 +++++++++++++++++++++++ views/partials/challenges.jade | 6 ++-- 7 files changed, 45 insertions(+), 6 deletions(-) rename seed_data/{seed_challenges.js => seed.js} (100%) create mode 100644 views/bonfire/show.jade diff --git a/README.md b/README.md index 411224ae9d..46f1d5b0cf 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ LINKEDIN_SECRET='LINKEDIN APP SECRET' ```bash # Seed your database with the challenges -node seed_data/seed_challenges.js +node seed_data/seed.js # start the application gulp diff --git a/controllers/bonfire.js b/controllers/bonfire.js index 88930d0e6b..42a843c430 100644 --- a/controllers/bonfire.js +++ b/controllers/bonfire.js @@ -64,6 +64,7 @@ exports.returnBonfire = function(req, res, next) { publicTests: c[bonfireNumber].publicTests, privateTests: c[bonfireNumber].privateTests, challengeSeed: c[bonfireNumber].challengeSeed, + challengeEntryPoint: c[bonfireNumber].challengeEntryPoint, cc: req.user ? req.user.bonfiresHash : undefined, points: req.user ? req.user.points : undefined, diff --git a/models/Bonfire.js b/models/Bonfire.js index f7213c5872..3e4bfadde2 100644 --- a/models/Bonfire.js +++ b/models/Bonfire.js @@ -20,7 +20,7 @@ var bonfireSchema = new mongoose.Schema({ publicTests: Array, privateTests: Array, challengeSeed: String, - bonfireNumber: Number, + bonfireNumber: Number }); module.exports = mongoose.model('Bonfire', bonfireSchema); diff --git a/seed_data/bonfires.json b/seed_data/bonfires.json index a6bd8e2f0f..520593ce4f 100644 --- a/seed_data/bonfires.json +++ b/seed_data/bonfires.json @@ -20,6 +20,7 @@ "assert.deepEqual(palindrome(\"nope\"), false);" ], "challengeSeed": "function palindrome(str) {\n // Good luck!\n return true;\n}\n\n", + "challengeEntryPoint": "palindrome(!!!)", "bonfireNumber": 1 } ] diff --git a/seed_data/seed_challenges.js b/seed_data/seed.js similarity index 100% rename from seed_data/seed_challenges.js rename to seed_data/seed.js diff --git a/views/bonfire/show.jade b/views/bonfire/show.jade new file mode 100644 index 0000000000..6b10d316c5 --- /dev/null +++ b/views/bonfire/show.jade @@ -0,0 +1,39 @@ +extends ../layout +block content + .row + .col-sm-12.col-md-12.col-xs-12 + .panel.panel-primary + .panel-heading.text-center #{name} (Level #{difficulty} bonfire) + .panel.panel-body + .col-xs-12.col-sm-10.col-sm-offset-1.col-md-8.col-md-offset-2 + h3 Details + h4 + ol + for sentence in description + li!= sentence + .ten-pixel-break + .btn.btn-success.btn-big.btn-block.all-challenges Show me all the challenges + #complete-dialog.modal(tabindex='-1') + .modal-dialog.animated.zoomIn.fast-animation + .modal-content + .modal-header.challenge-list-header Nicely done! + 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 + - 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") + i.fa.fa-twitter   + = phrase + - else + a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress + #all-challenges-dialog.modal(tabindex='-1') + .modal-dialog.animated.fadeInUp.fast-animation + .modal-content + .modal-header.challenge-list-header Challenges + a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') × + .modal-body + include ../partials/bonfires \ No newline at end of file diff --git a/views/partials/challenges.jade b/views/partials/challenges.jade index cef62c9d57..cb93b2deeb 100644 --- a/views/partials/challenges.jade +++ b/views/partials/challenges.jade @@ -2,7 +2,5 @@ h3 ol(start='0') for challenge in challenges li - a(href="/challenges/#{challenge.challengeNumber}", class="#{ (cc && cc[challenge.challengeNumber] > 0) ? 'strikethrough' : '' }") #{challenge.name} - |   (#{challenge.time} mins) - -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! \ No newline at end of file + a(href="/bonfire/#{bonfire.bonfireNumber}", class="#{ (cc && cc[bonfire.bonfireNumber] > 0) ? 'strikethrough' : '' }") #{bonfire.name} + |   (Level #{bonfire.difficulty}) From 378277f0e1479dfc970aa4d418fb7b288b205ca3 Mon Sep 17 00:00:00 2001 From: Nathan Leniz Date: Thu, 22 Jan 2015 13:20:46 -0500 Subject: [PATCH 06/12] More steps towards building the bonfire challenge interface --- app.js | 8 ++-- controllers/bonfire.js | 37 +++++++++-------- models/Bonfire.js | 4 +- seed_data/seed.js | 1 + views/bonfire/bonfire.jade | 2 +- views/bonfire/show.jade | 74 ++++++++++++++++++---------------- views/partials/bonfires.jade | 43 +++++++++++++++++++- views/partials/challenges.jade | 6 ++- 8 files changed, 111 insertions(+), 64 deletions(-) diff --git a/app.js b/app.js index fea606ba01..5b4a51980f 100644 --- a/app.js +++ b/app.js @@ -251,10 +251,10 @@ app.get( app.all('/account', passportConf.isAuthenticated); app.get('/account/api', userController.getAccountAngular); app.get('/bonfire', bonfireController.index); -//app.get( -// '/bonfire/:bonfireNumber', -// bonfireController.returnBonfire -//); +app.get( + '/bonfire/:bonfireNumber', + bonfireController.returnBonfire +); // Unique Check API route app.get('/api/checkUniqueUsername/:username', userController.checkUniqueUsername); diff --git a/controllers/bonfire.js b/controllers/bonfire.js index 42a843c430..809899100c 100644 --- a/controllers/bonfire.js +++ b/controllers/bonfire.js @@ -48,29 +48,32 @@ exports.returnBonfire = function(req, res, next) { "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, c) { + Bonfire.find({}, null, { sort: { bonfireNumber: 1 } }, function(err, bonfire) { 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, + //title: bonfire.name, + //name: bonfire.name, + //description: bonfire.description, - res.render('bonfires/show', { - title: 'bonfire: ' + c[bonfireNumber].name, - name: c[bonfireNumber].name, - number: bonfireNumber, - difficulty: c[bonfireNumber].difficulty, - description: c[bonfireNumber].description, - publicTests: c[bonfireNumber].publicTests, - privateTests: c[bonfireNumber].privateTests, - challengeSeed: c[bonfireNumber].challengeSeed, - challengeEntryPoint: c[bonfireNumber].challengeEntryPoint, - - 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: c + //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 }); }); }; \ No newline at end of file diff --git a/models/Bonfire.js b/models/Bonfire.js index 3e4bfadde2..c30e132f4f 100644 --- a/models/Bonfire.js +++ b/models/Bonfire.js @@ -6,9 +6,7 @@ var secrets = require('../config/secrets'); * @type {exports.Schema} */ -//new Schema({ _id: String }) -//var ObjectId = require('mongoose').Types.ObjectId; -//var myObjectId = ObjectId.fromString('myhexstring'); + var bonfireSchema = new mongoose.Schema({ name: { diff --git a/seed_data/seed.js b/seed_data/seed.js index 54b9f619bd..dacd5aa11e 100644 --- a/seed_data/seed.js +++ b/seed_data/seed.js @@ -22,6 +22,7 @@ Challenge.remove({}, function(err, data) { } }); }); + Bonfire.remove({}, function(err, data) { if (err) { console.error(err); diff --git a/views/bonfire/bonfire.jade b/views/bonfire/bonfire.jade index 2619a1a693..8fcf04a9ed 100644 --- a/views/bonfire/bonfire.jade +++ b/views/bonfire/bonfire.jade @@ -12,7 +12,7 @@ block content 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/jailed/jailed.js') script(src='/js/lib/bonfire/bonfireInit.js') .row #mainEditorPanel.col-sm-12.col-md-7.col-xs-12 diff --git a/views/bonfire/show.jade b/views/bonfire/show.jade index 6b10d316c5..f4263c81e5 100644 --- a/views/bonfire/show.jade +++ b/views/bonfire/show.jade @@ -1,39 +1,43 @@ extends ../layout 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 - .col-sm-12.col-md-12.col-xs-12 - .panel.panel-primary - .panel-heading.text-center #{name} (Level #{difficulty} bonfire) + #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 + form.code + h3 Details + h5 + ol + for sentence in description + li!= sentence + .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 - .col-xs-12.col-sm-10.col-sm-offset-1.col-md-8.col-md-offset-2 - h3 Details - h4 - ol - for sentence in description - li!= sentence - .ten-pixel-break - .btn.btn-success.btn-big.btn-block.all-challenges Show me all the challenges - #complete-dialog.modal(tabindex='-1') - .modal-dialog.animated.zoomIn.fast-animation - .modal-content - .modal-header.challenge-list-header Nicely done! - 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 - - 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") - i.fa.fa-twitter   - = phrase - - else - a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress - #all-challenges-dialog.modal(tabindex='-1') - .modal-dialog.animated.fadeInUp.fast-animation - .modal-content - .modal-header.challenge-list-header Challenges - a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') × - .modal-body - include ../partials/bonfires \ No newline at end of file + #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.js') \ No newline at end of file diff --git a/views/partials/bonfires.jade b/views/partials/bonfires.jade index 41f9bbe9dd..dfa484708a 100644 --- a/views/partials/bonfires.jade +++ b/views/partials/bonfires.jade @@ -2,5 +2,44 @@ h3 ol(start='0') for bonfire in bonfires li - a(href="/bonfire/#{bonfire.bonfireNumber}", class="#{ (cc && cc[bonfire.bonfireNumber] > 0) ? 'strikethrough' : '' }") #{bonfire.name} - |   (#{bonfire.time} mins) \ No newline at end of file + a(href="/bonfire/#{bonfire.bonfireNumber}") #{bonfire.name} + |   (Level #{bonfire.difficulty}) + + 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 + #mainEditorPanel.col-sm-12.col-md-7.col-xs-12 + .panel.panel-primary.panel-bonfire + .panel-heading.text-center Bonfire 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.js') \ No newline at end of file diff --git a/views/partials/challenges.jade b/views/partials/challenges.jade index cb93b2deeb..cef62c9d57 100644 --- a/views/partials/challenges.jade +++ b/views/partials/challenges.jade @@ -2,5 +2,7 @@ h3 ol(start='0') for challenge in challenges li - a(href="/bonfire/#{bonfire.bonfireNumber}", class="#{ (cc && cc[bonfire.bonfireNumber] > 0) ? 'strikethrough' : '' }") #{bonfire.name} - |   (Level #{bonfire.difficulty}) + a(href="/challenges/#{challenge.challengeNumber}", class="#{ (cc && cc[challenge.challengeNumber] > 0) ? 'strikethrough' : '' }") #{challenge.name} + |   (#{challenge.time} mins) + +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! \ No newline at end of file From 0e9523ab722bbf9a584b505314901a01387fbb03 Mon Sep 17 00:00:00 2001 From: Nathan Leniz Date: Thu, 22 Jan 2015 15:49:16 -0500 Subject: [PATCH 07/12] More steps towards integrating the bonfire challenge framework. Importing challnge seed, public tests, private tests, entry point and entry point negator --- controllers/bonfire.js | 5 +- models/Bonfire.js | 5 +- public/js/lib/bonfire/bonfireFramework.js | 62 ++++++++++++++++++----- seed_data/bonfires.json | 46 +++++++++++++++-- views/bonfire/show.jade | 32 +++++++----- views/partials/bonfires.jade | 46 +---------------- 6 files changed, 118 insertions(+), 78 deletions(-) diff --git a/controllers/bonfire.js b/controllers/bonfire.js index 809899100c..890c149a99 100644 --- a/controllers/bonfire.js +++ b/controllers/bonfire.js @@ -51,6 +51,7 @@ exports.returnBonfire = function(req, res, next) { 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); @@ -65,9 +66,7 @@ exports.returnBonfire = function(req, res, next) { privateTests: bonfire[bonfireNumber].privateTests, challengeSeed: bonfire[bonfireNumber].challengeSeed, challengeEntryPoint: bonfire[bonfireNumber].challengeEntryPoint, - //title: bonfire.name, - //name: bonfire.name, - //description: bonfire.description, + challengeEntryPointNegate: bonfire[bonfireNumber].challengeEntryPointNegate, //cc: req.user ? req.user.bonfiresHash : undefined, //points: req.user ? req.user.points : undefined, diff --git a/models/Bonfire.js b/models/Bonfire.js index c30e132f4f..461e663d77 100644 --- a/models/Bonfire.js +++ b/models/Bonfire.js @@ -18,7 +18,10 @@ var bonfireSchema = new mongoose.Schema({ publicTests: Array, privateTests: Array, challengeSeed: String, - bonfireNumber: Number + bonfireNumber: Number, + challengeEntryPoint: String, + challengeEntryPointNegate: String + }); module.exports = mongoose.model('Bonfire', bonfireSchema); diff --git a/public/js/lib/bonfire/bonfireFramework.js b/public/js/lib/bonfire/bonfireFramework.js index 93518ca501..ebbfa13d76 100644 --- a/public/js/lib/bonfire/bonfireFramework.js +++ b/public/js/lib/bonfire/bonfireFramework.js @@ -20,19 +20,37 @@ var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("codeEditor") } }); var editor = myCodeMirror; -myCodeMirror.setValue('/*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' + -'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' + -'test();'); + + +// 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' + + '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]);'; + +// Default seed for editor if one isn't provided +var nonChallengeSeed = 'test();'; +var editorValue; + + + + +if (challengeSeed) { + editorValue = challengeSeed; +} else { + editorValue = nonChallengeValue; +} + + +myCodeMirror.setValue(editorValue); var codeOutput = CodeMirror.fromTextArea(document.getElementById("codeOutput"), { lineNumbers: false, @@ -83,6 +101,17 @@ var tests; var testSalt = Math.random(); var scrapeTests = function(userJavaScript) { + + console.log(challengeEntryPointNegate); + var checkIfUserSuppliedEntry = new RegExp(challengeEntryPointNegate, 'g'); + console.log(checkIfUserSuppliedEntry); + console.log(checkIfUserSuppliedEntry.test(userJavaScript)); + if (!(checkIfUserSuppliedEntry.test(userJavaScript))) { + userJavaScript += '\n' + challengeEntryPoint; + } + for (var i = 0; i < publicTests.length; i++) { + userJavaScript += '\n' + publicTests[i]; + } var counter = 0; var regex = new RegExp(/(expect(\s+)?\(.*\;)|(assert(\s+)?\(.*\;)|(assert\.\w.*\;)|(.*\.should\..*\;)/); var match = regex.exec(userJavaScript); @@ -97,6 +126,11 @@ var scrapeTests = function(userJavaScript) { counter++; match = regex.exec(userJavaScript); } + + //for (publicTest in publicTests) { + // console.log(publicTest); + // tests.push(publicTest); + //} if (tests) replaceQuotesInTests(); return userJavaScript; }; @@ -170,7 +204,7 @@ var reassembleTest = function(test, data) { var runTests = function(err, data) { pushed = false; $('#testSuite').children().remove(); - if (err && tests) { + if (err && tests.length > 0) { tests = [{text:"Program Execution Failure", err: "No tests were run."}]; createTestDisplay(); } else if (tests) { diff --git a/seed_data/bonfires.json b/seed_data/bonfires.json index 520593ce4f..6c40b32dd5 100644 --- a/seed_data/bonfires.json +++ b/seed_data/bonfires.json @@ -9,7 +9,7 @@ "Return true if the string is a palindrome, otherwise false" ], "publicTests": [ - "expect(palindrome(\"eye\")).to.be.a.(\"boolean\");", + "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);" @@ -20,8 +20,48 @@ "assert.deepEqual(palindrome(\"nope\"), false);" ], "challengeSeed": "function palindrome(str) {\n // Good luck!\n return true;\n}\n\n", - "challengeEntryPoint": "palindrome(!!!)", - "bonfireNumber": 1 + "challengeEntryPoint": "palindrome(\"eye\")", + "bonfireNumber": 1, + "challengeEntryPointNegate" : "palindrome\\([^str].*\\;", + }, + { + "name": "Validate US Telephone Numbers", + "difficulty": 3, + "description": [ + "You are in charge of a campground's website signup form. Specifically, you have been asked to validate US phone numbers before forms are submitted.", + "But consider yourself forewarned: the camp leader is quick to anger. So don't try to pull something like forcing the user to enter a phone number in a predefined format. He can't stand it when coders are lazy. Don't be lazy, or he might throw you in the fire pit.", + "The user cmay 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": [ + "expect(telephoneCheck(\"555-555-5555\")).to.be.a(\"boolean\");", + "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(\"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", + "challengeEntryPoint": "telephoneCheck(\"555-555-5555\")", + "bonfireNumber": 2, + "challengeEntryPointNegate" : "palindrome\\([^str].*\\;", } ] diff --git a/views/bonfire/show.jade b/views/bonfire/show.jade index f4263c81e5..c9fed86687 100644 --- a/views/bonfire/show.jade +++ b/views/bonfire/show.jade @@ -15,19 +15,21 @@ block content script(src='/js/lib/codemirror/mode/javascript/javascript.js') script(src='/js/lib/jailed/jailed.js') script(src='/js/lib/bonfire/bonfireInit.js') + + .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 - form.code - h3 Details - h5 - ol - for sentence in description - li!= sentence - .form-group.codeMirrorView - textarea#codeEditor(autofocus=true) + .panel.panel-primary.panel-bonfire + .panel-heading.text-center #{name} (Level #{difficulty} bonfire) + .panel.panel-body + form.code + h3 Details + h5 + ol + for sentence in description + li!= sentence + .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 @@ -40,4 +42,10 @@ block content br ul#testSuite.list-group br - script(src='/js/lib/bonfire/bonfireFramework.js') \ No newline at end of file + 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') diff --git a/views/partials/bonfires.jade b/views/partials/bonfires.jade index dfa484708a..1adbb74b8d 100644 --- a/views/partials/bonfires.jade +++ b/views/partials/bonfires.jade @@ -1,45 +1 @@ -h3 - ol(start='0') -for bonfire in bonfires - li - a(href="/bonfire/#{bonfire.bonfireNumber}") #{bonfire.name} - |   (Level #{bonfire.difficulty}) - - 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 - #mainEditorPanel.col-sm-12.col-md-7.col-xs-12 - .panel.panel-primary.panel-bonfire - .panel-heading.text-center Bonfire 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.js') \ No newline at end of file +//TODO: STUFF \ No newline at end of file From 5881a14de32632e07cac1cf6d84ee28ea0bcac76 Mon Sep 17 00:00:00 2001 From: Nathan Leniz Date: Thu, 22 Jan 2015 15:58:41 -0500 Subject: [PATCH 08/12] Layout improvements to bonfire challenges view --- views/bonfire/show.jade | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/views/bonfire/show.jade b/views/bonfire/show.jade index c9fed86687..5a86ffd488 100644 --- a/views/bonfire/show.jade +++ b/views/bonfire/show.jade @@ -22,14 +22,14 @@ block content .panel.panel-primary.panel-bonfire .panel-heading.text-center #{name} (Level #{difficulty} bonfire) .panel.panel-body - form.code - h3 Details + h4 Details h5 ol for sentence in description li!= sentence - .form-group.codeMirrorView - textarea#codeEditor(autofocus=true) + 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 From 8a3618e3667f0ffd145b8a65641b5696f7ccd8b6 Mon Sep 17 00:00:00 2001 From: Nathan Leniz Date: Thu, 22 Jan 2015 16:15:43 -0500 Subject: [PATCH 09/12] No longer overwriting user entrypoint with predefined test entry point --- public/js/lib/bonfire/bonfireFramework.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/public/js/lib/bonfire/bonfireFramework.js b/public/js/lib/bonfire/bonfireFramework.js index ebbfa13d76..4f9a44423c 100644 --- a/public/js/lib/bonfire/bonfireFramework.js +++ b/public/js/lib/bonfire/bonfireFramework.js @@ -102,12 +102,15 @@ var testSalt = Math.random(); var scrapeTests = function(userJavaScript) { - console.log(challengeEntryPointNegate); + var checkIfUserSuppliedEntry = new RegExp(challengeEntryPointNegate, 'g'); - console.log(checkIfUserSuppliedEntry); - console.log(checkIfUserSuppliedEntry.test(userJavaScript)); - if (!(checkIfUserSuppliedEntry.test(userJavaScript))) { + + var userEntryCheck = checkIfUserSuppliedEntry.test(userJavaScript); + if (!userEntryCheck) { + userJavaScript += '\n' + challengeEntryPoint; + } else { + // do nothing? } for (var i = 0; i < publicTests.length; i++) { userJavaScript += '\n' + publicTests[i]; From e0311210e054f3e77725e00c391f9eab4b85d4a9 Mon Sep 17 00:00:00 2001 From: Nathan Leniz Date: Thu, 22 Jan 2015 18:44:25 -0500 Subject: [PATCH 10/12] Improving bonfire flow, working on seed.js --- public/css/main.less | 7 +++++++ public/js/lib/bonfire/bonfireFramework.js | 16 ++++++++++------ seed_data/bonfires.json | 8 ++++---- views/bonfire/show.jade | 9 ++++----- 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/public/css/main.less b/public/css/main.less index c6897caad0..e6717ff8d8 100644 --- a/public/css/main.less +++ b/public/css/main.less @@ -548,6 +548,13 @@ div.CodeMirror-scroll { } +.bonfire-instructions p { + padding: 0; +} +.bonfire-instructions { + margin-bottom: 2px; +} + //uncomment this to see the dimensions of all elements outlined in red //* { // border-color: red; diff --git a/public/js/lib/bonfire/bonfireFramework.js b/public/js/lib/bonfire/bonfireFramework.js index 4f9a44423c..0665c2da71 100644 --- a/public/js/lib/bonfire/bonfireFramework.js +++ b/public/js/lib/bonfire/bonfireFramework.js @@ -44,7 +44,7 @@ var editorValue; if (challengeSeed) { - editorValue = challengeSeed; + editorValue = challengeSeed + '\n\n' + challengeEntryPoint; } else { editorValue = nonChallengeValue; } @@ -100,9 +100,11 @@ var replaceQuotesInTests = function() { var tests; var testSalt = Math.random(); + var scrapeTests = function(userJavaScript) { + var checkIfUserSuppliedEntry = new RegExp(challengeEntryPointNegate, 'g'); var userEntryCheck = checkIfUserSuppliedEntry.test(userJavaScript); @@ -115,6 +117,11 @@ 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]; + } + var counter = 0; var regex = new RegExp(/(expect(\s+)?\(.*\;)|(assert(\s+)?\(.*\;)|(assert\.\w.*\;)|(.*\.should\..*\;)/); var match = regex.exec(userJavaScript); @@ -130,10 +137,6 @@ var scrapeTests = function(userJavaScript) { match = regex.exec(userJavaScript); } - //for (publicTest in publicTests) { - // console.log(publicTest); - // tests.push(publicTest); - //} if (tests) replaceQuotesInTests(); return userJavaScript; }; @@ -198,7 +201,7 @@ var createTestDisplay = function() { var assert = chai.assert; var expect = chai.expect; var should = chai.should(); -console.log(should); + var reassembleTest = function(test, data) { var lineNum = test.line; var regexp = new RegExp("\/\/" + lineNum + testSalt); @@ -219,6 +222,7 @@ var runTests = function(err, data) { var output = eval(reassembleTest(test, data)); } } catch(error) { + arr[ix].err = error.name + ":" + error.message; } finally { if (!test) { diff --git a/seed_data/bonfires.json b/seed_data/bonfires.json index 6c40b32dd5..111c7da0e4 100644 --- a/seed_data/bonfires.json +++ b/seed_data/bonfires.json @@ -1,7 +1,7 @@ [ { "name": "Palindrome Tester", - "difficulty": 1, // should be a range from 1-5 + "difficulty": 1, "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.", @@ -20,9 +20,9 @@ "assert.deepEqual(palindrome(\"nope\"), false);" ], "challengeSeed": "function palindrome(str) {\n // Good luck!\n return true;\n}\n\n", - "challengeEntryPoint": "palindrome(\"eye\")", + "challengeEntryPoint": "palindrome(\"eye\");", "bonfireNumber": 1, - "challengeEntryPointNegate" : "palindrome\\([^str].*\\;", + "challengeEntryPointNegate" : "palindrome\\([^str].*\\;" }, { "name": "Validate US Telephone Numbers", @@ -61,7 +61,7 @@ "challengeSeed": "function telephoneCheck(str) {\n // Good luck!\n return true;\n}\n\n", "challengeEntryPoint": "telephoneCheck(\"555-555-5555\")", "bonfireNumber": 2, - "challengeEntryPointNegate" : "palindrome\\([^str].*\\;", + "challengeEntryPointNegate" : "palindrome\\([^str].*\\;" } ] diff --git a/views/bonfire/show.jade b/views/bonfire/show.jade index 5a86ffd488..6b51fe72f1 100644 --- a/views/bonfire/show.jade +++ b/views/bonfire/show.jade @@ -22,11 +22,10 @@ block content .panel.panel-primary.panel-bonfire .panel-heading.text-center #{name} (Level #{difficulty} bonfire) .panel.panel-body - h4 Details - h5 - ol - for sentence in description - li!= sentence + .well + .text-justify.bonfire-instructions + for sentence in description + p.bonfire-instructions!= sentence form.code .form-group.codeMirrorView textarea#codeEditor(autofocus=true) From e9f24347b42a409629c6a7a45f2f9812b3a207e9 Mon Sep 17 00:00:00 2001 From: Nathan Leniz Date: Thu, 22 Jan 2015 19:04:16 -0500 Subject: [PATCH 11/12] Improving seeding function to also seed bonfires --- seed_data/bonfires.json | 202 ------------------------------------- seed_data/challenge-hashes | 202 +++++++++++++++++++++++++++++++++++++ seed_data/seed.js | 20 ++++ 3 files changed, 222 insertions(+), 202 deletions(-) create mode 100644 seed_data/challenge-hashes diff --git a/seed_data/bonfires.json b/seed_data/bonfires.json index 111c7da0e4..3a348cd296 100644 --- a/seed_data/bonfires.json +++ b/seed_data/bonfires.json @@ -65,205 +65,3 @@ } ] -/* -"aaa48de84e1ecc7c742e1124" -"ff0395860f5d3034dc0bfc94" -"7123c8c441eddfaeb5bdef0d" -"c3a4d278b9e760a0ffe8321f" -"aceca143b92049a4392a859e" -"ce9394f67d413734758e27e4" -"1369953ef6f03098cb60e2f7" -"fa229986db0716662e63163a" -"0a6207dfc9ac12f223b4e686" -"2e538b339cbcb7437e61d71f" -"21de1104b8ea7c6a382442d9" -"0aa3497514cb1d8a0ed04933" -"3a45068415f5a20a5d4a2039" -"6a73ec9b86f0e742f6c6ea76" -"06dc21940748badcdb29561e" -"0f2341ef36740b5c2b9d830c" -"dc4cc7ce1fd0418859b10e0b" -"1fcda9b5e0bf502c8b770374" -"482879c42188cde1f9ad3d8f" -"3d680bd03fd291028af57f4f" -"6b444fe5aa97359238bd3c0d" -"72d6ad274e72ffcd399e05cb" -"e864a710647bb6883c9ec617" -"024dcd8cc0178de7daa4f59f" -"ded24fb937a3fd60dc624677" -"9ad4c3b2aebe7282e973e5df" -"d16c66ecc656c82899a2d427" -"ee3e4bf39b840609dd88f5af" -"9a10d27eb6ab6f5030bdbcd9" -"b4cca5ecdeca1eebc0dc4183" -"ccdf1ef407864df62b03331e" -"1baa0329f02e41a5517b11a6" -"b5b33e5ecf6c02a5780ac419" -"84b690f53cd6cbbbf4a361f5" -"4e3b1b9d41ff11bdf3722ffe" -"1fd45e64c43cd640abcf8a76" -"c8bd32cdd943c88fb8a74934" -"9e5440269d09b71f07002333" -"5080016b8b68f40f7476c341" -"f762d45cc870d9f18c6b7024" -"cf21358ab1245c7033504b42" -"41eff7cb0f2fd8ec9e0cbf68" -"a344c63de6a00feea5c541e0" -"7ab3c18c0815d7b1f02e8768" -"a6f36e4387e2e1e25af4e000" -"9064af1431c1ff3aaa15a0d6" -"50946066aaba43a294155ab5" -"70e82e77857317d6936ecdcc" -"dc644dc20d5b02ffd7c8cc94" -"92af1e9f1813619d820dec4d" -"9d4a077fdaaa24b78a54cee9" -"cfd5fa7aea14fb294bd4f5ff" -"068541b6c5130ca541d6c05c" -"39f4d1f12142d583b0318265" -"4a201b8fa69d11cb669dca8c" -"6fa6bba2e334dd2c9e5a6911" -"30ff082b6a28558f16743fea" -"afed31c4dc2ddf056e263acb" -"b2431ecf36f0b780959aa03d" -"54e42938ab6fa923a5fbfbff" -"48d50e3ff5e96f152d912ebf" -"6c7aad2ee996132f76630c05" -"2705f0482774977fa9b5c7bc" -"c09d6682c7a144d9afd4bfab" -"1a0a30c55dd9bc2fff4e2aac" -"30c22b502e80afd144d79120" -"8f882989bbc98c68b6c7347e" -"888bf771b63a5f64e6b696ed" -"959aa13a2e6439fd5d29c5fe" -"d03d311ca64bf59a2404dcd0" -"7a650f3e4308a097d7883b1f" -"54c207808ac349fa34ed24a9" -"3cb12e3ea31fe15ba9d234e5" -"0d9f8123e52f791ae172f627" -"387518b1bb96bd918e7d0b91" -"27198d8918c9802ac0b06a58" -"7a519a552f723c6b1fdc9389" -"4240096651a50f888765ed60" -"8ba94f78cc44cfb82b3678d2" -"1cf7c3bda6ec7952923bc90f" -"cd54811e976edbc798a87c24" -"e4ee17912f5d7d80d41dc52d" -"572346dd1874a0c749c3a031" -"cf700031502680580ff25980" -"7054518832e5c7efde04a58c" -"7716c6b6a3dcc9c5df79a262" -"f4d1084c692f5a07c25a1b47" -"817b80892a78fc6f83eab4eb" -"ae0e0adda6d063d3fd2c9499" -"33184c427ecaab77b5332521" -"c6c4da707e3eed987eb65ba6" -"40f9801913c0cb9800960bf7" -"af11cf78e8340f172ba76bbe" -"c1daea28b5996b8e8800e300" -"7312b3234b5f2f50887597b9" -"3e4361c5356b30f8ce833268" -"e6fc8827b9aa96fc91035ac2" -"11658fe51b23319533c72106" -"34207fe236870fd855392ef6" -"dc970a2b17aa1432d180d078" -"2f1686ad711b5ac3d98905b5" -"ed20f4bf782e10ec26c7b3b1" -"cf4d6241df36b0bbcea401e2" -"97e414eb00338bd7bd5d1b31" -"bcfebb743729d4fc51b0db49" -"52782c1eaa15e050ac748b18" -"57f65a6cd2eb0a2745fc90ee" -"fcc569e80808c6cd84c839cc" -"2447f8e0e3ccfd895a619695" -"600687fe6332b2e2b20d6a84" -"0f8a972361baddb3ac64b6d9" -"f768594ab352cf8e2282b615" -"3163b25e25b0d6859df17751" -"c73d68f0cf77aa113337fcde" -"cc16163137f13f70decbcb5c" -"4adbf6c7ac2004ee8ae20f55" -"c2779f78a0e57dcee471cefd" -"bf44903cd2fca4ae4daf0818" -"ca8013372d58365e21bd0428" -"e308901ca272ad447dca965a" -"ec8cefe29832cd726185119f" -"36bf51da3f32b1e9550f3b15" -"aefff6dffdf534a6c9601f70" -"ce237971a71127f9ce747232" -"99f4d97fae16ccbeb8c26d46" -"c9f6480328ec4b63b1034826" -"ce10bb6e80b09533cb21c9a5" -"311a54aaf062b29422ac0b02" -"b2073bec873b295c04e9fb7e" -"7b7d94035d63c9c0598b242b" -"e19e9a0487f1bd3eabdb777c" -"eeafe5169a2afd9ce3979698" -"96c7a1f9fb73468fdb770034" -"77e607be2498160d3ceeff60" -"c784fa6b1fd7d9aedb05b607" -"a76319bca87e0b57bc79064f" -"a08db36785c51e5b92a6e92f" -"0933ab4a366d57fd1f1c0a48" -"17663f17a835cfe0bca64f4a" -"aee8323d1de634fc42c11d90" -"682044caf09a068e26c11cab" -"1346fdbe3c6fcb808b99cdf6" -"26fd8f47fe4791e2dd07b2e0" -"b1da27dd129216c2ead2e162" -"618adebe192e896eb1501708" -"2628d9eeb38db68c0b255a75" -"1fb78eda5deb8972cc357a9b" -"2fdebb85a401de75bb580a02" -"c59eae24bee36f63c938723d" -"fb66b55d5617e27ca64836a3" -"55994022872e01fd41d8ec7b" -"53ae83b5490e1cf55625ff3d" -"c44975deeb67b96e6cc37eb5" -"94c64d5ff48ca6487f5e0b07" -"e34e7c1a3d70678955a5df8e" -"6426d30a923dec6377132c47" -"d67811849354ded9d34c9ece" -"01e7ae81207cfd230cb02747" -"e24558477f94bcdd82f16ebe" -"4370f6dcc2f53bd5abed7899" -"679b1145cd3072fbcd513bcb" -"4dafd3fd84e7a337ef3e9933" -"2aca3d41cb148603b4a2d70b" -"5e5aa8c960d024109543c577" -"c5f5f313c8a7056bbcdb7639" -"a7b2aaa4cf85fce98cdeb314" -"e556c0d14bc0ce9cc7bde0ca" -"922a8284880a7c879d846f90" -"b146cf2fbf206ca48687e9b6" -"fbdc52bb7c7620bd4508e5a3" -"23d79a262a81459e75576cc2" -"a26721706d3b9f971cef3ce6" -"fb3801ed1b056a3ab4bbfdc1" -"d5cafae617f1485826de335c" -"e9650dfc8b570f9d33381012" -"453c804c7ce82e83305cd751" -"3eaab01bdd1393be8d461777" -"2b6d9ddd4754b71d92ed31b7" -"2338e9af6acab9fcf5327f6a" -"588e7405c30c346ed2ea5e44" -"eec8837994054fb2043b6166" -"0877406795956ca9eb13fea1" -"1dea30e852067eec48a24035" -"ee716ce45ea812167ed2497a" -"9621d5aeaf8de9b2f58977bd" -"e9bb838723083bac7f83d602" -"ef64da08bbe787891d47c31b" -"e01b6616cc6cf7819172f7f3" -"17c821c34fca587daec981fc" -"d0c4b7153dcb3e6af47bcd98" -"5188eb00680051c35cd6e0f0" -"9fc7b68e736a1f4931226ad8" -"b5eac897471f125224a3e594" -"c1d0f890a02c85a9320f96d5" -"7e3b1ca1b1b1e990367f0cc2" -"bff5ff77174c43f7c681e0bd" -"ddeb794121937d07a887c9e6" -"9db902e930f25fbacc125087" -"4f82d277b47ae9c98095f068" -"24f999491fa46cd194c7fd35" -*/ \ No newline at end of file diff --git a/seed_data/challenge-hashes b/seed_data/challenge-hashes new file mode 100644 index 0000000000..8b6ddfa36d --- /dev/null +++ b/seed_data/challenge-hashes @@ -0,0 +1,202 @@ +/* +"aaa48de84e1ecc7c742e1124" +"ff0395860f5d3034dc0bfc94" +"7123c8c441eddfaeb5bdef0d" +"c3a4d278b9e760a0ffe8321f" +"aceca143b92049a4392a859e" +"ce9394f67d413734758e27e4" +"1369953ef6f03098cb60e2f7" +"fa229986db0716662e63163a" +"0a6207dfc9ac12f223b4e686" +"2e538b339cbcb7437e61d71f" +"21de1104b8ea7c6a382442d9" +"0aa3497514cb1d8a0ed04933" +"3a45068415f5a20a5d4a2039" +"6a73ec9b86f0e742f6c6ea76" +"06dc21940748badcdb29561e" +"0f2341ef36740b5c2b9d830c" +"dc4cc7ce1fd0418859b10e0b" +"1fcda9b5e0bf502c8b770374" +"482879c42188cde1f9ad3d8f" +"3d680bd03fd291028af57f4f" +"6b444fe5aa97359238bd3c0d" +"72d6ad274e72ffcd399e05cb" +"e864a710647bb6883c9ec617" +"024dcd8cc0178de7daa4f59f" +"ded24fb937a3fd60dc624677" +"9ad4c3b2aebe7282e973e5df" +"d16c66ecc656c82899a2d427" +"ee3e4bf39b840609dd88f5af" +"9a10d27eb6ab6f5030bdbcd9" +"b4cca5ecdeca1eebc0dc4183" +"ccdf1ef407864df62b03331e" +"1baa0329f02e41a5517b11a6" +"b5b33e5ecf6c02a5780ac419" +"84b690f53cd6cbbbf4a361f5" +"4e3b1b9d41ff11bdf3722ffe" +"1fd45e64c43cd640abcf8a76" +"c8bd32cdd943c88fb8a74934" +"9e5440269d09b71f07002333" +"5080016b8b68f40f7476c341" +"f762d45cc870d9f18c6b7024" +"cf21358ab1245c7033504b42" +"41eff7cb0f2fd8ec9e0cbf68" +"a344c63de6a00feea5c541e0" +"7ab3c18c0815d7b1f02e8768" +"a6f36e4387e2e1e25af4e000" +"9064af1431c1ff3aaa15a0d6" +"50946066aaba43a294155ab5" +"70e82e77857317d6936ecdcc" +"dc644dc20d5b02ffd7c8cc94" +"92af1e9f1813619d820dec4d" +"9d4a077fdaaa24b78a54cee9" +"cfd5fa7aea14fb294bd4f5ff" +"068541b6c5130ca541d6c05c" +"39f4d1f12142d583b0318265" +"4a201b8fa69d11cb669dca8c" +"6fa6bba2e334dd2c9e5a6911" +"30ff082b6a28558f16743fea" +"afed31c4dc2ddf056e263acb" +"b2431ecf36f0b780959aa03d" +"54e42938ab6fa923a5fbfbff" +"48d50e3ff5e96f152d912ebf" +"6c7aad2ee996132f76630c05" +"2705f0482774977fa9b5c7bc" +"c09d6682c7a144d9afd4bfab" +"1a0a30c55dd9bc2fff4e2aac" +"30c22b502e80afd144d79120" +"8f882989bbc98c68b6c7347e" +"888bf771b63a5f64e6b696ed" +"959aa13a2e6439fd5d29c5fe" +"d03d311ca64bf59a2404dcd0" +"7a650f3e4308a097d7883b1f" +"54c207808ac349fa34ed24a9" +"3cb12e3ea31fe15ba9d234e5" +"0d9f8123e52f791ae172f627" +"387518b1bb96bd918e7d0b91" +"27198d8918c9802ac0b06a58" +"7a519a552f723c6b1fdc9389" +"4240096651a50f888765ed60" +"8ba94f78cc44cfb82b3678d2" +"1cf7c3bda6ec7952923bc90f" +"cd54811e976edbc798a87c24" +"e4ee17912f5d7d80d41dc52d" +"572346dd1874a0c749c3a031" +"cf700031502680580ff25980" +"7054518832e5c7efde04a58c" +"7716c6b6a3dcc9c5df79a262" +"f4d1084c692f5a07c25a1b47" +"817b80892a78fc6f83eab4eb" +"ae0e0adda6d063d3fd2c9499" +"33184c427ecaab77b5332521" +"c6c4da707e3eed987eb65ba6" +"40f9801913c0cb9800960bf7" +"af11cf78e8340f172ba76bbe" +"c1daea28b5996b8e8800e300" +"7312b3234b5f2f50887597b9" +"3e4361c5356b30f8ce833268" +"e6fc8827b9aa96fc91035ac2" +"11658fe51b23319533c72106" +"34207fe236870fd855392ef6" +"dc970a2b17aa1432d180d078" +"2f1686ad711b5ac3d98905b5" +"ed20f4bf782e10ec26c7b3b1" +"cf4d6241df36b0bbcea401e2" +"97e414eb00338bd7bd5d1b31" +"bcfebb743729d4fc51b0db49" +"52782c1eaa15e050ac748b18" +"57f65a6cd2eb0a2745fc90ee" +"fcc569e80808c6cd84c839cc" +"2447f8e0e3ccfd895a619695" +"600687fe6332b2e2b20d6a84" +"0f8a972361baddb3ac64b6d9" +"f768594ab352cf8e2282b615" +"3163b25e25b0d6859df17751" +"c73d68f0cf77aa113337fcde" +"cc16163137f13f70decbcb5c" +"4adbf6c7ac2004ee8ae20f55" +"c2779f78a0e57dcee471cefd" +"bf44903cd2fca4ae4daf0818" +"ca8013372d58365e21bd0428" +"e308901ca272ad447dca965a" +"ec8cefe29832cd726185119f" +"36bf51da3f32b1e9550f3b15" +"aefff6dffdf534a6c9601f70" +"ce237971a71127f9ce747232" +"99f4d97fae16ccbeb8c26d46" +"c9f6480328ec4b63b1034826" +"ce10bb6e80b09533cb21c9a5" +"311a54aaf062b29422ac0b02" +"b2073bec873b295c04e9fb7e" +"7b7d94035d63c9c0598b242b" +"e19e9a0487f1bd3eabdb777c" +"eeafe5169a2afd9ce3979698" +"96c7a1f9fb73468fdb770034" +"77e607be2498160d3ceeff60" +"c784fa6b1fd7d9aedb05b607" +"a76319bca87e0b57bc79064f" +"a08db36785c51e5b92a6e92f" +"0933ab4a366d57fd1f1c0a48" +"17663f17a835cfe0bca64f4a" +"aee8323d1de634fc42c11d90" +"682044caf09a068e26c11cab" +"1346fdbe3c6fcb808b99cdf6" +"26fd8f47fe4791e2dd07b2e0" +"b1da27dd129216c2ead2e162" +"618adebe192e896eb1501708" +"2628d9eeb38db68c0b255a75" +"1fb78eda5deb8972cc357a9b" +"2fdebb85a401de75bb580a02" +"c59eae24bee36f63c938723d" +"fb66b55d5617e27ca64836a3" +"55994022872e01fd41d8ec7b" +"53ae83b5490e1cf55625ff3d" +"c44975deeb67b96e6cc37eb5" +"94c64d5ff48ca6487f5e0b07" +"e34e7c1a3d70678955a5df8e" +"6426d30a923dec6377132c47" +"d67811849354ded9d34c9ece" +"01e7ae81207cfd230cb02747" +"e24558477f94bcdd82f16ebe" +"4370f6dcc2f53bd5abed7899" +"679b1145cd3072fbcd513bcb" +"4dafd3fd84e7a337ef3e9933" +"2aca3d41cb148603b4a2d70b" +"5e5aa8c960d024109543c577" +"c5f5f313c8a7056bbcdb7639" +"a7b2aaa4cf85fce98cdeb314" +"e556c0d14bc0ce9cc7bde0ca" +"922a8284880a7c879d846f90" +"b146cf2fbf206ca48687e9b6" +"fbdc52bb7c7620bd4508e5a3" +"23d79a262a81459e75576cc2" +"a26721706d3b9f971cef3ce6" +"fb3801ed1b056a3ab4bbfdc1" +"d5cafae617f1485826de335c" +"e9650dfc8b570f9d33381012" +"453c804c7ce82e83305cd751" +"3eaab01bdd1393be8d461777" +"2b6d9ddd4754b71d92ed31b7" +"2338e9af6acab9fcf5327f6a" +"588e7405c30c346ed2ea5e44" +"eec8837994054fb2043b6166" +"0877406795956ca9eb13fea1" +"1dea30e852067eec48a24035" +"ee716ce45ea812167ed2497a" +"9621d5aeaf8de9b2f58977bd" +"e9bb838723083bac7f83d602" +"ef64da08bbe787891d47c31b" +"e01b6616cc6cf7819172f7f3" +"17c821c34fca587daec981fc" +"d0c4b7153dcb3e6af47bcd98" +"5188eb00680051c35cd6e0f0" +"9fc7b68e736a1f4931226ad8" +"b5eac897471f125224a3e594" +"c1d0f890a02c85a9320f96d5" +"7e3b1ca1b1b1e990367f0cc2" +"bff5ff77174c43f7c681e0bd" +"ddeb794121937d07a887c9e6" +"9db902e930f25fbacc125087" +"4f82d277b47ae9c98095f068" +"24f999491fa46cd194c7fd35" +*/ \ No newline at end of file diff --git a/seed_data/seed.js b/seed_data/seed.js index dacd5aa11e..797f704d5e 100644 --- a/seed_data/seed.js +++ b/seed_data/seed.js @@ -8,6 +8,19 @@ var Challenge = require('../models/Challenge.js'), mongoose.connect(secrets.db); +var counter = 0; + +var CompletionMonitor = function() { + counter++; + console.log('call ' + counter); + + if (counter < 2) { + return; + } else { + process.exit(0); + } +} + Challenge.remove({}, function(err, data) { if (err) { console.error(err); @@ -20,7 +33,9 @@ Challenge.remove({}, function(err, data) { } else { console.log('Saved ', data); } + CompletionMonitor(); }); + console.log('challenges'); }); Bonfire.remove({}, function(err, data) { @@ -35,5 +50,10 @@ Bonfire.remove({}, function(err, data) { } else { console.log('Saved ', data); } + CompletionMonitor(); }); + console.log('bonfires'); + }); + + From bc1f01f67b4f6be8cbc31b429d63a962b0d5c073 Mon Sep 17 00:00:00 2001 From: Nathan Leniz Date: Thu, 22 Jan 2015 22:47:15 -0500 Subject: [PATCH 12/12] More bonfire improvements, restoring functionality to original bonfire module after growing it to accept the challenge framework --- public/js/lib/bonfire/bonfireFramework.js | 96 +++++++++++------------ seed_data/bonfires.json | 13 +-- 2 files changed, 48 insertions(+), 61 deletions(-) diff --git a/public/js/lib/bonfire/bonfireFramework.js b/public/js/lib/bonfire/bonfireFramework.js index 0665c2da71..4311a7fa09 100644 --- a/public/js/lib/bonfire/bonfireFramework.js +++ b/public/js/lib/bonfire/bonfireFramework.js @@ -34,23 +34,8 @@ var nonChallengeValue = '/*Welcome to Bonfire, Free Code Camp\'s future CoderByt ' });\n' + '}\n' + 'expect(test()).to.be.a("array");\n\n' + - 'assert.deepEqual(test(), [1,4,9]);'; - -// Default seed for editor if one isn't provided -var nonChallengeSeed = 'test();'; -var editorValue; - - - - -if (challengeSeed) { - editorValue = challengeSeed + '\n\n' + challengeEntryPoint; -} else { - editorValue = nonChallengeValue; -} - - -myCodeMirror.setValue(editorValue); + 'assert.deepEqual(test(), [1,4,9]);\n\n' + + 'test();'; var codeOutput = CodeMirror.fromTextArea(document.getElementById("codeOutput"), { lineNumbers: false, @@ -68,6 +53,26 @@ 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 publicTests = publicTests || []; +var privateTests = privateTests || []; +var challengeEntryPoint = challengeEntryPoint || null; +var challengeEntryPointNegate = challengeEntryPointNegate || null; + + +if (challengeSeed !== null) { + editorValue = challengeSeed + '\n\n' + challengeEntryPoint; +} else { + editorValue = nonChallengeValue; +} + + +myCodeMirror.setValue(editorValue); + function doLinting () { editor.operation(function () { for (var i = 0; i < widgets.length; ++i) @@ -91,6 +96,28 @@ function doLinting () { }); }; +$('#submitButton').on('click', function () { + bonfireExecute(); +}); + +function bonfireExecute() { + tests = null; + $('#codeOutput').empty(); + var userJavaScript = myCodeMirror.getValue(); + userJavaScript = removeComments(userJavaScript); + userJavaScript = scrapeTests(userJavaScript); + 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 replaceQuotesInTests = function() { tests.forEach(function(elt, ix, arr) { arr[ix].text = arr[ix].text.replace(/\"/g,'\''); @@ -103,17 +130,6 @@ var testSalt = Math.random(); var scrapeTests = function(userJavaScript) { - - - var checkIfUserSuppliedEntry = new RegExp(challengeEntryPointNegate, 'g'); - - var userEntryCheck = checkIfUserSuppliedEntry.test(userJavaScript); - if (!userEntryCheck) { - - userJavaScript += '\n' + challengeEntryPoint; - } else { - // do nothing? - } for (var i = 0; i < publicTests.length; i++) { userJavaScript += '\n' + publicTests[i]; } @@ -147,32 +163,10 @@ function removeComments(userJavaScript) { } function removeLogs(userJavaScript) { - //return userJavaScript.replace(/(console\.[\w]+\s*\(.*\;)/g, ''); + return userJavaScript.replace(/(console\.[\w]+\s*\(.*\;)/g, ''); return userJavaScript; } -$('#submitButton').on('click', function () { - bonfireExecute(); -}); - -function bonfireExecute() { - tests = null; - $('#codeOutput').empty(); - var userJavaScript = myCodeMirror.getValue(); - userJavaScript = removeComments(userJavaScript); - userJavaScript = scrapeTests(userJavaScript); - 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 pushed = false; var createTestDisplay = function() { if (pushed) { diff --git a/seed_data/bonfires.json b/seed_data/bonfires.json index 3a348cd296..79f5f34bfb 100644 --- a/seed_data/bonfires.json +++ b/seed_data/bonfires.json @@ -28,15 +28,8 @@ "name": "Validate US Telephone Numbers", "difficulty": 3, "description": [ - "You are in charge of a campground's website signup form. Specifically, you have been asked to validate US phone numbers before forms are submitted.", - "But consider yourself forewarned: the camp leader is quick to anger. So don't try to pull something like forcing the user to enter a phone number in a predefined format. He can't stand it when coders are lazy. Don't be lazy, or he might throw you in the fire pit.", - "The user cmay 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", + "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": [ @@ -59,7 +52,7 @@ "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\")", + "challengeEntryPoint": "telephoneCheck(\"555-555-5555\");", "bonfireNumber": 2, "challengeEntryPointNegate" : "palindrome\\([^str].*\\;" }