From bafba0b16ff876e939239f36c17716f1c2e2c937 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Fri, 13 Feb 2015 11:01:12 -0800 Subject: [PATCH 01/13] make some copy changes reflecting our shift to coderbyte --- app.js | 4 --- controllers/resources.js | 19 ------------- controllers/resources.json | 28 ------------------- controllers/user.js | 2 -- seed_data/challenges.json | 20 ++++++------- views/account/show.jade | 2 -- views/partials/about.jade | 4 +-- .../nonprofit-project-instructions.jade | 6 ++-- .../pair-program-with-team-viewer.jade | 27 ------------------ 9 files changed, 15 insertions(+), 97 deletions(-) delete mode 100644 views/resources/pair-program-with-team-viewer.jade diff --git a/app.js b/app.js index 2417185e98..632edb58f8 100644 --- a/app.js +++ b/app.js @@ -211,10 +211,6 @@ app.get('/control-shortcuts', resourcesController.deployAWebsite); app.get('/stats', function(req, res) { res.redirect(301, '/learn-to-code'); }); -app.get( - '/pair-program-with-team-viewer', - resourcesController.pairProgramWithTeamViewer -); app.get('/learn-to-code', resourcesController.about); app.get('/about', function(req, res) { res.redirect(301, '/learn-to-code'); diff --git a/controllers/resources.js b/controllers/resources.js index ec1c063f20..d0a5a458b9 100644 --- a/controllers/resources.js +++ b/controllers/resources.js @@ -97,25 +97,6 @@ module.exports = { }); }, - pairProgramWithTeamViewer: function(req, res) { - Challenge.find({}, null, { sort: { challengeNumber: 1 } }, function(err, c) { - if (err) { - debug('Challenge err: ', err); - next(err); - } - res.render('resources/pair-program-with-team-viewer', { - title: 'Challenge: Pair Program with Team Viewer', - name: 'Pair Program with Team Viewer', - video: '', - time: 30, - steps: steps, - cc: req.user ? req.user.challengesHash : undefined, - points: req.user ? req.user.points : undefined, - challenges: c - }); - }); - }, - about: function(req, res) { var date1 = new Date("10/15/2014"); var date2 = new Date(); diff --git a/controllers/resources.json b/controllers/resources.json index 1c3ea9abe2..1a7e038db6 100644 --- a/controllers/resources.json +++ b/controllers/resources.json @@ -117,34 +117,6 @@ "question": "Latency of Sending a packet from California to the Netherlands and back", "answer": "150,000,000 nanoseconds" }], - "steps": [ - "In the spirit of keeping Free Code Camp 100% free, we've created directions for using a totally free pair programming tool called Team Viewer. It's not as user-friendly as Screen Hero, but it gets the job done (and works on Linux!).", - "Go to http://www.teamviewer.com/en/index.aspx and download Team Viewer. Be sure not to download the beta version, which isn't compatible with the current stable version everyone else will be using.", - "Install it and launch it", - "We have a special chat room for people ready to pair program. Go to https://gitter.im/FreeCodeCamp/LetsPair and type \"Hello Pair Programmers!\". you on a CoderByte challenge.", - "If someone is available, they will be your \"pair\" - the person you pair programming with.", - "First, you will pair program on your pair's computer. Ask your pair for his or her Team Viewer ID and password.", - "Enter this id, and then password, to start the session.", - "Once the Team Viewer session starts, look at the the top of the screen. You will see 6 buttons. If you hover your cursor over the buttons, they will slide down so that you can read them. Click the audio/video button. This will allow you to turn on Voice Over IP and unmute your microphone, opening up your voice channel.", - "Note that you can now control your pair's keyboard and mouse, enabling you to step in and code yourself on your pair's computer when desired", - "Now you can click the X to end the pair programming session.", - "Next, you will pair program on your computer. Copy your Team Viewer ID and paste it into the private chat, so that your pair can use it to connect with you.", - "You will need to share your randomly generated password with your pair as well.", - "Once your pair connects, you will see a Team Viewer side menu. ", - "Click the audio button that drops down.", - "Click the headset icon and choose Voice over IP", - "Click the microphone button to unmute your microphone. Once your pair does the same, you two will have an open voice channel.", - "Now you can click the X to end the pair programming session.", - "Now it's time to tackle CoderByte.", - "Create a CoderByte account at http://coderbyte.com/sl/", - "Now go to http://coderbyte.com/CodingArea/Challenges/#easyChals and start working through Coderbyte's easy algorithm scripting challenges using JavaScript.", - "When you are finished pair programming, click the X to end the session.", - "Congratulations! You have completed your first pair programming session.", - "You should pair program with different campers until you've completed all the Easy, Medium and Hard CoderByte challenges. This is a big time investment, but the JavaScript practice you'll get, along with the scripting and algorithm experience, are well worth it!", - "You can complete CoderByte problems while you continue to work through Free Code Camp's challenges.", - "Be sure to pair program on these challenges, and remember to apply the RSAP methodology.", - "Click the button below to return to the Pair Programming challenge, then mark it complete." - ], "verbs": [ "aced", "nailed", diff --git a/controllers/user.js b/controllers/user.js index 1c0f0bfca2..d637fb8906 100644 --- a/controllers/user.js +++ b/controllers/user.js @@ -233,7 +233,6 @@ exports.returnUser = function(req, res, next) { username: user.profile.username, name: user.profile.name, location: user.profile.location, - coderbyteProfile: user.profile.coderbyteProfile, githubProfile: user.profile.githubProfile, linkedinProfile: user.profile.linkedinProfile, codepenProfile: user.profile.codepenProfile, @@ -329,7 +328,6 @@ exports.postUpdateProfile = function(req, res, next) { user.profile.username = req.body.username.trim() || ''; user.profile.location = req.body.location.trim() || ''; user.profile.githubProfile = req.body.githubProfile.trim() || ''; - user.profile.coderbyteProfile = req.body.coderbyteProfile.trim() || ''; user.profile.linkedinProfile = req.body.linkedinProfile.trim() || ''; user.profile.codepenProfile = req.body.codepenProfile.trim() || ''; user.profile.twitterHandle = req.body.twitterHandle.trim() || ''; diff --git a/seed_data/challenges.json b/seed_data/challenges.json index 6830fc0442..a0d519239b 100644 --- a/seed_data/challenges.json +++ b/seed_data/challenges.json @@ -412,7 +412,7 @@ ] }, { - "name": "Pair Program on CoderByte", + "name": "Pair Program on Bonfires", "time": 60, "video": "114635308", "challengeNumber": 34, @@ -421,21 +421,19 @@ "Pair Programming is where two people code together on the same computer. It is an efficient way to collaborate, and widely practiced at software companies. Pair Programming is one of the core concepts of \"Agile\" Software Development, which you will hear more about later.", "Many people use Skype or Google Hangouts to pair program, but if you talk with professional software engineers, they will tell you that it's not really pair programming unless both people have the ability to use the keyboard and mouse.", "The most popular tool for pair programming is Screen Hero. You can download Screen Hero for Mac or Windows. Create your new user account from within the app.", - "If you are using Linux, go to http://www.freecodecamp.com/pair-program-with-team-viewer to learn how to use an alternative (but inferior) tool called Team Viewer.", "We have a special chat room for people ready to pair program. Go to https://gitter.im/FreeCodeCamp/LetsPair and type \"Hello Pair Programmers!\"", "If someone is available, they will be your \"pair\" - the person you pair programming with.", - "Private message your pair and ask for the email address he or she used to register Screen Hero.", + "If no one gets back to you in the first few minutes, don't worry. There will be lots of opportunities to pair program in the future.", + "If someone does get back to you, private message them and ask for the email address they used to register Screen Hero.", "Add them as a new contact in Screen Hero, then click the monitor-looking button to attempt to share your screen with them.", "Once the Screen Hero session starts, your screen's margins will glow orange. You are now sharing your screen.", - "Your pair will have his or her own cursor, and will be able to type text on his or her and keyboard.", - "Now it's time to tackle CoderByte.", - "Create a CoderByte account at http://coderbyte.com/sl/", - "Now go to http://coderbyte.com/CodingArea/Challenges/#easyChals and start working through Coderbyte's easy algorithm scripting challenges using JavaScript.", - "When you are finished pair programming, end the session in Screen Hero session.", + "Your pair will have their own cursor, and will be able to type text on his or her and keyboard.", + "Now it's time to tackle our Bonfires.", + "Go to http://freecodecamp.com/bonfires and start working through our Bonfire challenges.", + "Once you you finish pair programming, end the session in Screen Hero session.", "Congratulations! You have completed your first pair programming session.", - "You should pair program with different campers until you've completed all the Easy, Medium and Hard CoderByte challenges. This is a big time investment, but the JavaScript practice you'll get, along with the scripting and algorithm experience, are well worth it!", - "You can complete CoderByte problems while you continue to work through Free Code Camp's challenges.", - "Be sure to pair program on these challenges, and remember to apply the RSAP methodology.", + "Try to pair program with different campers until you've completed all the Bonfire challenges. This is a big time investment, but the JavaScript practice you'll get, along with the scripting and algorithm experience, are well worth it!", + "You can complete Bonfire challenges while you continue to work through Free Code Camp's challenges. Take your time.", "Mark this challenge as complete and move on." ] }, diff --git a/views/account/show.jade b/views/account/show.jade index 2f4d8648a1..ad95d1b91b 100644 --- a/views/account/show.jade +++ b/views/account/show.jade @@ -24,8 +24,6 @@ block content a.ion-social-linkedin.text-primary(title="@#{username}'s LinkedIn Profile", href=linkedinProfile, target='_blank') - if (codepenProfile) a.ion-social-codepen.text-primary(title="@#{username}'s CodePen Profile", href=codepenProfile, target='_blank') - - if (coderbyteProfile) - a.ion-social-javascript.text-primary(title="@#{username}'s CoderByte Profile", href=coderbyteProfile, target='_blank') .visible-md.visible-lg .col-xs-12.col-sm-12.col-md-4.text-justify h1.flat-top.wrappable= name diff --git a/views/partials/about.jade b/views/partials/about.jade index 26ca70c763..429e3a2850 100644 --- a/views/partials/about.jade +++ b/views/partials/about.jade @@ -20,7 +20,7 @@ p.negative-10 "I code whenever I'm not sleeping or in school. Making computers obey me is a dream come true." .col-xs-12.col-sm-4.col-md-3.team-member h3.negative-10.text-nowrap Branden Byers - h4.negative-10.text-nowrap Community Builder + h4.negative-10.text-nowrap Instructional Designer img.profile-image(src='https://s3.amazonaws.com/freecodecamp/branden-byers.jpg' alt="Branden Byers picture") h4.text-nowrap Madison, Wisconsin p.negative-10 "Cookbook author and stay-at-home-dad. Started coding as a kid, got distracted, but now I'm back in full JavaScript force!" @@ -68,7 +68,7 @@ p.negative-10 "I love origami, piano, and playing minecraft with my kids. My JavaScript grows stronger every day." .col-xs-12.col-sm-4.col-md-3.team-member h3.negative-10.text-nowrap Charles Watson - h4.negative-10.text-nowrap iOS Engineer + h4.negative-10.text-nowrap JavaScript Engineer img.profile-image(src='https://s3.amazonaws.com/freecodecamp/charles-watson.jpg' alt="Charles Watson's picture") h4.text-nowrap Minneapolis, Minnesota p.negative-10 "I skipped college. I build iOS apps. I love the obstacles and puzzles that coding presents me." diff --git a/views/resources/nonprofit-project-instructions.jade b/views/resources/nonprofit-project-instructions.jade index e121b5b817..8c88acf588 100644 --- a/views/resources/nonprofit-project-instructions.jade +++ b/views/resources/nonprofit-project-instructions.jade @@ -14,8 +14,10 @@ block content li Read this document, which will answer many questions you may have about our nonprofit projects:   a(href="http://forum.freecodecamp.com/t/an-introduction-to-our-nonprofit-projects/856" target="_blank") http://forum.freecodecamp.com/t/an-introduction-to-our-nonprofit-projects/856 | . - li We'll send you an invite to our Nonprofit Projects Trello board. Once we do, go there and add yourself to each of the nonprofit projects that interests you. - li Finish any unfinished easy and medium coderbyte challenges. These challenges serve as the Free Code Camp "exit test". You must be complete these before you can start working on nonprofit projects. + li We'll send you an invite to our Nonprofit Projects Trello board. Once we do, go there and add yourself to at least 3 nonprofit projects that interest you. + li Finish any unfinished Bonfire challenges. These challenges serve as the Free Code Camp "exit test". You must complete these before you can start working on nonprofit projects. If you completed CoderByte or CodeWars challenges instead of Bonfire, email us and we'll take a look:  + a(href="mailto:team@freecodecamp.com") team@freecodecamp.com + | . h4 Please email us if you have further questions:   a(href="mailto:team@freecodecamp.com") team@freecodecamp.com | . \ No newline at end of file diff --git a/views/resources/pair-program-with-team-viewer.jade b/views/resources/pair-program-with-team-viewer.jade deleted file mode 100644 index dca54e7897..0000000000 --- a/views/resources/pair-program-with-team-viewer.jade +++ /dev/null @@ -1,27 +0,0 @@ -extends ../layout -block content - .row - .col-sm-12.col-md-8.col-xs-12 - .panel.panel-primary - .panel-heading #{name} (takes #{time} minutes) - .panel.panel-body - //.embed-responsive.embed-responsive-16by9 - // iframe.embed-responsive-item(src='//player.vimeo.com/video/#{video}') - h3 Steps: - h4 - ol - for step in steps - li!= step - a.btn.btn-primary.btn-big.btn-block.completed-challenge(href='/challenges/34') Take me back to the Pair Programming Challenge - .panel-footer.text-center - span Need a break? Check out our:  - a(href="https://gitter.im/FreeCodeCamp/FreeCodeCamp", target="_blank") Chat Room - |  ,  - a(href="http://blog.freecodecamp.com", target="_blank") Blog - |  ,  - a(href="https://twitter.com/freecodecamp", target="_blank") Twitter Feed - |  , or  - a(href="https://reddit.com/r/freecodecamp", target="_blank") Subreddit - | . - .col-sm-12.col-md-4.col-xs-12 - include ../partials/challenges \ No newline at end of file From b691a35163e8197d161577475ff6c2be579687b6 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Fri, 13 Feb 2015 11:13:09 -0800 Subject: [PATCH 02/13] merge challenge entry point into challenge seed --- seed_data/bonfires.json | 322 ++++++++++++++++++---------------------- 1 file changed, 144 insertions(+), 178 deletions(-) diff --git a/seed_data/bonfires.json b/seed_data/bonfires.json index 52a74e78d9..c7fcddb49f 100644 --- a/seed_data/bonfires.json +++ b/seed_data/bonfires.json @@ -1,6 +1,6 @@ [ { - "_id" : "ad7123c8c441eddfaeb5bdef", + "_id": "ad7123c8c441eddfaeb5bdef", "name": "Meet Bonfire", "difficulty": "0", "description": [ @@ -13,26 +13,24 @@ "expect(meetBonfire(\"test\")).to.be.a(\"boolean\");", "expect(meetBonfire(\"test\")).to.be.true;" ], - "challengeSeed": "function meetBonfire(argument) {\n // Good luck!\n console.log(\"you can read this function's argument in the developer tools\", argument);\n\n return false;\n}\n\n", - "challengeEntryPoint": "meetBonfire(\"You can do this!\");" + "challengeSeed": "function meetBonfire(argument) {\n // Good luck!\n console.log(\"you can read this function's argument in the developer tools\", argument);\n\n return false;\n}\n\n\n\nmeetBonfire(\"You can do this!\");" }, { - "_id": "a202eed8fc186c8434cb6d61", - "name": "Reverse a String", - "difficulty": "1.01", - "tests": [ - "expect(reverseString('hello')).to.be.a('String');", - "expect(reverseString('hello')).to.equal('olleh');", - "expect(reverseString('Howdy')).to.equal('ydwoH');", - "expect(reverseString('Greetings from Earth')).to.equal('htraE morf sgniteerG');" - ], - "description": [ - "Reverse the provided string.", - "You may need to turn the string into an array before you can reverse it.", - "Your result must be a string." - ], - "challengeEntryPoint": "reverseString('hello');", - "challengeSeed": "function reverseString(str) {\n return str;\r\n}" + "_id": "a202eed8fc186c8434cb6d61", + "name": "Reverse a String", + "difficulty": "1.01", + "tests": [ + "expect(reverseString('hello')).to.be.a('String');", + "expect(reverseString('hello')).to.equal('olleh');", + "expect(reverseString('Howdy')).to.equal('ydwoH');", + "expect(reverseString('Greetings from Earth')).to.equal('htraE morf sgniteerG');" + ], + "description": [ + "Reverse the provided string.", + "You may need to turn the string into an array before you can reverse it.", + "Your result must be a string." + ], + "challengeSeed": "function reverseString(str) {\n return str;\r\n}\n\nreverseString('hello');" }, { "_id": "a302f7aae1aa3152a5b413bc", @@ -50,11 +48,10 @@ "Factorials are often represented with the shorthand notation n!", "For example: 5! = 1 * 2 * 3 * 4 * 5 = 120f" ], - "challengeSeed": "function factorialize(num) {\n return num;\r\n}", - "challengeEntryPoint": "factorialize(5);" + "challengeSeed": "function factorialize(num) {\n return num;\r\n}\n\nfactorialize(5);" }, { - "_id" : "aaa48de84e1ecc7c742e1124", + "_id": "aaa48de84e1ecc7c742e1124", "name": "Check for Palindromes", "difficulty": "1.03", "description": [ @@ -72,8 +69,7 @@ "assert.deepEqual(palindrome(\"never odd or even\"), true);", "assert.deepEqual(palindrome(\"nope\"), false);" ], - "challengeSeed": "function palindrome(str) {\n // Good luck!\n return true;\n}\n\n", - "challengeEntryPoint": "palindrome(\"eye\");" + "challengeSeed": "function palindrome(str) {\n // Good luck!\n return true;\n}\n\n\n\npalindrome(\"eye\");" }, { "_id": "a26cbbe9ad8655a977e1ceb5", @@ -83,8 +79,7 @@ "Return the length of the longest word in the provided sentence.", "Your response should be a number." ], - "challengeEntryPoint": "findLongestWord('The quick brown fox jumped over the lazy dog');", - "challengeSeed": "function findLongestWord(str) {\n return str.length;\r\n}", + "challengeSeed": "function findLongestWord(str) {\n return str.length;\r\n}\n\nfindLongestWord('The quick brown fox jumped over the lazy dog');", "tests": [ "expect(findLongestWord('The quick brown fox jumped over the lazy dog')).to.be.a('Number');", "expect(findLongestWord('The quick brown fox jumped over the lazy dog')).to.equal(6);", @@ -101,8 +96,7 @@ "Return the provided string with the first letter of each word capitalized.", "For the purpose of this exercise, you should also capitalize connecting words like 'the' and 'of'." ], - "challengeEntryPoint": "titleCase(\"I'm a little tea pot\");", - "challengeSeed": "function titleCase(str) {\n return str;\r\n}", + "challengeSeed": "function titleCase(str) {\n return str;\r\n}\n\ntitleCase(\"I'm a little tea pot\");", "tests": [ "expect(titleCase(\"I'm a little tea pot\")).to.be.a('String');", "expect(titleCase(\"I'm a little tea pot\")).to.equal(\"I'm A Little Tea Pot\");", @@ -119,56 +113,53 @@ "Remember, you can iterate through an array with a simple for loop, and access each member with array syntax arr[i] .", "If you are writing your own Chai.js tests, be sure to use a deep equal statement instead of an equal statement when comparing arrays." ], - "challengeEntryPoint": "largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);", - "challengeSeed": "function largestOfFour(arr) {\n // You can do this!\r\n return arr;\r\n}", + "challengeSeed": "function largestOfFour(arr) {\n // You can do this!\r\n return arr;\r\n}\n\nlargestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);", "tests": [ "expect(largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]])).to.be.a('array');", "(largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]])).should.eql([5,27,39,1001]);", "assert(largestOfFour([[4, 9, 1, 3], [13, 35, 18, 26], [32, 35, 97, 39], [1000000, 1001, 857, 1]]).should.eql([9,35,97,1000000]));" ] }, - { - "_id":"acda2fb1324d9b0fa741e6b5", - "name":"Confirm the Ending", - "difficulty":"1.07", - "description":[ + "_id": "acda2fb1324d9b0fa741e6b5", + "name": "Confirm the Ending", + "difficulty": "1.07", + "description": [ "Check if a string (first argument) ends with the given target string (second argument)." ], - "challengeEntryPoint":"end('Bastian', 'n');", - "challengeSeed":"function end(str, target) {\n // \"Never give up and good luck will find you.\"\r\n // -- Falcor\r\n return str;\r\n}", - "tests":[ + + "challengeSeed": "function end(str, target) {\n // \"Never give up and good luck will find you.\"\r\n // -- Falcor\r\n return str;\r\n}\n\nend('Bastian', 'n');", + "tests": [ "assert.strictEqual(end('Bastian', 'n'), true, 'should equal true if target equals end of string');", "assert.strictEqual(end('He has to give me a new name', 'name'), true, 'should equal true if target equals end of string');", "assert.strictEqual(end('If you want to save our world, you must hurry. We dont know how much longer we can withstand the nothing', 'mountain'), false, 'should equal false if target does not equal end of string');" ] }, { - "_id":"afcc8d540bea9ea2669306b6", - "name":"Repeat a string repeat a string", - "difficulty":"1.08", - "description":[ + "_id": "afcc8d540bea9ea2669306b6", + "name": "Repeat a string repeat a string", + "difficulty": "1.08", + "description": [ "Repeat a given string (first argument) n times (second argument). Return an empty string if n is a negative number." ], - "challengeEntryPoint":"repeat('abc', 3);", - "challengeSeed":"function repeat(str, num) {\n // repeat after me\r\n return str;\r\n}", - "tests":[ + "challengeSeed": "function repeat(str, num) {\n // repeat after me\r\n return str;\r\n}\n\nrepeat('abc', 3);", + "tests": [ "assert.strictEqual(repeat('*', 3), '***', 'should repeat a string n times');", "assert.strictEqual(repeat('abc', 3), 'abcabcabc', 'should repeat a string n times');", "assert.strictEqual(repeat('abc', -2), '', 'should return an empty string for negative numbers');" ] }, { - "_id":"ac6993d51946422351508a41", - "name":"Truncate a string", - "difficulty":"1.09", - "description":[ + "_id": "ac6993d51946422351508a41", + "name": "Truncate a string", + "difficulty": "1.09", + "description": [ "Truncate a string (first argument) if it is longer than the given maximum string length (second argument). Return the truncated string with a '...' ending.", "Note that the three dots at the end add to the string length." ], - "challengeEntryPoint":"truncate('A-tisket a-tasket A green and yellow basket', 11);", - "challengeSeed":"function truncate(str, num) {\n // Clear out that junk in your trunc\r\n return str;\r\n}", - "tests":[ + "challengeSeed": "function truncate(str, num) {\n // Clear out that junk in your trunc\r\n return str;\r\n}", + "challengeEntryPoint": "truncate('A-tisket a-tasket A green and yellow basket', 11);", + "tests": [ "var string = 'A-tisket a-tasket A green and yellow basket’;", "assert.strictEqual(truncate('A-tisket a-tasket A green and yellow basket’, 24), 'A-tisket…’, ’should truncate string the given length');", "assert.strictEqual(truncate('A-tisket a-tasket A green and yellow basket’, 'A-tisket a-tasket A green and yellow basket’.length), string, 'should not truncate if string is = length');", @@ -176,89 +167,83 @@ ] }, { - "_id":"a9bd25c716030ec90084d8a1", - "name":"Chunky Monkey", - "difficulty":"1.10", - "description":[ + "_id": "a9bd25c716030ec90084d8a1", + "name": "Chunky Monkey", + "difficulty": "1.10", + "description": [ "Write a function that splits an array (first argument) into groups the length of size (second argument) and returns them as a multidimensional array." ], - "challengeEntryPoint":"chunk((['a', 'b', 'c', 'd'], 2));", - "challengeSeed":"function chunk(arr, size) {\n // Break it up.\r\n return arr;\r\n}", - "tests":[ + "challengeSeed": "function chunk(arr, size) {\n // Break it up.\r\n return arr;\r\n}\n\nchunk((['a', 'b', 'c', 'd'], 2));", + "tests": [ "assert.deepEqual(chunk(['a', 'b', 'c', 'd'], 2), [['a', 'b'], ['c', 'd']], 'should return chunked arrays');", "assert.deepEqual(chunk([0, 1, 2, 3, 4, 5], 3), [[0, 1, 2], [3, 4, 5]], 'should return chunked arrays');", "assert.deepEqual(chunk([0, 1, 2, 3, 4, 5], 4), [[0, 1, 2, 3], [4, 5]], 'should return cthe last chunk as remaining elements');" ] }, { - "_id":"ab31c21b530c0dafa9e241ee", - "name":"Slasher Flick", - "difficulty":"1.11", - "description":[ + "_id": "ab31c21b530c0dafa9e241ee", + "name": "Slasher Flick", + "difficulty": "1.11", + "description": [ "Return the remaining elements of an array after chopping off n elements from the head." ], - "challengeEntryPoint":"slasher([1, 2, 3], 2);", - "challengeSeed":"function slasher(arr) {\n // it doesn't allways pay to be first\r\n return arr;\r\n}", - "tests":[ + "challengeSeed": "function slasher(arr) {\n // it doesn't allways pay to be first\r\n return arr;\r\n}\n\nslasher([1, 2, 3], 2);", + "tests": [ "assert.deepEqual(slasher([1, 2, 3], 2), [3], 'should drop the first two elements');", "assert.deepEqual(slasher([1, 2, 3], 0), [1, 2, 3], 'should return all elements when n < 1');", "assert.deepEqual(slasher([1, 2, 3], 9), [], 'should return an empty array when n >= array.length');" ] }, { - "_id":"adf08ec01beb4f99fc7a68f2", - "name":"Falsey Bouncer", - "difficulty":"1.50", - "description":[ + "_id": "adf08ec01beb4f99fc7a68f2", + "name": "Falsey Bouncer", + "difficulty": "1.50", + "description": [ "Remove all falsey values from an array.", "Falsey values in javascript are false, null, 0, \"\", undefined, and NaN." ], - "challengeEntryPoint":"bouncer([7, 'ate', '', false, 9]);", - "challengeSeed":"function bouncer(arr) {\n // Don't show a false ID to this bouncer.\r\n return arr;\r\n}", - "tests":[ + "challengeSeed": "function bouncer(arr) {\n // Don't show a false ID to this bouncer.\r\n return arr;\r\n}\n\nbouncer([7, 'ate', '', false, 9]);", + "tests": [ "assert.deepEqual(bouncer([7, 'ate', '', false, 9]), [7, 'ate', 9], 'should remove falsey values');", "assert.deepEqual(bouncer(['a', 'b', 'c']), ['a', 'b', 'c'], 'should return full array if no falsey elements');", "assert.deepEqual(bouncer([false, null, 0]), [], 'should return empty array if all elements are falsey');" ] }, { - "_id":"a8e512fbe388ac2f9198f0fa", - "name":"Where art thou", - "difficulty":"1.55", - "description":[ + "_id": "a8e512fbe388ac2f9198f0fa", + "name": "Where art thou", + "difficulty": "1.55", + "description": [ "Maketh a function that looks through a list (first argument) and returns an array of all objects that have equivalent property values (second argument)." ], - "challengeEntryPoint":"where([{ first: 'Romeo', last: 'Montague' }, { first: 'Mercutio', last: null }, { first: 'Tybalt', last: 'Capulet' }], { last: 'Capulet' });", - "challengeSeed":"function where(collection, source) {\n var arr = [];\r\n // What's in a name?\r\n return arr;\r\n}", - "tests":[ + "challengeSeed": "function where(collection, source) {\n var arr = [];\r\n // What's in a name?\r\n return arr;\r\n}\n\nwhere([{ first: 'Romeo', last: 'Montague' }, { first: 'Mercutio', last: null }, { first: 'Tybalt', last: 'Capulet' }], { last: 'Capulet' });", + "tests": [ "assert.deepEqual(where([{ first: 'Romeo', last: 'Montague' }, { first: 'Mercutio', last: null }, { first: 'Tybalt', last: 'Capulet' }], { last: 'Capulet' }), [{ first: 'Tybalt', last: 'Capulet' }], 'should return an array of objects');", "assert.deepEqual(where([{ 'a': 1 }, { 'a': 1 }, { 'a': 1, 'b': 2 }], { 'a': 1 }), [{ 'a': 1 }, { 'a': 1 }, { 'a': 1 }], 'should return with multiples');" ] }, { - "_id":"a39963a4c10bc8b4d4f06d7e", - "name":"Seek and Destroy", - "difficulty":"1.60", - "description":[ + "_id": "a39963a4c10bc8b4d4f06d7e", + "name": "Seek and Destroy", + "difficulty": "1.60", + "description": [ "Remove all values (last argument(s)) from an array (first argument) and return as a new array." ], - "challengeEntryPoint":"destroyer([1, 2, 3, 1, 2, 3], 2, 3);", - "challengeSeed":"function destroyer(arr) {\n // Remove all the values\r\n return arr;\r\n}", - "tests":[ + "challengeSeed": "function destroyer(arr) {\n // Remove all the values\r\n return arr;\r\n}\n\ndestroyer([1, 2, 3, 1, 2, 3], 2, 3);", + "tests": [ "assert.strictEqual(destroyer([1, 2, 3, 1, 2, 3], 2, 3), [1, 1], 'should remove correct values from an array');", "assert.strictEqual(destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3), [1, 5, 1], 'should remove correct values from an array');" ] }, { - "_id":"a24c1a4622e3c05097f71d67", - "name":"Where do I belong?", - "difficulty":"1.61", - "description":[ + "_id": "a24c1a4622e3c05097f71d67", + "name": "Where do I belong?", + "difficulty": "1.61", + "description": [ "Return the lowest index at which a value (second argument) should be inserted into a sorted array (first argument)." ], - "challengeEntryPoint":"where([40, 60], 50);", - "challengeSeed":"function where(arr, num) {\n // Find my place in this sorted array.\r\n return num;\r\n}", - "tests":[ + "challengeSeed": "function where(arr, num) {\n // Find my place in this sorted array.\r\n return num;\r\n}\n\nwhere([40, 60], 50);", + "tests": [ "var numbers = [10, 20, 30, 40, 50], num = 35;", "var indexForNum = where(numbers, num);", "assert.equal(indexForNum, 3, '35 should be inserted at index 3');", @@ -274,8 +259,7 @@ "We'll pass you an array of two numbers. Return the sum of those two numbers and all numbers between them.", "The lowest number will not always come first." ], - "challengeEntryPoint": "sumAll([1, 4]);", - "challengeSeed": "function sumAll(arr) {\n return(1);\r\n}", + "challengeSeed": "function sumAll(arr) {\n return(1);\r\n}\n\nsumAll([1, 4]);", "tests": [ "expect(sumAll([1, 4])).to.be.a('Number');", "expect(sumAll([1, 4])).to.equal(10);", @@ -291,8 +275,7 @@ "description": [ "Compare two arrays and return a new array with any items not found in both of the original arrays." ], - "challengeEntryPoint": "diff([1, 2, 3, 5], [1, 2, 3, 4, 5]);", - "challengeSeed": "function diff(arr1, arr2) {\n var newArr = [];\r\n // Same, same; but different.\r\n return newArr;\r\n}", + "challengeSeed": "function diff(arr1, arr2) {\n var newArr = [];\r\n // Same, same; but different.\r\n return newArr;\r\n}\n\ndiff([1, 2, 3, 5], [1, 2, 3, 4, 5]);", "tests": [ "expect(diff([1, 2, 3, 5], [1, 2, 3, 4, 5])).to.be.a('array');", "assert.deepEqual(diff(['diorite', 'andesite', 'grass', 'dirt', 'pink wool', 'dead shrub'], ['diorite', 'andesite', 'grass', 'dirt', 'dead shrub']), ['pink wool'], 'arrays with only one difference');", @@ -304,16 +287,15 @@ ] }, { - "_id":"a77dbc43c33f39daa4429b4f", - "name":"Boo who?", - "difficulty":"2.06", - "description":[ + "_id": "a77dbc43c33f39daa4429b4f", + "name": "Boo who?", + "difficulty": "2.06", + "description": [ "Check if a value is classified as a boolean primitive. Return true or false.", "Boolean primitives are true and false." ], - "challengeEntryPoint":"boo(null);", - "challengeSeed":"function boo(boolean) {\n // What is the new fad diet for ghost developers? The Boolean.\r\n return boolean;\r\n}", - "tests":[ + "challengeSeed": "function boo(boolean) {\n // What is the new fad diet for ghost developers? The Boolean.\r\n return boolean;\r\n}\n\nboo(null);", + "tests": [ "assert.strictEqual(boo(true), true);", "assert.strictEqual(boo(false), true);", "assert.strictEqual(boo(Object(true)), true);", @@ -328,43 +310,40 @@ ] }, { - "_id":"a105e963526e7de52b219be9", - "name":"Sorted Union", - "difficulty":"2.07", - "description":[ + "_id": "a105e963526e7de52b219be9", + "name": "Sorted Union", + "difficulty": "2.07", + "description": [ "Write a function that takes two or more arrays and returns a new array of unique values sorted in order." ], - "challengeEntryPoint":"unite([1, 2, 3], [5, 2, 1, 4], [2, 1]);", - "challengeSeed":"function unite(arr) {\n return arr;\r\n}", - "tests":[ + "challengeSeed": "function unite(arr) {\n return arr;\r\n}\n\nunite([1, 2, 3], [5, 2, 1, 4], [2, 1]);", + "tests": [ "assert.deepEqual(unite([1, 3, 2], [5, 2, 1, 4], [2, 1]), [1, 3, 2, 5, 4], 'should return the union of the given arrays');", "assert.deepEqual(unite([1, 3, 2], [1, [5]], [2, [4]]), [1, 3, 2, [5], [4]], 'should not flatten nested arrays');" ] }, { - "_id":"a6b0bb188d873cb2c8729495", - "name":"Convert HTML Entities", - "difficulty":"2.07", - "description":[ + "_id": "a6b0bb188d873cb2c8729495", + "name": "Convert HTML Entities", + "difficulty": "2.07", + "description": [ "Convert the characters \"&\", \"<\", \">\", '\"', and \"'\", in a string to their corresponding HTML entities." ], - "challengeEntryPoint":"convert('Dolce & Gabbana');", - "challengeSeed":"function convert(str) {\n // :)\r\n return str;\r\n}", - "tests":[ + "challengeSeed": "function convert(str) {\n // :)\r\n return str;\r\n}\n\nconvert('Dolce & Gabbana');", + "tests": [ "assert.strictEqual(convert('Dolce & Gabbana'), 'Dolce & Gabbana', 'should escape characters');", "assert.strictEqual(convert('abc'), 'abc', 'should handle strings with nothing to escape');" ] }, { - "_id":"a103376db3ba46b2d50db289", - "name":"Spinal-Tap-Case", - "difficulty":"2.08", - "description":[ + "_id": "a103376db3ba46b2d50db289", + "name": "Spinal-Tap-Case", + "difficulty": "2.08", + "description": [ "Convert a string to spinal case." ], - "challengeEntryPoint":"spinalCase('This Is Spinal Tap');", - "challengeSeed":"function spinalCase(str) {\n // \"It's such a fine line between stupid, and clever.\"\r\n // --David St. Hubbins\r\n return str;\r\n}", - "tests":[ + "challengeSeed": "function spinalCase(str) {\n // \"It's such a fine line between stupid, and clever.\"\r\n // --David St. Hubbins\r\n return str;\r\n}\n\nspinalCase('This Is Spinal Tap');", + "tests": [ "assert.strictEqual(spinalCase('This Is Spinal Tap'), 'this-is-spinal-tap', 'should return spinal case from string with spaces');", "assert.strictEqual(spinalCase('thisIsSpinalTap'), 'this-is-spinal-tap', 'should return spinal case from string with camel case');", "assert.strictEqual(spinalCase('The_Andy_Griffith_Show'), 'the-andy-griffith-show', 'should return spinal case from string with snake case');", @@ -380,8 +359,7 @@ "The first few numbers of the Fibonacci sequence are 1, 1, 2, 3, 5 and 8, and each subsequent number is the sum of the previous two numbers.", "As an example, passing 4 to the function should return 5 because all the odd Fibonacci numbers under 4 are 1, 1, and 3." ], - "challengeEntryPoint": "sumFibs(4);", - "challengeSeed": "function sumFibs(num) {\n return num;\r\n}", + "challengeSeed": "function sumFibs(num) {\n return num;\r\n}\n\nsumFibs(4);", "tests": [ "expect(sumFibs(1)).to.be.a('number');", "expect(sumFibs(1000)).to.equal(1785);", @@ -400,8 +378,7 @@ "A prime number is defined as having only two divisors, 1 and itself. For example, 2 is a prime number because it's only divisible by 1 and 2. 1 isn't a prime number, because it's only divisible by itself.", "The provided number may not be a prime." ], - "challengeEntryPoint": "sumPrimes(10);", - "challengeSeed": "function sumPrimes(num) {\n return num;\r\n}", + "challengeSeed": "function sumPrimes(num) {\n return num;\r\n}\n\nsumPrimes(10);", "tests": [ "expect(sumPrimes(10)).to.be.a('number');", "expect(sumPrimes(10)).to.equal(17);", @@ -416,8 +393,7 @@ "Find the smallest number that evenly divides all numbers in the provided range.", "The range will be an array of two numbers that will not necessarily be in numerical order." ], - "challengeEntryPoint": "smallestCommons([1,5]);", - "challengeSeed": "function smallestCommons(arr) {\n return arr;\r\n}\r\n", + "challengeSeed": "function smallestCommons(arr) {\n return arr;\r\n}\r\n\n\nsmallestCommons([1,5]);", "tests": [ "expect(smallestCommons([1,5])).to.be.a('number');", "expect(smallestCommons([1,5])).to.equal(60);", @@ -426,75 +402,70 @@ ] }, { - "_id":"a6e40f1041b06c996f7b2406", - "name":"Finders Keepers", - "difficulty":"2.12", - "description":[ + "_id": "a6e40f1041b06c996f7b2406", + "name": "Finders Keepers", + "difficulty": "2.12", + "description": [ "Create a function that looks through an array (first argument) and returns the first element in the array that passes a truth test (second argument)." ], - "challengeEntryPoint":"find([1, 2, 3, 4], function(num){ return num % 2 === 0; });", - "challengeSeed":"function find(arr, func) {\n var num = 0;\r\n return num;\r\n}", - "tests":[ + "challengeSeed": "function find(arr, func) {\n var num = 0;\r\n return num;\r\n}\n\nfind([1, 2, 3, 4], function(num){ return num % 2 === 0; });", + "tests": [ "assert.strictEqual(find([1, 3, 5, 8, 9, 10], function(num) { return num % 2 === 0; }), 8, 'should return first found value');", "assert.strictEqual(find([1, 3, 5, 9], function(num) { return num % 2 === 0; }), undefined, 'should return undefined if not found');" ] }, { - "_id":"a5deed1811a43193f9f1c841", - "name":"Drop it like it's hot", - "difficulty":"2.13", - "description":[ + "_id": "a5deed1811a43193f9f1c841", + "name": "Drop it like it's hot", + "difficulty": "2.13", + "description": [ "Drop the elements of an array (first argument), starting from the front, until the predicate (second argument) returns true." ], - "challengeEntryPoint":"drop([1, 2, 3], function(n) {return n < 3; });", - "challengeSeed":"function drop(arr, func) {\n // Drop them elements.\r\n return arr;\r\n}", - "tests":[ + "challengeSeed": "function drop(arr, func) {\n // Drop them elements.\r\n return arr;\r\n}\n\ndrop([1, 2, 3], function(n) {return n < 3; });", + "tests": [ "assert.deepEqual(drop([1, 2, 3, 4], function(n) {return n < 3; }), [3, 4], 'should return remaining array');", "assert.deepEqual(drop([1, 2, 3], function(n) {return n < 0; }), [1, 2, 3], 'should return complete array if predicate met in first element.');", "assert.deepEqual(drop([1, 2, 3, 4], function(n) {return n < 5; }), [], 'should return an empty array if predicate does not return true');" ] }, { - "_id":"ab306dbdcc907c7ddfc30830", - "name":"Steamroller", - "difficulty":"2.14", - "description":[ + "_id": "ab306dbdcc907c7ddfc30830", + "name": "Steamroller", + "difficulty": "2.14", + "description": [ "Flatten a nested array. You must account for varying levels of nesting." ], - "challengeEntryPoint":"steamroller([1, [2], [3, [[4]]]]);", - "challengeSeed":"function steamroller(arr) {\n // I'm a steamroller, baby\r\n return arr;\r\n}", - "tests":[ + "challengeSeed": "function steamroller(arr) {\n // I'm a steamroller, baby\r\n return arr;\r\n}\n\nsteamroller([1, [2], [3, [[4]]]]);", + "tests": [ "assert.deepEqual(steamroller([[['a']], [['b']]]), ['a', 'b'], 'should flatten nested arrays');", "assert.deepEqual(steamroller([1, [2], [3, [[4]]]]), [1, 2, 3, 4], 'should flatten nested arrays');", "assert.deepEqual(steamroller([1, [], [3, [[4]]]]), [1, 3, 4], 'should work with empty arrays');" ] }, { - "_id":"a3f503de51cf954ede28891d", - "name":"Symmetric Difference", - "difficulty":"2.20", - "description":[ + "_id": "a3f503de51cf954ede28891d", + "name": "Symmetric Difference", + "difficulty": "2.20", + "description": [ "Create a function that takes two or more arrays and returns an array of the symmetric difference of the provided arrays.", "The mathematical term symmetric difference refers to the elements in two sets that are in either the first or second set, but not in both." ], - "challengeEntryPoint":"sym([1, 2, 3], [5, 2, 1, 4]);", - "challengeSeed":"function sym(arr) {\n return arr;\r\n}", - "tests":[ + "challengeSeed": "function sym(arr) {\n return arr;\r\n}\n\nsym([1, 2, 3], [5, 2, 1, 4]);", + "tests": [ "assert.deepEqual(sym([1, 2, 5], [2, 3, 5], [3, 4, 5]), [1, 4, 5], 'should return the symmetric difference of the given arrays');", "assert.deepEqual(sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]), [1, 4, 5], 'should return an array of unique values');", "assert.deepEqual(sym([1, 1]), [1], 'should return an array of unique values');" ] }, { - "_id":"a10d2431ad0c6a099a4b8b52", - "name":"Everything Be True", - "difficulty":"2.21", - "description":[ + "_id": "a10d2431ad0c6a099a4b8b52", + "name": "Everything Be True", + "difficulty": "2.21", + "description": [ "Check if the predicate (second argument) returns truthy for all elements of a collection (first argument)." ], - "challengeEntryPoint":"every([{'user': 'Tinky-Winky', 'sex': 'male'}, {'user': 'Dipsy', 'sex': 'male'}, {'user': 'Laa-Laa', 'sex': 'female'}, {'user': 'Po', 'sex': 'female'}], 'sex');", - "challengeSeed":"function every(collection, pre) {\n // Does everyone have one of these?\r\n return pre;\r\n}", - "tests":[ + "challengeSeed": "function every(collection, pre) {\n // Does everyone have one of these?\r\n return pre;\r\n}\n\nevery([{'user': 'Tinky-Winky', 'sex': 'male'}, {'user': 'Dipsy', 'sex': 'male'}, {'user': 'Laa-Laa', 'sex': 'female'}, {'user': 'Po', 'sex': 'female'}], 'sex');", + "tests": [ "assert.strictEqual(every([{'user': 'Tinky-Winky', 'sex': 'male'}, {'user': 'Dipsy', 'sex': 'male'}, {'user': 'Laa-Laa', 'sex': 'female'}, {'user': 'Po', 'sex': 'female'}], 'sex'), true, 'should return true if predicate returns truthy for all elements in the collection');", "assert.strictEqual(every([{'user': 'Tinky-Winky', 'sex': 'male'}, {'user': 'Dipsy', 'sex': 'male'}, {'user': 'Laa-Laa', 'sex': 'female'}, {'user': 'Po', 'sex': 'female'}], {'sex', 'female'}), false, 'should return false if predicate returns falsey for any element in the collection');" ] @@ -509,8 +480,7 @@ "These methods must be the only available means for interacting with the object.", "There will be some linting errors on the tests. You may safely ignore them. You should see undefined in the console output." ], - "challengeEntryPoint": "var bob = new Person('Bob Ross');", - "challengeSeed": "var Person = function(firstAndLast) {\n return firstAndLast;\r\n};", + "challengeSeed": "var Person = function(firstAndLast) {\n return firstAndLast;\r\n};\n\nvar bob = new Person('Bob Ross');", "tests": [ "expect(Object.keys(bob).length).to.eql(6);", "expect(bob instanceof Person).to.be.true;", @@ -528,7 +498,7 @@ ] }, { - "_id" : "aff0395860f5d3034dc0bfc9", + "_id": "aff0395860f5d3034dc0bfc9", "name": "Validate US Telephone Numbers", "difficulty": "4.01", "description": [ @@ -561,8 +531,7 @@ "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\");" + "challengeSeed": "function telephoneCheck(str) {\n // Good luck!\n return true;\n}\n\n\n\ntelephoneCheck(\"555-555-5555\");" }, { "_id": "aa2e6f85cab2ab736c9a9b24", @@ -571,8 +540,7 @@ "description": [ "Design a cash register drawer function that accepts purchase price as the first argument, payment as the second argument, and cash-in-drawer (cid) as the third argument. cid is a 2d array listing available currency. Return the string \"Insufficient Funds\" if change due is less than the cash-in-drawer. Return the string \"Closed\" if cash-in-drawer is equal to the change due. Otherwise, return change in coin and bills, sorted in highest to lowest order." ], - "challengeEntryPoint": "drawer(19.50, 20.00, [['PENNY', 1.01], ['NICKEL', 2.05], ['DIME', 3.10], ['QUARTER', 4.25], ['ONE', 90.00], ['FIVE', 55.00], ['TEN', 20.00], ['TWENTY', 60.00], ['ONE HUNDRED', 100.00]]);", - "challengeSeed": "function drawer(price, cash, cid) {\n var change;\r\n // Here is your change, ma'am.\r\n return change;\r\n}\r\n\r\n// Example cash-in-drawer array:\r\n// [['PENNY', 1.01],\r\n// ['NICKEL', 2.05],\r\n// ['DIME', 3.10],\r\n// ['QUARTER', 4.25],\r\n// ['ONE', 90.00],\r\n// ['FIVE', 55.00],\r\n// ['TEN', 20.00],\r\n// ['TWENTY', 60.00],\r\n// ['ONE HUNDRED', 100.00]]", + "challengeSeed": "function drawer(price, cash, cid) {\n var change;\r\n // Here is your change, ma'am.\r\n return change;\r\n}\r\n\r\n// Example cash-in-drawer array:\r\n// [['PENNY', 1.01],\r\n// ['NICKEL', 2.05],\r\n// ['DIME', 3.10],\r\n// ['QUARTER', 4.25],\r\n// ['ONE', 90.00],\r\n// ['FIVE', 55.00],\r\n// ['TEN', 20.00],\r\n// ['TWENTY', 60.00],\r\n// ['ONE HUNDRED', 100.00]]\n\ndrawer(19.50, 20.00, [['PENNY', 1.01], ['NICKEL', 2.05], ['DIME', 3.10], ['QUARTER', 4.25], ['ONE', 90.00], ['FIVE', 55.00], ['TEN', 20.00], ['TWENTY', 60.00], ['ONE HUNDRED', 100.00]]);", "tests": [ "expect(drawer(19.50, 20.00, [['PENNY', 1.01], ['NICKEL', 2.05], ['DIME', 3.10], ['QUARTER', 4.25], ['ONE', 90.00], ['FIVE', 55.00], ['TEN', 20.00], ['TWENTY', 60.00], ['ONE HUNDRED', 100.00]])).to.be.a('array');", "expect(drawer(19.50, 20.00, [['PENNY', 0.01], ['NICKEL', 0], ['DIME', 0], ['QUARTER', 0], ['ONE', 0], ['FIVE', 0], ['TEN', 0], ['TWENTY', 0], ['ONE HUNDRED', 0]])).to.be.a('string');", @@ -590,8 +558,7 @@ "description": [ "Compare and update inventory stored in a 2d array against a second 2d array of a fresh delivery. Update current inventory item quantity, and if an item cannot be found, add the new item and quantity into the inventory array in alphabetical order." ], - "challengeEntryPoint": "// Example inventory lists\r\nvar curInv = [\r\n [21, 'Bowling Ball'],\r\n [2, 'Dirty Sock'],\r\n [1, 'Hair pin'],\r\n [5, 'Microphone']\r\n];\r\n\r\nvar newInv = [\r\n [2, 'Hair Pin'],\r\n [3, 'Half-Eaten Apple'],\r\n [67, 'Bowling Ball'],\r\n [7, 'Toothpaste']\r\n];\r\n\r\ninventory(curInv, newInv);", - "challengeSeed": "function inventory(arr1, arr2) {\n // All inventory must be accounted for or you're fired!\r\n return arr1;\r\n}", + "challengeSeed": "function inventory(arr1, arr2) {\n // All inventory must be accounted for or you're fired!\r\n return arr1;\r\n}\n\n// Example inventory lists\r\nvar curInv = [\r\n [21, 'Bowling Ball'],\r\n [2, 'Dirty Sock'],\r\n [1, 'Hair pin'],\r\n [5, 'Microphone']\r\n];\r\n\r\nvar newInv = [\r\n [2, 'Hair Pin'],\r\n [3, 'Half-Eaten Apple'],\r\n [67, 'Bowling Ball'],\r\n [7, 'Toothpaste']\r\n];\r\n\r\ninventory(curInv, newInv);", "tests": [ "expect(inventory([[21, 'Bowling Ball'], [2, 'Dirty Sock'], [1, 'Hair pin'], [5, 'Microphone']], [[2, 'Hair Pin'], [3, 'Half-Eaten Apple'], [67, 'Bowling Ball'], [7, 'Toothpaste']])).to.be.a('array');", "assert.equal(inventory([[21, 'Bowling Ball'], [2, 'Dirty Sock'], [1, 'Hair pin'], [5, 'Microphone']], [[2, 'Hair Pin'], [3, 'Half-Eaten Apple'], [67, 'Bowling Ball'], [7, 'Toothpaste']]).length, 6);", @@ -601,5 +568,4 @@ "assert.deepEqual(inventory([[0, 'Bowling Ball'], [0, 'Dirty Sock'], [0, 'Hair pin'], [0, 'Microphone']], [[1, 'Hair Pin'], [1, 'Half-Eaten Apple'], [1, 'Bowling Ball'], [1, 'Toothpaste']]), [[1, 'Bowling Ball'], [1, 'Dirty Sock'], [1, 'Hair pin'], [1, 'Half-Eaten Apple'], [1, 'Microphone'], [1, 'Toothpaste']]);" ] } -] - +] \ No newline at end of file From b5c0ad99422c33f2ef5e1e33c32bfad18b2b4722 Mon Sep 17 00:00:00 2001 From: Nathan Leniz Date: Fri, 13 Feb 2015 20:55:49 -0500 Subject: [PATCH 03/13] Building out new challenge framework to allow controller to determine view type for challenge --- controllers/bonfire.js | 7 - controllers/courseware.js | 95 +++++-- models/Bonfire.js | 3 +- ...k_v0.1.1.js => bonfireFramework_v0.1.2.js} | 7 +- ....js => coursewaresHCJQFramework_v0.1.1.js} | 0 .../lib/coursewares/coursewaresJSFramework.js | 245 ++++++++++++++++++ public/js/main.js | 3 + seed_data/bonfires.json | 26 +- seed_data/coursewares.json | 45 +++- views/bonfire/bonfire.jade | 2 +- views/bonfire/show.jade | 3 +- views/coursewares/show.jade | 7 +- views/coursewares/showJS.jade | 83 ++++++ views/coursewares/showVideo.jade | 47 ++++ 14 files changed, 515 insertions(+), 58 deletions(-) rename public/js/lib/bonfire/{bonfireFramework_v0.1.1.js => bonfireFramework_v0.1.2.js} (96%) rename public/js/lib/coursewares/{coursewaresFramework_v0.1.1.js => coursewaresHCJQFramework_v0.1.1.js} (100%) create mode 100644 public/js/lib/coursewares/coursewaresJSFramework.js create mode 100644 views/coursewares/showJS.jade create mode 100644 views/coursewares/showVideo.jade diff --git a/controllers/bonfire.js b/controllers/bonfire.js index 514d473130..49b143fd43 100644 --- a/controllers/bonfire.js +++ b/controllers/bonfire.js @@ -24,7 +24,6 @@ exports.index = function(req, res) { details: '', tests: [], challengeSeed: '', - challengeEntryPoint: '', cc: req.user ? req.user.bonfiresHash : undefined, points: req.user ? req.user.points : undefined, verb: resources.randomVerb(), @@ -105,7 +104,6 @@ exports.returnIndividualBonfire = function(req, res, next) { details: bonfire.description.slice(1), tests: bonfire.tests, challengeSeed: bonfire.challengeSeed, - challengeEntryPoint: bonfire.challengeEntryPoint, cc: !!req.user, points: req.user ? req.user.points : undefined, verb: resources.randomVerb(), @@ -131,7 +129,6 @@ exports.returnGenerator = function(req, res) { details: null, tests: null, challengeSeed: null, - challengeEntryPoint: null, bonfireHash: randomString() }); }; @@ -160,7 +157,6 @@ exports.testBonfire = function(req, res) { bonfireTests = req.body.tests, bonfireDifficulty = req.body.difficulty, bonfireDescription = req.body.description, - bonfireEntryPoint = req.body.challengeEntryPoint, bonfireChallengeSeed = req.body.challengeSeed; bonfireTests = bonfireTests.split('\r\n'); bonfireDescription = bonfireDescription.split('\r\n'); @@ -176,7 +172,6 @@ exports.testBonfire = function(req, res) { details: bonfireDescription.slice(1), tests: bonfireTests, challengeSeed: bonfireChallengeSeed, - challengeEntryPoint: bonfireEntryPoint, cc: req.user ? req.user.bonfiresHash : undefined, points: req.user ? req.user.points : undefined, verb: resources.randomVerb(), @@ -202,7 +197,6 @@ exports.generateChallenge = function(req, res) { bonfireTests = req.body.tests, bonfireDifficulty = req.body.difficulty, bonfireDescription = req.body.description, - bonfireEntryPoint = req.body.challengeEntryPoint, bonfireChallengeSeed = req.body.challengeSeed; bonfireTests = bonfireTests.split('\r\n'); bonfireDescription = bonfireDescription.split('\r\n'); @@ -216,7 +210,6 @@ exports.generateChallenge = function(req, res) { name: bonfireName, difficulty: bonfireDifficulty, description: bonfireDescription, - challengeEntryPoint: bonfireEntryPoint, challengeSeed: bonfireChallengeSeed, tests: bonfireTests }; diff --git a/controllers/courseware.js b/controllers/courseware.js index fe48720a35..eca76fd68a 100644 --- a/controllers/courseware.js +++ b/controllers/courseware.js @@ -72,23 +72,84 @@ exports.returnIndividualCourseware = function(req, res, next) { return res.redirect('../coursewares/' + dashedNameFull); } - // Render the view for the user - res.render('coursewares/show', { - title: courseware.name, - dashedName: dashedName, - name: courseware.name, - brief: courseware.description[0], - details: courseware.description.slice(1), - tests: courseware.tests, - challengeSeed: courseware.challengeSeed, - cc: !!req.user, - points: req.user ? req.user.points : undefined, - verb: resources.randomVerb(), - phrase: resources.randomPhrase(), - compliment: resources.randomCompliment(), - coursewareHash: courseware._id, - environment: resources.whichEnvironment() - }); + var challengeType = { + 0 : function() { + res.render('coursewares/show', { + title: courseware.name, + dashedName: dashedName, + name: courseware.name, + brief: courseware.description[0], + details: courseware.description.slice(1), + tests: courseware.tests, + challengeSeed: courseware.challengeSeed, + cc: !!req.user, + points: req.user ? req.user.points : undefined, + verb: resources.randomVerb(), + phrase: resources.randomPhrase(), + compliment: resources.randomCompliment(), + coursewareHash: courseware._id, + environment: resources.whichEnvironment() + }); + }, + + 1 : function() { + res.render('coursewares/showJS', { + title: courseware.name, + dashedName: dashedName, + name: courseware.name, + brief: courseware.description[0], + details: courseware.description.slice(1), + tests: courseware.tests, + challengeSeed: courseware.challengeSeed, + cc: !!req.user, + points: req.user ? req.user.points : undefined, + verb: resources.randomVerb(), + phrase: resources.randomPhrase(), + compliment: resources.randomCompliment(), + coursewareHash: courseware._id, + environment: resources.whichEnvironment(), + + }); + }, + + 2: function() { + res.render('coursewares/showVideo', { + title: courseware.name, + dashedName: dashedName, + name: courseware.name, + details: courseware.description, + tests: courseware.tests, + video: courseware.challengeSeed[0], + cc: !!req.user, + points: req.user ? req.user.points : undefined, + verb: resources.randomVerb(), + phrase: resources.randomPhrase(), + compliment: resources.randomCompliment(), + coursewareHash: courseware._id, + environment: resources.whichEnvironment() + }); + } + }; + + return challengeType[courseware.challengeType](); + + //// Render the view for the user + //res.render('coursewares/show', { + // title: courseware.name, + // dashedName: dashedName, + // name: courseware.name, + // brief: courseware.description[0], + // details: courseware.description.slice(1), + // tests: courseware.tests, + // challengeSeed: courseware.challengeSeed, + // cc: !!req.user, + // points: req.user ? req.user.points : undefined, + // verb: resources.randomVerb(), + // phrase: resources.randomPhrase(), + // compliment: resources.randomCompliment(), + // coursewareHash: courseware._id, + // environment: resources.whichEnvironment() + //}); }); }; diff --git a/models/Bonfire.js b/models/Bonfire.js index d8785f7196..cee4c8413a 100644 --- a/models/Bonfire.js +++ b/models/Bonfire.js @@ -15,8 +15,7 @@ var bonfireSchema = new mongoose.Schema({ difficulty: String, description: Array, tests: Array, - challengeSeed: String, - challengeEntryPoint: String, + challengeSeed: String }); module.exports = mongoose.model('Bonfire', bonfireSchema); diff --git a/public/js/lib/bonfire/bonfireFramework_v0.1.1.js b/public/js/lib/bonfire/bonfireFramework_v0.1.2.js similarity index 96% rename from public/js/lib/bonfire/bonfireFramework_v0.1.1.js rename to public/js/lib/bonfire/bonfireFramework_v0.1.2.js index 03d531a5a0..4b2edebb0e 100644 --- a/public/js/lib/bonfire/bonfireFramework_v0.1.1.js +++ b/public/js/lib/bonfire/bonfireFramework_v0.1.2.js @@ -73,11 +73,10 @@ var editorValue; var challengeSeed = challengeSeed || null; var tests = tests || []; -var challengeEntryPoint = challengeEntryPoint || null; if (challengeSeed !== null) { - editorValue = challengeSeed + '\n\n' + challengeEntryPoint; + editorValue = challengeSeed; } else { editorValue = nonChallengeValue; } @@ -121,9 +120,7 @@ function bonfireExecute() { userJavaScript = removeComments(userJavaScript); userJavaScript = scrapeTests(userJavaScript); // simple fix in case the user forgets to invoke their function - if (challengeEntryPoint && challengeSeed) { - //userJavaScript = challengeEntryPoint + ' ' + userJavaScript; - } + submit(userJavaScript, function(cls, message) { if (cls) { codeOutput.setValue(message.error); diff --git a/public/js/lib/coursewares/coursewaresFramework_v0.1.1.js b/public/js/lib/coursewares/coursewaresHCJQFramework_v0.1.1.js similarity index 100% rename from public/js/lib/coursewares/coursewaresFramework_v0.1.1.js rename to public/js/lib/coursewares/coursewaresHCJQFramework_v0.1.1.js diff --git a/public/js/lib/coursewares/coursewaresJSFramework.js b/public/js/lib/coursewares/coursewaresJSFramework.js new file mode 100644 index 0000000000..72a24eff4d --- /dev/null +++ b/public/js/lib/coursewares/coursewaresJSFramework.js @@ -0,0 +1,245 @@ +var widgets = []; +var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("codeEditor"), { + lineNumbers: true, + mode: "javascript", + theme: 'monokai', + runnable: true, + lint: true, + matchBrackets: true, + autoCloseBrackets: true, + scrollbarStyle: 'null', + lineWrapping: true, + gutters: ["CodeMirror-lint-markers"], + onKeyEvent: doLinting +}); +var editor = myCodeMirror; +editor.setSize("100%", "auto"); + +// Hijack tab key to enter two spaces intead +editor.setOption("extraKeys", { + Tab: function(cm) { + var spaces = Array(cm.getOption("indentUnit") + 1).join(" "); + cm.replaceSelection(spaces); + }, + "Ctrl-Enter": function() { + bonfireExecute(); + return false; + } +}); + + + +var attempts = 0; +if (attempts) { + attempts = 0; +} + +// Default value for editor if one isn't provided in (i.e. a challenge) +var nonChallengeValue = '/*Welcome to Bonfire, Free Code Camp\'s future CoderByte replacement.\n' + + 'Please feel free to use Bonfire as an in-browser playground and linting tool.\n' + + 'Note that you can also write tests using Chai.js by using the keywords assert and expect */\n\n' + + 'function test() {\n' + + ' assert(2 !== 3, "2 is not equal to 3");\n' + + ' return [1,2,3].map(function(elem) {\n' + + ' return elem * elem;\n' + + ' });\n' + + '}\n' + + 'expect(test()).to.be.a("array");\n\n' + + 'assert.deepEqual(test(), [1,4,9]);\n\n' + + 'var foo = test();\n' + + 'foo.should.be.a("array");\n\n' + + 'test();\n'; + +var codeOutput = CodeMirror.fromTextArea(document.getElementById("codeOutput"), { + lineNumbers: false, + mode: "text", + theme: 'monokai', + readOnly: 'nocursor', + lineWrapping: true +}); + +codeOutput.setValue('/**\n' + +' * Your output will go here.\n' + ' * Console.log() -type statements\n' + +' * will appear in your browser\'s\n' + ' * DevTools JavaScript console.\n' + +' */'); +codeOutput.setSize("100%", "100%"); +var info = editor.getScrollInfo(); +var after = editor.charCoords({line: editor.getCursor().line + 1, ch: 0}, "local").top; +if (info.top + info.clientHeight < after) + editor.scrollTo(null, after - info.clientHeight + 3); + +var editorValue; + + +var challengeSeed = challengeSeed || null; +var tests = tests || []; + +var allSeeds = ''; +(function() { + challengeSeed.forEach(function(elem) { + allSeeds += elem + '\n'; + }); +})(); + +editorValue = allSeeds; + + +myCodeMirror.setValue(editorValue); + +function doLinting () { + editor.operation(function () { + for (var i = 0; i < widgets.length; ++i) + editor.removeLineWidget(widgets[i]); + widgets.length = 0; + JSHINT(editor.getValue()); + for (var i = 0; i < JSHINT.errors.length; ++i) { + var err = JSHINT.errors[i]; + if (!err) continue; + var msg = document.createElement("div"); + var icon = msg.appendChild(document.createElement("span")); + icon.innerHTML = "!!"; + icon.className = "lint-error-icon"; + msg.appendChild(document.createTextNode(err.reason)); + msg.className = "lint-error"; + widgets.push(editor.addLineWidget(err.line - 1, msg, { + coverGutter: false, + noHScroll: true + })); + } + }); +}; + +$('#submitButton').on('click', function () { + bonfireExecute(); +}); + +function bonfireExecute() { + attempts++; + ga('send', 'event', 'Challenge', 'ran-code', challengeName); + userTests= null; + $('#codeOutput').empty(); + var userJavaScript = myCodeMirror.getValue(); + userJavaScript = removeComments(userJavaScript); + userJavaScript = scrapeTests(userJavaScript); + // simple fix in case the user forgets to invoke their function + + submit(userJavaScript, function(cls, message) { + if (cls) { + codeOutput.setValue(message.error); + runTests('Error', null); + } else { + codeOutput.setValue(message.output); + message.input = removeLogs(message.input); + runTests(null, message); + } + }); +} + + +var userTests; +var testSalt = Math.random(); + + +var scrapeTests = function(userJavaScript) { + + // insert tests from mongo + for (var i = 0; i < tests.length; i++) { + userJavaScript += '\n' + tests[i]; + } + + var counter = 0; + var regex = new RegExp(/(expect(\s+)?\(.*\;)|(assert(\s+)?\(.*\;)|(assert\.\w.*\;)|(.*\.should\..*\;)/); + var match = regex.exec(userJavaScript); + while (match != null) { + var replacement = '//' + counter + testSalt; + userJavaScript = userJavaScript.substring(0, match.index) + replacement + userJavaScript.substring(match.index + match[0].length); + + if (!userTests) { + userTests= []; + } + userTests.push({"text": match[0], "line": counter, "err": null}); + counter++; + match = regex.exec(userJavaScript); + } + + return userJavaScript; +}; + +function removeComments(userJavaScript) { + var regex = new RegExp(/(\/\*[^(\*\/)]*\*\/)|\/\/[^\n]*/g); + return userJavaScript.replace(regex, ''); +} + +function removeLogs(userJavaScript) { + return userJavaScript.replace(/(console\.[\w]+\s*\(.*\;)/g, ''); +} + +var pushed = false; +var createTestDisplay = function() { + if (pushed) { + userTests.pop(); + } + for (var i = 0; i < userTests.length;i++) { + var test = userTests[i]; + var testDoc = document.createElement("div"); + if (test.err != null) { + $(testDoc) + .html("
" + test.text + "
" + test.err + "
") + .prependTo($('#testSuite')) + } else { + $(testDoc) + .html("
" + test.text + "
") + .appendTo($('#testSuite')); + } + }; +}; + +var expect = chai.expect; + + +var reassembleTest = function(test, data) { + var lineNum = test.line; + var regexp = new RegExp("\/\/" + lineNum + testSalt); + return data.input.replace(regexp, test.text); +}; + +var runTests = function(err, data) { + var allTestsPassed = true; + pushed = false; + $('#testSuite').children().remove(); + if (err && userTests.length > 0) { + userTests= [{text:"Program Execution Failure", err: "No user tests were run."}]; + createTestDisplay(); + } else if (userTests) { + userTests.push(false); + pushed = true; + userTests.forEach(function(test, ix, arr){ + try { + if (test) { + var output = eval(reassembleTest(test, data)); + } + } catch(error) { + allTestsPassed = false; + console.log(error); + arr[ix].err = error.name + ":" + error.message; + } + }); + + if (allTestsPassed) { + allTestsPassed = false; + showCompletion(); + } + + } +}; + +function showCompletion() { + var time = Math.floor(Date.now() / 1000) - started; + ga('send', 'event', 'Challenge', 'solved', challengeName + ', Time: ' + time +', Attempts: ' + attempts); + $('#complete-courseware-dialog').modal('show'); + $('#complete-courseware-dialog').keydown(function(e) { + if (e.ctrlKey && e.keyCode == 13) { + $('.next-bonfire-button').click(); + } + }); +} \ No newline at end of file diff --git a/public/js/main.js b/public/js/main.js index 2d8d85b29e..f3af637d3f 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -66,6 +66,9 @@ $(document).ready(function() { completedBonfire(didCompleteWith, bonfireSolution, thisBonfireHash); }); + $('#completed-courseware').on('click', function() { + $('#complete-courseware-dialog').modal('show'); + }); $('#complete-bonfire-dialog').on('hidden.bs.modal', function() { editor.focus(); diff --git a/seed_data/bonfires.json b/seed_data/bonfires.json index 3fd930d072..0991b56c7e 100644 --- a/seed_data/bonfires.json +++ b/seed_data/bonfires.json @@ -157,9 +157,7 @@ "Truncate a string (first argument) if it is longer than the given maximum string length (second argument). Return the truncated string with a '...' ending.", "Note that the three dots at the end add to the string length." ], - - "challengeEntryPoint":"truncate('A-tisket a-tasket A green and yellow basket', 11);", - "challengeSeed":"function truncate(str, num) {\n // Clear out that junk in your trunk\r\n return str;\r\n}", + "challengeSeed":"function truncate(str, num) {\n // Clear out that junk in your trunk\r\n return str;\r\n}\n\ntruncate('A-tisket a-tasket A green and yellow basket', 11);", "tests": [ "expect(truncate('A-tisket a-tasket A green and yellow basket', 11)).to.eqls('A-tisket...');", "assert(truncate('A-tisket a-tasket A green and yellow basket', 'A-tisket a-tasket A green and yellow basket'.length) === 'A-tisket a-tasket A green and yellow basket', 'should not truncate if string is = length');", @@ -209,19 +207,6 @@ "assert.deepEqual(bouncer([false, null, 0]), [], 'should return empty array if all elements are falsey');" ] }, - { - "_id": "a8e512fbe388ac2f9198f0fa", - "name": "Where art thou", - "difficulty": "1.55", - "description": [ - "Maketh a function that looks through a list (first argument) and returns an array of all objects that have equivalent property values (second argument)." - ], - "challengeSeed": "function where(collection, source) {\n var arr = [];\r\n // What's in a name?\r\n return arr;\r\n}\n\nwhere([{ first: 'Romeo', last: 'Montague' }, { first: 'Mercutio', last: null }, { first: 'Tybalt', last: 'Capulet' }], { last: 'Capulet' });", - "tests": [ - "assert.deepEqual(where([{ first: 'Romeo', last: 'Montague' }, { first: 'Mercutio', last: null }, { first: 'Tybalt', last: 'Capulet' }], { last: 'Capulet' }), [{ first: 'Tybalt', last: 'Capulet' }], 'should return an array of objects');", - "assert.deepEqual(where([{ 'a': 1 }, { 'a': 1 }, { 'a': 1, 'b': 2 }], { 'a': 1 }), [{ 'a': 1 }, { 'a': 1 }, { 'a': 1 }], 'should return with multiples');" - ] - }, { "_id": "a39963a4c10bc8b4d4f06d7e", "name": "Seek and Destroy", @@ -231,13 +216,13 @@ ], "challengeSeed": "function destroyer(arr) {\n // Remove all the values\r\n return arr;\r\n}\n\ndestroyer([1, 2, 3, 1, 2, 3], 2, 3);", "tests": [ - "assert.strictEqual(destroyer([1, 2, 3, 1, 2, 3], 2, 3), [1, 1], 'should remove correct values from an array');", - "assert.strictEqual(destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3), [1, 5, 1], 'should remove correct values from an array');" + "assert.deepEqual(destroyer([1, 2, 3, 1, 2, 3], 2, 3), [1, 1], 'should remove correct values from an array');", + "assert.deepEqual(destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3), [1, 5, 1], 'should remove correct values from an array');" ] }, { "_id": "a24c1a4622e3c05097f71d67", - "name": "Where do I belong?", + "name": "Where do I belong", "difficulty": "1.61", "description": [ "Return the lowest index at which a value (second argument) should be inserted into a sorted array (first argument)." @@ -479,8 +464,7 @@ "Those methods are getFirstName(), getLastName(), getFullName(), setFirstName(), setLastName(), and setFullName().", "These methods must be the only available means for interacting with the object." ], - "challengeSeed": "var Person = function(firstAndLast) {\n return firstAndLast;\r\n};\n\nvar bob = new Person('Bob Ross');", - "challengeEntryPoint": "var bob = new Person('Bob Ross');\nbob.getFullName();", + "challengeSeed": "var Person = function(firstAndLast) {\n return firstAndLast;\r\n};\n\nvar bob = new Person('Bob Ross');\n\nvar bob = new Person('Bob Ross');\nbob.getFullName();", "tests": [ "expect(Object.keys(bob).length).to.eql(6);", "expect(bob instanceof Person).to.be.true;", diff --git a/seed_data/coursewares.json b/seed_data/coursewares.json index f675d0e52c..90d97633cc 100644 --- a/seed_data/coursewares.json +++ b/seed_data/coursewares.json @@ -1,8 +1,51 @@ [ + { + "_id" : "bbbbbbbbbbbbbbbbbbbbbbbb", + "name": "Learn how Free Code Camp Works", + "difficulty": 0.00, + "description": [ + "Watch this 1-minute video, or simply read this summary:", + "Welcome to Free Code Camp. We're a community of busy people learning to code.", + "We built this community because learning to code is hard. But anyone who can stay motivated can learn to code. And the best way to stay motivated is to code with friends.", + "To maximize accessibility, all our challenges are self-paced, browser-based, and free.", + "All of us start with the same 100 hours of interactive coding challenges. These cover Computer Science and databases. They also cover in-demand JavaScript tools like jQuery, Node.js and MongoDB.", + "Once we have a basic understanding of web development, we'll spend another 900 hours putting that theory into practice. We'll build full stack solutions for nonprofits.", + "By the end of this process, we'll be good at coding. We'll have a portfolio of apps with happy users to prove it. We'll also have an alumni network of fellow coders and nonprofits ready to serve as references.", + "If you make it through Free Code Camp, you will be able to get a coding job. There are far more job openings out there than there are qualified coders to fill them.", + "Also, for every pure coding job, there are at least 5 additional jobs that require some coding skills. So even if you decide not to pursue coding as a career, you'll still walk away with a valuable job skill.", + "There are 3 keys to succeeding in our community: do the challenges, make friends, and find a routine.", + "Now it's time to join our chatroom. Click the \"I've completed this challenge\" button to move on to your next challenge." + ], + "tests": [ + "" + ], + "challengeSeed": [ + "114486344" + ], + "challengeType" : 2, + "completionMessage": "" + }, + { + "_id": "bd7123c8c441eddfaeb5bdef", + "name": "Meet Booleans", + "difficulty": "0.001", + "description": [ + "Return true" + ], + "tests": [ + "expect(welcomeToBooleans()).to.be.a(\"boolean\");", + "expect(welcomeToBooleans()).to.be.true;" + ], + "challengeSeed": [ + "function welcomeToBooleans() {\n // Good luck!\n return false;\n}\n\nwelcomeToBooleans();" + ], + "challengeType": 1, + "completionMessage": "" + }, { "_id" : "bd7123c8c441eddfaeb5bdef", "name": "Start our Challenges", - "difficulty": "0.00", + "difficulty": "0.002", "description": [ "Welcome to Free Code Camp's first challenge! Click on the button below for further instructions.", "Awesome. Now you can read the rest of this challenge's instructions.", diff --git a/views/bonfire/bonfire.jade b/views/bonfire/bonfire.jade index 87399bac70..a5fdabf7ca 100644 --- a/views/bonfire/bonfire.jade +++ b/views/bonfire/bonfire.jade @@ -42,4 +42,4 @@ block content br ul#testSuite.list-group br - script(src='/js/lib/bonfire/bonfireFramework_v0.1.1.js') \ No newline at end of file + script(src='/js/lib/bonfire/bonfireFramework_v0.1.2.js') \ No newline at end of file diff --git a/views/bonfire/show.jade b/views/bonfire/show.jade index d92ec50300..f90390c61e 100644 --- a/views/bonfire/show.jade +++ b/views/bonfire/show.jade @@ -87,7 +87,6 @@ block content script(type="text/javascript"). var tests = !{JSON.stringify(tests)}; var challengeSeed = !{JSON.stringify(challengeSeed)}; - var challengeEntryPoint = !{JSON.stringify(challengeEntryPoint)}; var passedBonfireHash = !{JSON.stringify(bonfireHash)}; var challengeName = !{JSON.stringify(name)}; var started = Math.floor(Date.now() / 1000); @@ -96,7 +95,7 @@ block content form.code .form-group.codeMirrorView textarea#codeEditor(autofocus=true) - script(src='/js/lib/bonfire/bonfireFramework_v0.1.1.js') + script(src='/js/lib/bonfire/bonfireFramework_v0.1.2.js') diff --git a/views/coursewares/show.jade b/views/coursewares/show.jade index 17e3d9d905..3b4f1ab158 100644 --- a/views/coursewares/show.jade +++ b/views/coursewares/show.jade @@ -40,7 +40,10 @@ block content span.ion-help-circled | Less information - if (cc) - a.btn.btn-primary.btn-lg.btn-block#next-courseware-button Go to my next challenge (ctrl + enter) + a.btn.btn-primary.btn-lg.btn-block#next-courseware-button + | Go to my next challenge + br + | (ctrl + enter) script. var userLoggedIn = true; @@ -70,7 +73,7 @@ block content form.code .form-group.codeMirrorView textarea#codeEditor(autofocus=true) - script(src='/js/lib/coursewares/coursewaresFramework_v0.1.1.js') + script(src='/js/lib/coursewares/coursewaresHCJQFramework_v0.1.1.js') .col-md-4.col-lg-3 .hidden-xs.hidden-sm img.iphone-position(src="https://s3.amazonaws.com/freecodecamp/iphone6-frame.png") diff --git a/views/coursewares/showJS.jade b/views/coursewares/showJS.jade new file mode 100644 index 0000000000..30df71c717 --- /dev/null +++ b/views/coursewares/showJS.jade @@ -0,0 +1,83 @@ +extends ../layout-wide +block content + script(src='/js/lib/codemirror/lib/codemirror.js') + script(src='/js/lib/codemirror/addon/edit/closebrackets.js') + script(src='/js/lib/codemirror/addon/edit/matchbrackets.js') + script(src='/js/lib/codemirror/addon/lint/lint.js') + script(src='/js/lib/codemirror/addon/lint/javascript-lint.js') + script(src='//ajax.aspnetcdn.com/ajax/jshint/r07/jshint.js') + script(src='/js/lib/chai/chai.js') + link(rel='stylesheet', href='/js/lib/codemirror/lib/codemirror.css') + link(rel='stylesheet', href='/js/lib/codemirror/addon/lint/lint.css') + link(rel='stylesheet', href='/js/lib/codemirror/theme/monokai.css') + link(rel="stylesheet", href="http://fonts.googleapis.com/css?family=Ubuntu+Mono") + script(src='/js/lib/codemirror/mode/javascript/javascript.js') + script(src='/js/lib/jailed/jailed.js') + script(src='/js/lib/bonfire/bonfireInit.js') + .row + .col-xs-12.col-sm-12.col-md-4.bonfire-top + #testCreatePanel + h1.text-center= name + .well + .row + .col-xs-12 + .bonfire-instructions + p= brief + #brief-instructions + .text-center + button#more-info.btn.btn-info + span.ion-help-circled + | More information + #long-instructions.row.hide + .col-xs-12 + for sentence in details + p!= sentence + .text-center + button#less-info.btn.btn-info + span.ion-help-circled + | Less information + #submitButton.btn.btn-primary.btn-big.btn-block Run code (ctrl + enter) + br + form.code + .form-group.codeMirrorView + textarea#codeOutput + br + #testSuite.hidden + br + script(type="text/javascript"). + var tests = !{JSON.stringify(tests)}; + var challengeSeed = !{JSON.stringify(challengeSeed)}; + var passedBonfireHash = !{JSON.stringify(coursewareHash)}; + var challengeName = !{JSON.stringify(name)}; + var started = Math.floor(Date.now() / 1000); + .col-xs-12.col-sm-12.col-md-8 + #mainEditorPanel + form.code + .form-group.codeMirrorView + textarea#codeEditor(autofocus=true) + script(src='/js/lib/coursewares/coursewaresJSFramework.js') + #complete-courseware-dialog.modal(tabindex='-1') + .modal-dialog.animated.zoomIn.fast-animation + .modal-content + .modal-header.challenge-list-header= compliment + a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') × + .modal-body(ng-controller="pairedWithController") + .text-center + .animated.zoomInDown.delay-half + span.completion-icon.ion-checkmark-circled.text-primary + - if (cc) + + a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block.next-courseware-button(name='_csrf', value=_csrf, ng-disabled='completedWithForm.$invalid && existingUser.length > 0') Go to my next challenge (ctrl + enter) + - if (points && points > 2) + a.animated.fadeIn.btn.btn-lg.btn-block.btn-twitter(href="https://twitter.com/intent/tweet?text=I%20just%20#{verb}%20%40FreeCodeCamp%20Bonfire:%20#{name}&url=http%3A%2F%2Ffreecodecamp.com/bonfires/#{dashedName}&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-bonfires-dialog.modal(tabindex='-1') + // .modal-dialog.animated.fadeInUp.fast-animation + // .modal-content + // .modal-header.challenge-list-header Bonfires + // a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') × + // .modal-body + // include ../partials/bonfires diff --git a/views/coursewares/showVideo.jade b/views/coursewares/showVideo.jade new file mode 100644 index 0000000000..e0e72b5fd2 --- /dev/null +++ b/views/coursewares/showVideo.jade @@ -0,0 +1,47 @@ + +extends ../layout +block content + .row + .col-sm-12.col-md-12.col-xs-12 + .panel.panel-primary + .panel-heading.text-center + h1 #{name} + script. + var challengeName = !{JSON.stringify(name)}; + var passedCoursewareHash = !{JSON.stringify(coursewareHash)}; + + .panel.panel-body + .embed-responsive.embed-responsive-16by9 + iframe.embed-responsive-item(src='//player.vimeo.com/video/#{video}') + .col-xs-12.col-sm-10.col-sm-offset-1.col-md-8.col-md-offset-2 + h3 Steps: + h4 + ol + for step in details + li!= step + .btn.btn-primary.btn-big.btn-block#completed-courseware I've completed this challenge + .ten-pixel-break + .btn.btn-success.btn-big.btn-block.all-challenges Show me all the challenges + #complete-courseware-dialog.modal(tabindex='-1') + .modal-dialog.animated.zoomIn.fast-animation + .modal-content + .modal-header.challenge-list-header= compliment + a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') × + .modal-body + .text-center + .animated.zoomInDown.delay-half + span.completion-icon.ion-checkmark-circled.text-primary + - if (cc) + a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block#next-courseware-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}%20%40FreeCodeCamp%20Challenge%20%23#{number}:%20#{name}&url=http%3A%2F%2Ffreecodecamp.com/challenges/#{number}&hashtags=LearnToCode, JavaScript" target="_blank") + i.fa.fa-twitter   + = 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 From efa4b2d9bc3bcbf5378fe86254cf8b23e2d9463c Mon Sep 17 00:00:00 2001 From: Nathan Leniz Date: Fri, 13 Feb 2015 21:07:56 -0500 Subject: [PATCH 04/13] Factor all challenges button out of showvideo --- views/coursewares/showVideo.jade | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/views/coursewares/showVideo.jade b/views/coursewares/showVideo.jade index e0e72b5fd2..4d207bf6e5 100644 --- a/views/coursewares/showVideo.jade +++ b/views/coursewares/showVideo.jade @@ -1,5 +1,5 @@ -extends ../layout +extends ../layout-wide block content .row .col-sm-12.col-md-12.col-xs-12 @@ -39,9 +39,3 @@ block content = 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 From a22e472fb202ee487451e30330a0fc40a66a9956 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Fri, 13 Feb 2015 18:40:39 -0800 Subject: [PATCH 05/13] update the showVideo view --- controllers/courseware.js | 22 +- seed_data/coursewares.json | 327 ++++++------------ .../coursewares/{show.jade => showHTML.jade} | 0 views/coursewares/showJS.jade | 9 +- views/coursewares/showVideo.jade | 80 +++-- 5 files changed, 157 insertions(+), 281 deletions(-) rename views/coursewares/{show.jade => showHTML.jade} (100%) diff --git a/controllers/courseware.js b/controllers/courseware.js index eca76fd68a..58e57cef7d 100644 --- a/controllers/courseware.js +++ b/controllers/courseware.js @@ -74,7 +74,7 @@ exports.returnIndividualCourseware = function(req, res, next) { var challengeType = { 0 : function() { - res.render('coursewares/show', { + res.render('coursewares/showHTML', { title: courseware.name, dashedName: dashedName, name: courseware.name, @@ -107,7 +107,7 @@ exports.returnIndividualCourseware = function(req, res, next) { phrase: resources.randomPhrase(), compliment: resources.randomCompliment(), coursewareHash: courseware._id, - environment: resources.whichEnvironment(), + environment: resources.whichEnvironment() }); }, @@ -133,24 +133,6 @@ exports.returnIndividualCourseware = function(req, res, next) { return challengeType[courseware.challengeType](); - //// Render the view for the user - //res.render('coursewares/show', { - // title: courseware.name, - // dashedName: dashedName, - // name: courseware.name, - // brief: courseware.description[0], - // details: courseware.description.slice(1), - // tests: courseware.tests, - // challengeSeed: courseware.challengeSeed, - // cc: !!req.user, - // points: req.user ? req.user.points : undefined, - // verb: resources.randomVerb(), - // phrase: resources.randomPhrase(), - // compliment: resources.randomCompliment(), - // coursewareHash: courseware._id, - // environment: resources.whichEnvironment() - //}); - }); }; diff --git a/seed_data/coursewares.json b/seed_data/coursewares.json index 90d97633cc..0c752ff36b 100644 --- a/seed_data/coursewares.json +++ b/seed_data/coursewares.json @@ -1,10 +1,10 @@ [ { - "_id" : "bbbbbbbbbbbbbbbbbbbbbbbb", + "_id" : "bd7123d8c441eddfaeb5bdef", "name": "Learn how Free Code Camp Works", "difficulty": 0.00, "description": [ - "Watch this 1-minute video, or simply read this summary:", + "Watch this 90 second video, or simply read this summary:", "Welcome to Free Code Camp. We're a community of busy people learning to code.", "We built this community because learning to code is hard. But anyone who can stay motivated can learn to code. And the best way to stay motivated is to code with friends.", "To maximize accessibility, all our challenges are self-paced, browser-based, and free.", @@ -14,7 +14,7 @@ "If you make it through Free Code Camp, you will be able to get a coding job. There are far more job openings out there than there are qualified coders to fill them.", "Also, for every pure coding job, there are at least 5 additional jobs that require some coding skills. So even if you decide not to pursue coding as a career, you'll still walk away with a valuable job skill.", "There are 3 keys to succeeding in our community: do the challenges, make friends, and find a routine.", - "Now it's time to join our chatroom. Click the \"I've completed this challenge\" button to move on to your next challenge." + "Now it's time to join our chatroom. Click the \"Go to my next challenge\" button to move on to your next challenge." ], "tests": [ "" @@ -22,8 +22,7 @@ "challengeSeed": [ "114486344" ], - "challengeType" : 2, - "completionMessage": "" + "challengeType" : 2 }, { "_id": "bd7123c8c441eddfaeb5bdef", @@ -39,8 +38,7 @@ "challengeSeed": [ "function welcomeToBooleans() {\n // Good luck!\n return false;\n}\n\nwelcomeToBooleans();" ], - "challengeType": 1, - "completionMessage": "" + "challengeType": 1 }, { "_id" : "bd7123c8c441eddfaeb5bdef", @@ -61,8 +59,7 @@ "challengeSeed": [ "

Hello

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -82,8 +79,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -102,8 +98,7 @@ "

hello world

", "

hello html

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -123,8 +118,7 @@ "

hello html

", "

hello paragraph

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -148,8 +142,7 @@ "", "

hello paragraph

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -174,8 +167,7 @@ "", "

hello paragraph

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -196,8 +188,7 @@ "

cat photo app

", "

hello paragraph

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -218,8 +209,7 @@ "

cat photo app

", "

lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -243,8 +233,7 @@ "

cat photo app

", "

lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -271,8 +260,7 @@ "

cat photo app

", "

lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -301,8 +289,7 @@ "

cat photo app

", "

lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -329,8 +316,7 @@ "

cat photo app

", "

lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -362,8 +348,7 @@ "

cat photo app

", "

lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -392,8 +377,7 @@ "

cat photo app

", "

lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -432,8 +416,7 @@ "

cat photo app

", "

lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -464,8 +447,7 @@ "

cat photo app

", "

lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -491,8 +473,7 @@ "

cat photo app

", "

lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -521,8 +502,7 @@ "

cat photo app

", "

lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -549,8 +529,7 @@ "

cat photo app

", "

lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -582,8 +561,7 @@ "

lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

", "" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -621,8 +599,7 @@ "

lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

", "" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -660,8 +637,7 @@ "

lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

", "" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -698,8 +674,7 @@ "

lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

", "" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -734,8 +709,7 @@ "This is a link to Google", "
" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -772,8 +746,7 @@ "This named anchor leads nowhere", "
" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -807,8 +780,7 @@ "", "" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -841,8 +813,7 @@ "\"a", "" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -894,8 +865,7 @@ "
padding
", "
" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -949,8 +919,7 @@ "
padding
", "
" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1003,8 +972,7 @@ "
padding
", "" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1058,8 +1026,7 @@ "
padding
", "" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1113,8 +1080,7 @@ "
padding
", "" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1165,8 +1131,7 @@ "
padding
", "" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1202,8 +1167,7 @@ "This is a link to Google", "
" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1231,8 +1195,7 @@ "", "
" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1261,8 +1224,7 @@ "", "
" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1292,8 +1254,7 @@ "
", "" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1324,8 +1285,7 @@ "
", "" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1356,8 +1316,7 @@ "
", "" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1388,8 +1347,7 @@ "
", "" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1420,8 +1378,7 @@ "
", "" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1461,8 +1418,7 @@ "
", "" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1502,8 +1458,7 @@ "
", "" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1529,8 +1484,7 @@ "

lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

", "" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1548,8 +1502,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1567,8 +1520,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1586,8 +1538,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1605,8 +1556,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1624,8 +1574,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1643,8 +1592,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1662,8 +1610,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1681,8 +1628,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1700,8 +1646,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1719,8 +1664,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1738,8 +1682,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1757,8 +1700,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1776,8 +1718,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1795,8 +1736,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1814,8 +1754,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1833,8 +1772,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1852,8 +1790,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1871,8 +1808,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1890,8 +1826,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1909,8 +1844,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1928,8 +1862,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1947,8 +1880,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1966,8 +1898,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -1985,8 +1916,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2004,8 +1934,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2023,8 +1952,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2042,8 +1970,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2061,8 +1988,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2080,8 +2006,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2099,8 +2024,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2118,8 +2042,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2137,8 +2060,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2156,8 +2078,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2175,8 +2096,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2194,8 +2114,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2213,8 +2132,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2232,8 +2150,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2251,8 +2168,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2270,8 +2186,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2289,8 +2204,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2308,8 +2222,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2327,8 +2240,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2346,8 +2258,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2365,8 +2276,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2384,8 +2294,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2403,8 +2312,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2422,8 +2330,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2441,8 +2348,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2460,8 +2366,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2479,8 +2384,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2498,8 +2402,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2517,8 +2420,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2536,8 +2438,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2555,8 +2456,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2574,8 +2474,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2593,8 +2492,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2612,8 +2510,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2631,8 +2528,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2650,8 +2546,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2669,8 +2564,7 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 }, { @@ -2688,7 +2582,6 @@ "challengeSeed": [ "

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 } ] diff --git a/views/coursewares/show.jade b/views/coursewares/showHTML.jade similarity index 100% rename from views/coursewares/show.jade rename to views/coursewares/showHTML.jade diff --git a/views/coursewares/showJS.jade b/views/coursewares/showJS.jade index 30df71c717..71c8e037e3 100644 --- a/views/coursewares/showJS.jade +++ b/views/coursewares/showJS.jade @@ -73,11 +73,4 @@ block content 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-bonfires-dialog.modal(tabindex='-1') - // .modal-dialog.animated.fadeInUp.fast-animation - // .modal-content - // .modal-header.challenge-list-header Bonfires - // a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') × - // .modal-body - // include ../partials/bonfires + a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress \ No newline at end of file diff --git a/views/coursewares/showVideo.jade b/views/coursewares/showVideo.jade index 4d207bf6e5..95b6e8590d 100644 --- a/views/coursewares/showVideo.jade +++ b/views/coursewares/showVideo.jade @@ -1,41 +1,49 @@ - extends ../layout-wide block content .row - .col-sm-12.col-md-12.col-xs-12 - .panel.panel-primary - .panel-heading.text-center - h1 #{name} + .col-xs-12.col-sm-12.col-md-4.bonfire-top + h1.text-center= name + .well + h4 + ol + for step in details + li!= step + .col-xs-12.col-sm-12.col-md-8 + .embed-responsive.embed-responsive-16by9 + iframe.embed-responsive-item(src='//player.vimeo.com/video/#{video}') + br + - if (cc) + a.btn.btn-primary.btn-lg.btn-block#next-courseware-button Go to my next challenge (ctrl + enter) script. - var challengeName = !{JSON.stringify(name)}; + var userLoggedIn = true; + - else + a.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress + script. + var userLoggedIn = false; + br + script(type="text/javascript"). + var tests = !{JSON.stringify(tests)}; var passedCoursewareHash = !{JSON.stringify(coursewareHash)}; - - .panel.panel-body - .embed-responsive.embed-responsive-16by9 - iframe.embed-responsive-item(src='//player.vimeo.com/video/#{video}') - .col-xs-12.col-sm-10.col-sm-offset-1.col-md-8.col-md-offset-2 - h3 Steps: - h4 - ol - for step in details - li!= step - .btn.btn-primary.btn-big.btn-block#completed-courseware I've completed this challenge - .ten-pixel-break - .btn.btn-success.btn-big.btn-block.all-challenges Show me all the challenges - #complete-courseware-dialog.modal(tabindex='-1') - .modal-dialog.animated.zoomIn.fast-animation - .modal-content - .modal-header.challenge-list-header= compliment - a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') × - .modal-body - .text-center - .animated.zoomInDown.delay-half - span.completion-icon.ion-checkmark-circled.text-primary - - if (cc) - a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block#next-courseware-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}%20%40FreeCodeCamp%20Challenge%20%23#{number}:%20#{name}&url=http%3A%2F%2Ffreecodecamp.com/challenges/#{number}&hashtags=LearnToCode, JavaScript" target="_blank") - i.fa.fa-twitter   - = phrase - - else - a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress + var challengeName = !{JSON.stringify(name)}; + var started = Math.floor(Date.now() / 1000); + #complete-courseware-dialog.modal(tabindex='-1') + .modal-dialog.animated.zoomIn.fast-animation + .modal-content + .modal-header.challenge-list-header= compliment + a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') × + .modal-body(ng-controller="pairedWithController") + .text-center + .animated.zoomInDown.delay-half + span.completion-icon.ion-checkmark-circled.text-primary + - if (cc) + a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block.next-courseware-button(name='_csrf', value=_csrf, ng-disabled='completedWithForm.$invalid && existingUser.length > 0') Go to my next challenge (ctrl + enter) + - if (points && points > 2) + a.animated.fadeIn.btn.btn-lg.btn-block.btn-twitter(href="https://twitter.com/intent/tweet?text=I%20just%20#{verb}%20%40FreeCodeCamp%20Bonfire:%20#{name}&url=http%3A%2F%2Ffreecodecamp.com/bonfires/#{dashedName}&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 + h1 #{name} + script. + var challengeName = !{JSON.stringify(name)}; + var passedCoursewareHash = !{JSON.stringify(coursewareHash)}; \ No newline at end of file From 255d2654ea215e4f63e10c6fa6e48ca16bd5938d Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Sat, 14 Feb 2015 12:52:04 -0800 Subject: [PATCH 06/13] fix an indentation issue in showHTML --- views/coursewares/showVideo.jade | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/views/coursewares/showVideo.jade b/views/coursewares/showVideo.jade index 95b6e8590d..88099ddc42 100644 --- a/views/coursewares/showVideo.jade +++ b/views/coursewares/showVideo.jade @@ -21,11 +21,11 @@ block content script. var userLoggedIn = false; br - script(type="text/javascript"). - var tests = !{JSON.stringify(tests)}; - var passedCoursewareHash = !{JSON.stringify(coursewareHash)}; - var challengeName = !{JSON.stringify(name)}; - var started = Math.floor(Date.now() / 1000); + script(type="text/javascript"). + var tests = !{JSON.stringify(tests)}; + var passedCoursewareHash = !{JSON.stringify(coursewareHash)}; + var challengeName = !{JSON.stringify(name)}; + var started = Math.floor(Date.now() / 1000); #complete-courseware-dialog.modal(tabindex='-1') .modal-dialog.animated.zoomIn.fast-animation .modal-content From fb971ab080198652a78de9a13e33956506160fae Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Sat, 14 Feb 2015 14:09:26 -0800 Subject: [PATCH 07/13] start adding test output to coursewares --- .../coursewaresHCJQFramework_v0.1.1.js | 9 ++++++++- public/js/lib/coursewares/iFrameScripts.js | 19 ++++++++++++------- seed_data/coursewares.json | 10 +++++----- views/coursewares/showHTML.jade | 12 +++++------- 4 files changed, 30 insertions(+), 20 deletions(-) diff --git a/public/js/lib/coursewares/coursewaresHCJQFramework_v0.1.1.js b/public/js/lib/coursewares/coursewaresHCJQFramework_v0.1.1.js index 026f36c04e..189f796c6a 100644 --- a/public/js/lib/coursewares/coursewaresHCJQFramework_v0.1.1.js +++ b/public/js/lib/coursewares/coursewaresHCJQFramework_v0.1.1.js @@ -62,7 +62,7 @@ function updatePreview() { var previewFrame = document.getElementById('preview'); var preview = previewFrame.contentDocument || previewFrame.contentWindow.document; preview.open(); - preview.write(libraryIncludes + editor.getValue() + otherTestsForNow); + preview.write(libraryIncludes + editor.getValue()); preview.close(); } setTimeout(updatePreview, 300); @@ -81,6 +81,13 @@ eventer(messageEvent,function(e) { } },false); +var postError = function(data) { + console.log(Object.keys(data)); + var testDoc = document.createElement("div"); + $(testDoc) + .html("
" + data + "
") + .prependTo($('#testSuite')) +}; var challengeSeed = challengeSeed || null; var tests = tests || []; var allSeeds = ''; diff --git a/public/js/lib/coursewares/iFrameScripts.js b/public/js/lib/coursewares/iFrameScripts.js index 325b34af69..5c3d38998f 100644 --- a/public/js/lib/coursewares/iFrameScripts.js +++ b/public/js/lib/coursewares/iFrameScripts.js @@ -1,14 +1,19 @@ (function() { var allTestsGood = true; var expect = chai.expect; + var tests = parent.tests; - try { - eval(parent.allTests); - } catch (err) { - allTestsGood = false; - } finally { - if (allTestsGood) { - parent.postMessage('CompleteAwesomeSauce', parent.nodeEnv); + for (var i = 0; i < tests.length; i++) { + + try { + eval(tests[i]); + } catch (err) { + parent.postError(err); + allTestsGood = false; + } finally { + if (allTestsGood) { + parent.postMessage('CompleteAwesomeSauce', parent.nodeEnv); + } } } })(); \ No newline at end of file diff --git a/seed_data/coursewares.json b/seed_data/coursewares.json index 0c752ff36b..e7c4a99289 100644 --- a/seed_data/coursewares.json +++ b/seed_data/coursewares.json @@ -256,7 +256,7 @@ " color: blue;", " }", "", - "

hello world

", + "

hello world

", "

cat photo app

", "

lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

" ], @@ -534,7 +534,7 @@ { "_id" : "bad87fee1348bd9acdf08812", - "name": "Specify an Image Size TEST", + "name": "Specify an Image Size", "difficulty" : "0.19", "description": [ "Create a class called narrow-image and use it to resize the image so that it's only 200 pixels wide", @@ -544,7 +544,7 @@ ], "tests": [ "expect($('img')).to.have.class('narrow-image');", - "expect($('img')).to.have.css('width', 200px)" + "expect($('img')).to.have.css('width', '200px')" ], "challengeSeed": [ "