From d2c1667db759e66229f5f3a7eaa915b018497910 Mon Sep 17 00:00:00 2001 From: Abhisek Pattnaik Date: Thu, 29 Oct 2015 17:19:29 +0530 Subject: [PATCH 01/24] for loop clarification - fix typo - variable - Instruction clarification - Example clarification --- challenges/basic-javascript.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/challenges/basic-javascript.json b/challenges/basic-javascript.json index b22ee617c7..6f7fa03251 100644 --- a/challenges/basic-javascript.json +++ b/challenges/basic-javascript.json @@ -868,16 +868,16 @@ "The most common type of JavaScript loop is called a \"for loop\" because it runs \"for\" a specific number of times.", "For loops are declared with three optional expressions seperated by semicolons:", "for([initialization]; [condition]; [final-expression])", - "The initialization statement is executed one time only before the loop starts. It is typically used to define and setup your loop varaible.", - "The condition statement is evaluated at the beginning of every loop and will continue as long as it evalutes true. When condition is false at the start of the loop, the loop will stop executing. This means if condition starts as false, your loop will never execute.", + "The initialization statement is executed one time only before the loop starts. It is typically used to define and setup your loop variable.", + "The condition statement is evaluated at the beginning of every loop iteration and will continue as long as it evalutes to true. When condition is false at the start of the iteration, the loop will stop executing. This means if condition starts as false, your loop will never execute.", "The final-expression is executed at the end of each loop iteration, prior to the next condition check and is usually used to increment or decrement your loop counter.", - "We'll initialize with i = 0 and loop while our condition i < 5 is true. We'll increment i by 1 each loop with i++ as our final-expression.", + "In the following example we initialize with i = 0 and iterate while our condition i < 5 is true. We'll increment i by 1 in each loop iteration with i++ as our final-expression.", "var ourArray = [];", "for(var i = 0; i < 5; i++) {", "  ourArray.push(i);", "}", - "ourArray will now contain [0,1,2,3,4] ", - "Let's try getting a for loop to work by pushing values to an array." + "ourArray will now contain [0,1,2,3,4].", + "Let's try getting a for loop to work by pushing values to an array." ], "tests": [ "assert(editor.getValue().match(/for\\s*\\(/g).length > 1, 'message: You should be using a for loop for this.');", From d394a2aad140da8558521a00f5995994e166e406 Mon Sep 17 00:00:00 2001 From: Logan Tegman Date: Thu, 29 Oct 2015 20:05:48 -0700 Subject: [PATCH 02/24] Fix Nest Anchor in Paragraph Test Closes #4012 and closes #3989 --- challenges/html5-and-css.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/challenges/html5-and-css.json b/challenges/html5-and-css.json index 4372a5cf6b..9ae6a4ad8b 100644 --- a/challenges/html5-and-css.json +++ b/challenges/html5-and-css.json @@ -1172,7 +1172,7 @@ "assert($(\"a\").text().match(/cat\\sphotos/gi), 'Your a element should have the anchor text of \"cat photos\"')", "assert($(\"p\") && $(\"p\").length > 2, 'Create a new p element around your a element.')", "assert($(\"a[href=\\\"http://www.freecatphotoapp.com\\\"]\").parent().is(\"p\"), 'Your a element should be nested within your new p element.')", - "assert($(\"p\").text().match(/^\\s*View\\smore\\s/gi), 'Your p element should have the text \"View more \" (with a space after it).')", + "assert($(\"a[href=\\\"http://www.freecatphotoapp.com\\\"]\").parent().text().match(/^\\s*View\\smore\\s/gi), 'Your p element should have the text \"View more \" (with a space after it).')", "assert(!$(\"a\").text().match(/View\\smore/gi), 'Your a element should not have the text \"View more\".')", "assert(editor.match(/<\\/p>/g) && editor.match(/

/g).length === editor.match(/

p elements has a closing tag.')", "assert(editor.match(/<\\/a>/g) && editor.match(//g).length === editor.match(/a elements has a closing tag.')" From 5aa23af1e91fec408a7f929260496c042f22eeaf Mon Sep 17 00:00:00 2001 From: Utsav Ahuja Date: Fri, 30 Oct 2015 02:25:19 -0700 Subject: [PATCH 03/24] Removed Chai.js mention from Bonfire --- challenges/basic-bonfires.json | 1 - 1 file changed, 1 deletion(-) diff --git a/challenges/basic-bonfires.json b/challenges/basic-bonfires.json index 8ac6cbcae7..f81241c9d2 100644 --- a/challenges/basic-bonfires.json +++ b/challenges/basic-bonfires.json @@ -273,7 +273,6 @@ "description": [ "Return an array consisting of the largest number from each provided sub-array. For simplicity, the provided array will contain exactly 4 sub-arrays.", "Remember, you can iterate through an array with a simple for loop, and access each member with array syntax arr[i] .", - "If you are writing your own Chai.js tests, be sure to use a deep equal statement instead of an equal statement when comparing arrays.", "Remember to use Read-Search-Ask if you get stuck. Write your own code." ], "challengeSeed": [ From 4abdab67f3729160d6df44ecf973ec186b9378dc Mon Sep 17 00:00:00 2001 From: Martin Delille Date: Thu, 29 Oct 2015 11:01:35 +0100 Subject: [PATCH 04/24] fix typo and add comma latitiude => latitude add space and
--- challenges/json-apis-and-ajax.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/challenges/json-apis-and-ajax.json b/challenges/json-apis-and-ajax.json index ea3a4351e2..76b89f1688 100644 --- a/challenges/json-apis-and-ajax.json +++ b/challenges/json-apis-and-ajax.json @@ -377,7 +377,7 @@ "Here's some code that does this:", "if (navigator.geolocation) {", "  navigator.geolocation.getCurrentPosition(function(position) {", - "    $(\"#data\").html(\"latitiude\" + position.coords.latitude + \"longitude\" + position.coords.longitude);", + "    $(\"#data\").html(\"latitude: \" + position.coords.latitude + \"<br>longitude: \" + position.coords.longitude);", "  });", "}" ], From 880e153edda69632e20f8f17cb4b899048ea3ab7 Mon Sep 17 00:00:00 2001 From: bencassidy Date: Fri, 30 Oct 2015 09:30:08 -0700 Subject: [PATCH 05/24] fixed typer --- challenges/object-oriented-and-functional-programming.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/challenges/object-oriented-and-functional-programming.json b/challenges/object-oriented-and-functional-programming.json index 95c6d73b85..4570dd45ff 100644 --- a/challenges/object-oriented-and-functional-programming.json +++ b/challenges/object-oriented-and-functional-programming.json @@ -330,7 +330,7 @@ "tests": [ "assert.deepEqual(array, [7,6,5,4,3,2,1], 'message: You should reverse the array.');", "assert(editor.getValue().match(/\\.reverse\\s*\\(\\)/gi), 'message: You should use the reverse method.');", - "assert(editor.getValue().match(/\\[1\\,2\\,3\\,4\\,5\\,6\\,7/gi), 'message: You should only be using revserse to modify array.');" + "assert(editor.getValue().match(/\\[1\\,2\\,3\\,4\\,5\\,6\\,7/gi), 'message: You should only be using reverse to modify array.');" ], "challengeSeed": [ "var array = [1,2,3,4,5,6,7];", From 163b54c2621690bff837043c2613c1e0a8bc4414 Mon Sep 17 00:00:00 2001 From: pC15 Date: Fri, 30 Oct 2015 11:56:23 -0700 Subject: [PATCH 06/24] fix for issue#4011 changed codepen links to /full/ for Weather challenge --- challenges/intermediate-ziplines.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/challenges/intermediate-ziplines.json b/challenges/intermediate-ziplines.json index 0d2afbcb5c..bc8c20c063 100644 --- a/challenges/intermediate-ziplines.json +++ b/challenges/intermediate-ziplines.json @@ -8,7 +8,7 @@ "title": "Show the Local Weather", "challengeSeed": ["126415127"], "description": [ - "Objective: Build a CodePen.io app that successfully reverse-engineers this: http://codepen.io/FreeCodeCamp/pen/avqvgJ.", + "Objective: Build a CodePen.io app that successfully reverse-engineers this: http://codepen.io/FreeCodeCamp/full/avqvgJ.", "Rule #1: Don't look at the example project's code on CodePen. Figure it out for yourself.", "Rule #2: You may use whichever libraries or APIs you need.", "Rule #3: Reverse engineer the example project's functionality, and also feel free to personalize it.", From 1a2c64a17854b1c7393a933724d1531791c00a30 Mon Sep 17 00:00:00 2001 From: Logan Tegman Date: Thu, 29 Oct 2015 21:51:35 -0700 Subject: [PATCH 07/24] JSON/API Lesson Cleanup + Fixes Convert JSON to HTML lesson (Closes #4016) + Add Formatting to Geolocation lesson output (Closes #4010) + Fixes Render Images lesson + Removes unnecessary `?callback=` from JSON challenges. (Closes #3972) + Lots of other formatting and consistancy changes. + Also closes #3962 and closes #3969 --- challenges/json-apis-and-ajax.json | 288 ++++++++++++++--------------- 1 file changed, 140 insertions(+), 148 deletions(-) diff --git a/challenges/json-apis-and-ajax.json b/challenges/json-apis-and-ajax.json index d0373c1d75..940cb95bdb 100644 --- a/challenges/json-apis-and-ajax.json +++ b/challenges/json-apis-and-ajax.json @@ -7,7 +7,7 @@ "id": "bb000000000000000000001", "title": "Trigger Click Events with jQuery", "description": [ - "In this section, we'll learn how to get data from APIs. APIs - or Application Interfaces - are tools that computers use to communicate with one another.", + "In this section, we'll learn how to get data from APIs. APIs - or Application Programming Interfaces - are tools that computers use to communicate with one another.", "We'll also learn how to update HTML with the data we get from these APIs using a technology called Ajax.", "First, let's review what the $(document).ready() function does. This function makes it so all code inside of it only runs once our page loads.", "Let's make our \"Get Message\" button change the text of the element with the class message.", @@ -31,21 +31,21 @@ "", "", "

", - "
", - "

Cat Photo Finder

", - "
", - "
", - "
", - " The message will go here", - "
", - "
", - "
", - "
", - " ", - "
", - "
", + "
", + "

Cat Photo Finder

", + "
", + "
", + "
", + " The message will go here", + "
", + "
", + "
", + "
", + " ", + "
", + "
", "
" ], "challengeType": 0, @@ -68,30 +68,29 @@ " $(document).ready(function() {", " $(\"#getMessage\").on(\"click\", function(){", " // Only change code below this line.", - "", + " ", " // Only change code above this line.", " });", " });", "fcces", "", "", - "
", - "
", - "

Cat Photo Finder

", - "
", - "
", - "
", - " The message will go here", - "
", - "
", - "
", - "
", - " ", - "
", - "
", + "
", + "

Cat Photo Finder

", + "
", + "
", + "
", + " The message will go here", + "
", + "
", + "
", + "
", + " ", + "
", + "
", "
" ], "challengeType": 0, @@ -102,55 +101,55 @@ "title": "Get JSON with the jQuery getJSON Method", "description": [ "You can also request data from an external source. This is where APIs come into play.", - "Remember that APIs - or Application Interfaces - are tools that computers use to communicate with one another.", + "Remember that APIs - or Application Programming Interfaces - are tools that computers use to communicate with one another.", "Most web APIs transfer data in a format called JSON. JSON stands for JavaScript Object Notation.", "You've already been using JSON whenever you create a JavaScript object. JSON is nothing more than object properties and their current values, sandwiched between a { and a }.", "These properties and their values are often referred to as \"key-value pairs\".", "Let's get the JSON from Free Code Camp's Cat Photo API.", "Here's the code you can put in your click event to do this:", - "  $.getJSON(\"/json/cats.json?callback=\", function( json ) {", - "    $(\".message\").html(JSON.stringify(json))", + "  $.getJSON(\"/json/cats.json\", function(json) {", + "    $(\".message\").html(JSON.stringify(json));", "  });", "Once you've added this, click the \"Get Message\" button. Your Ajax function will replace the \"The message will go here\" text with the raw JSON output from the Free Code Camp Cat Photo API." ], "tests": [ "assert(editor.match(/\\$\\s*?\\(\\s*?(\\\"|\\')\\#getMessage(\\\"|\\')\\s*?\\)\\s*?\\.\\s*?on\\s*?\\(\\s*?(\\\"|\\')click(\\\"|\\')\\s*?\\,\\s*?function\\s*?\\(\\s*?\\)\\s*?\\{/gi), 'You should have a click handler on the getMessage button to trigger the AJAX request.')", - "assert(editor.match(/\\s*?\\}\\s*?\\)\\s*?\\;/gi), 'You should have at least on closing set of brackets and parenthesis.')", + "assert(editor.match(/\\s*?\\}\\s*?\\)\\s*?\\;/gi), 'You should have at least one closing set of brackets and parenthesis.')", "assert(editor.match(/\\s*?\\}\\s*?\\)\\s*?\\;/gi) && editor.match(/\\,\\s*?function\\s*?\\(\\s*?\\w*?\\s*?\\)\\s*?\\{/gi) && editor.match(/\\s*?\\}\\s*?\\)\\s*?\\;/gi).length === editor.match(/\\s*?function\\s*?\\(\\s*?\\w*?\\s*?\\)\\s*?\\{/gi).length, 'Each callback function should have a closing set of brackets and parenthesis.')", - "assert(editor.match(/\\$\\s*?\\.\\s*?getJSON\\s*?\\(\\s*?\"\\\/json\\\/cats\\.json\\?callback\\=\"\\s*?\\,\\s*?function\\s*?\\(\\s*?json\\s*?\\)\\s*?\\{/gi), 'You should be making use of the getJSON method given in the description to load data from the json file.')", - "assert(editor.match(/\\$\\s*?\\(\\s*?\\\"\\.message\\\"\\s*?\\)\\s*?\\.\\s*?html\\s*?\\(\\s*?JSON\\s*?\\.\\s*?stringify\\s*?\\(\\s*?json\\s*?\\)\\s*?\\)/gi), 'Don\\'t forget to make the .html change the contents of the message box so that it contains the result of the getJSON.')" + "assert(editor.match(/\\$\\s*?\\.\\s*?getJSON\\s*?\\(\\s*?(\\\"|\\')\\\/json\\\/cats\\.json(\\\"|\\')\\s*?\\,\\s*?function\\s*?\\(\\s*?json\\s*?\\)\\s*?\\{/gi), 'You should be making use of the getJSON method given in the description to load data from the json file.')", + "assert(editor.match(/\\$\\s*?\\(\\s*?(\\\"|\\')\\.message(\\\"|\\')\\s*?\\)\\s*?\\.\\s*?html\\s*?\\(\\s*?JSON\\s*?\\.\\s*?stringify\\s*?\\(\\s*?json\\s*?\\)\\s*?\\)/gi), 'Don\\'t forget to make the .html change the contents of the message box so that it contains the result of the getJSON.')" ], "challengeSeed": [ "fccss", - " $(document).ready(function() {", - " ", - " $(\"#getMessage\").on(\"click\", function(){", - " // Only change code below this line.", + " $(document).ready(function() {", "", + " $(\"#getMessage\").on(\"click\", function(){", + " // Only change code below this line.", + " ", + " ", + " ", + " // Only change code above this line.", + " });", "", - "", - " // Only change code above this line.", - " });", - " ", - " });", + " });", "fcces", "", "
", - "
", - "

Cat Photo Finder

", - "
", - "
", - "
", - " The message will go here", - "
", - "
", - "
", - "
", - " ", - "
", - "
", + "
", + "

Cat Photo Finder

", + "
", + "
", + "
", + " The message will go here", + "
", + "
", + "
", + "
", + " ", + "
", + "
", "
" ], "challengeType": 0, @@ -166,9 +165,12 @@ "Then, let's loop through our JSON, adding more HTML to that variable. When the loop is finished, we'll render it.", "Here's the code that does this:", "json.map(function(val) {", - "  html = html + \"<div class = 'cat'>\"", - "  html = html + '<div>' + val + '</div>';", - "  html = html + \"</div><br/>\"", + "  var keys = Object.keys(val);", + "  html += \"<div class = 'cat'>\";", + "  keys.map(function(key) {", + "    html += \"<b>\" + key + \"</b>: \" + val[key] + \"<br>\";", + "  });", + "  html += \"</div><br>\";", "});" ], "tests": [ @@ -179,18 +181,13 @@ " $(document).ready(function() {", "", " $(\"#getMessage\").on(\"click\", function() {", - "   $.getJSON(\"/json/cats.json?callback=\", function( json ) {", + "   $.getJSON(\"/json/cats.json\", function(json) {", "", + " var html = \"\";", " // Only change code below this line.", - "", - "", - "", - "", - "", - "", - "", - "", - "", + " ", + " ", + " ", " // Only change code above this line.", "", "     $(\".message\").html(html);", @@ -201,20 +198,20 @@ "fcces", "", "
", - "
", - "

Cat Photo Finder

", - "
", - "
", - "
", - " The message will go here","
", - "
", - "
", - "
", - " ", - "
", - "
", + "
", + "

Cat Photo Finder

", + "
", + "
", + "
", + " The message will go here","
", + "
", + "
", + "
", + " ", + "
", + "
", "
" ], "challengeType": 0, @@ -225,35 +222,34 @@ "title": "Render Images from Data Sources", "description": [ "In the JSON that we receive data from Free Code Camp's Cat Photo API.", - "When we're looping through these strings, let's check whether they are links. If it is, instead of outputing the image link, let's render the image.", + "We've seen from the last two lessons that each object in our JSON array contains an imageLink key with a value that is the url of a cat's image.", + "When we're looping through these objects, let's use this imageLink property to display this image in an img element.", "Here's the code that does this:", - "if(val.match(\"http\")) {", - "  html = html + '<img src = \"' + val + '\">';", - "}" + "  html += \"<img src = '\" + val.imageLink + \"'>\";" ], "tests": [ - "assert(editor.match(/val.match/gi), 'You should have checked whether the strings contain links.')" + "assert(editor.match(/val.imageLink/gi), 'You should have used the imageLink property to display the images.')" ], "challengeSeed": [ "fccss", " $(document).ready(function() {", "", " $(\"#getMessage\").on(\"click\", function() {", - "  $.getJSON(\"/json/cats.json?callback=\", function( json ) {", + "  $.getJSON(\"/json/cats.json\", function(json) {", "", " var html = \"\";", "", " json.map(function(val) {", "", - " html = html + \"
\"", + " html += \"
\";", "", - " // Only change code below this line.", + " // Only change code below this line.", + " ", + " ", + " ", + " // Only change code above this line.", "", - "", - "", - " // Only change code above this line.", - "", - " html = html + \"
\"", + " html += \"
\";", "", " });", "", @@ -265,21 +261,21 @@ "fcces", "", "
", - "
", - "

Cat Photo Finder

", - "
", - "
", - "
", - " The message will go here", - "
", - "
", - "
", - "
", - " ", - "
", - "
", + "
", + "

Cat Photo Finder

", + "
", + "
", + "
", + " The message will go here", + "
", + "
", + "
", + "
", + " ", + "
", + "
", "
" ], "challengeType": 0, @@ -304,25 +300,23 @@ " $(document).ready(function() {", "", " $(\"#getMessage\").on(\"click\", function() {", - "   $.getJSON(\"/json/cats.json?callback=\", function( json ) {", + "   $.getJSON(\"/json/cats.json\", function(json) {", "", " var html = \"\";", "", " // Only change code below this line.", - "", - "", - "", + " ", + " ", + " ", " // Only change code above this line.", "", " json.map(function(val){", "", - "    val = \"\" ", + " html += \"
\"", "", - " html = html + \"
\"", + " html += \"\"", "", - " html = html + '
' + val + '
';", - "", - " html = html + \"
\"", + " html += \"
\"", "", " });", "", @@ -333,25 +327,23 @@ " });", "fcces", "", - "", "
", - "
", - "

Cat Photo Finder

", - "
", - "
", - "
", - " The message will go here", - "
", - "
", - "
", - "
", - " ", - "
", - "
", - "
", - "" + "
", + "

Cat Photo Finder

", + "
", + "
", + "
", + " The message will go here", + "
", + "
", + "
", + "
", + " ", + "
", + "
", + "" ], "challengeType": 0, "type": "waypoint" @@ -375,9 +367,9 @@ "challengeSeed": [ "fccss", " // Only change code below this line.", - "", - "", - "", + " ", + " ", + " ", " // Only change code above this line.", "fcces", "
", From 668de6e3274faf9077122a5727f4aafd477bb6b2 Mon Sep 17 00:00:00 2001 From: natac13 Date: Fri, 30 Oct 2015 19:13:31 -0400 Subject: [PATCH 08/24] added warning about navigator prompt closes #3996 --- challenges/json-apis-and-ajax.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/challenges/json-apis-and-ajax.json b/challenges/json-apis-and-ajax.json index 940cb95bdb..6c44cabac4 100644 --- a/challenges/json-apis-and-ajax.json +++ b/challenges/json-apis-and-ajax.json @@ -354,6 +354,8 @@ "description": [ "Another cool thing we can do is access our user's current location. Every browser has a built in navigator that can give us this information.", "The navigator will get our user's current longitude and latitude.", + "You will see a prompt to allow or block this site from knowing your current location. The challenge can be completed either way, as long as the code is correct.", + "By selecting allow you will see the text on the output phone change to your latitude and longitude", "Here's some code that does this:", "if (navigator.geolocation) {", "  navigator.geolocation.getCurrentPosition(function(position) {", From 90c92b0504d7dce5a99bcb709d9179ef59d7b9ba Mon Sep 17 00:00:00 2001 From: Logan Tegman Date: Fri, 30 Oct 2015 22:00:47 -0700 Subject: [PATCH 09/24] Fix BF Title Case Test Closes #3366 --- challenges/basic-bonfires.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/challenges/basic-bonfires.json b/challenges/basic-bonfires.json index f81241c9d2..8cef5e19ca 100644 --- a/challenges/basic-bonfires.json +++ b/challenges/basic-bonfires.json @@ -243,8 +243,8 @@ "titleCase(\"I'm a little tea pot\");" ], "tests": [ - "assert(typeof(titleCase(\"I'm a little tea pot\")) === \"string\", 'message: titleCase() should return a string.');", - "assert(titleCase(\"I'm a little tea pot\") === \"I'm A Little Tea Pot\", 'message: titleCase(\"I'm a little tea pot\") should return \"I'm A Little Tea Pot\".');", + "assert(typeof(titleCase(\"I'm a little tea pot\")) === \"string\", 'message: titleCase() should return a string.');", + "assert(titleCase(\"I'm a little tea pot\") === \"I'm A Little Tea Pot\", 'message: titleCase(\"I'm a little tea pot\") should return \"I'm A Little Tea Pot\".');", "assert(titleCase(\"sHoRt AnD sToUt\") === \"Short And Stout\", 'message: titleCase(\"sHoRt AnD sToUt\") should return \"Short And Stout\".');", "assert(titleCase(\"HERE IS MY HANDLE HERE IS MY SPOUT\") === \"Here Is My Handle Here Is My Spout\", 'message: titleCase(\"HERE IS MY HANDLE HERE IS MY SPOUT\") should return \"Here Is My Handle Here Is My Spout\".');" ], From a02fac9346510bee743efc1032dbdbca5da61205 Mon Sep 17 00:00:00 2001 From: Vladimir Tamara Date: Fri, 30 Oct 2015 23:49:11 -0500 Subject: [PATCH 10/24] Points to working example of using Twitch JSONP --- challenges/intermediate-ziplines.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/challenges/intermediate-ziplines.json b/challenges/intermediate-ziplines.json index bc8c20c063..454a7eb72f 100644 --- a/challenges/intermediate-ziplines.json +++ b/challenges/intermediate-ziplines.json @@ -64,7 +64,7 @@ "User Story: As a user, if Free Code Camp is streaming, I can see additional details about what they are streaming.", "Bonus User Story: As a user, I can search through the streams listed.", "Bonus User Story: As a user, I will see a placeholder notification if a streamer has closed their Twitch account. You can verify this works by adding brunofin and comster404 to your array of Twitch streamers.", - "Hint: Here's an example call to Twitch.tv's JSON API: https://api.twitch.tv/kraken/streams/freecodecamp.", + "Hint: See an example call to Twitch.tv's JSONP API at https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Zipline-Use-the-Twitchtv-JSON-API.", "Hint: The relevant documentation about this API call is here: https://github.com/justintv/Twitch-API/blob/master/v3_resources/streams.md#get-streamschannel.", "Hint: Here's an array of the Twitch.tv usernames of people who regularly stream coding: [\"freecodecamp\", \"storbeck\", \"terakilobyte\", \"habathcx\",\"RobotCaleb\",\"thomasballinger\",\"noobs2ninjas\",\"beohoff\"]", "Remember to use Read-Search-Ask if you get stuck.", From eb5c165a360cf576ab8b26bbbf60e0fe8002ced4 Mon Sep 17 00:00:00 2001 From: Logan Tegman Date: Sat, 31 Oct 2015 09:25:17 -0700 Subject: [PATCH 11/24] Fix Waypoint Target Parent Seed Code Closes #4013 --- challenges/jquery.json | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/challenges/jquery.json b/challenges/jquery.json index 37a0899018..f4bdcbd520 100644 --- a/challenges/jquery.json +++ b/challenges/jquery.json @@ -645,27 +645,29 @@ "", "", "", - "
", - "

jQuery Playground

", - "
", - "
", - "

#left-well

", - "
", - " ", - " ", - " ", + "", + "
", + "

jQuery Playground

", + "
", + "
", + "

#left-well

", + "
", + " ", + " ", + " ", + "
", "
", - "
", - "
", - "

#right-well

", - "
", - " ", - " ", - " ", + "
", + "

#right-well

", + "
", + " ", + " ", + " ", + "
", "
", "
", "
", - "
" + "" ], "type": "waypoint", "challengeType": 0 From d15953a293b3f995f82d9f4ee3dd5a33a467b6ea Mon Sep 17 00:00:00 2001 From: krantzinator Date: Sat, 31 Oct 2015 13:26:35 -0400 Subject: [PATCH 12/24] update test to allow space between css property and colon --- challenges/html5-and-css.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/challenges/html5-and-css.json b/challenges/html5-and-css.json index 9ae6a4ad8b..82f2c72603 100644 --- a/challenges/html5-and-css.json +++ b/challenges/html5-and-css.json @@ -390,7 +390,7 @@ "assert(!$(\"h2\").attr(\"style\"), 'Remove the style attribute from your h2 element.')", "assert($(\"style\") && $(\"style\").length > 1, 'Create a style element.')", "assert($(\"h2\").css(\"color\") === \"rgb(0, 0, 255)\", 'Your h2 element should be blue.')", - "assert(editor.match(/h2\\s*\\{\\s*color:\\s*blue;\\s*\\}/g), 'Ensure that your stylesheet h2 declaration is valid with a semicolon and closing brace')", + "assert(editor.match(/h2\\s*\\{\\s*color\\s*:\\s*blue;\\s*\\}/g), 'Ensure that your stylesheet h2 declaration is valid with a semicolon and closing brace')", "assert(editor.match(/<\\/style>/g) && editor.match(/<\\/style>/g).length === (editor.match(//g) || []).length, 'Make sure all your style elements are valid and have a closing tag.')" ], "challengeSeed": [ From eaf01cfe399bef8d647c03322934910df472f11b Mon Sep 17 00:00:00 2001 From: natac13 Date: Sat, 31 Oct 2015 17:42:01 -0400 Subject: [PATCH 13/24] fix seed different from description iterating odd numbers with for loop closes #4081 --- challenges/basic-javascript.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/challenges/basic-javascript.json b/challenges/basic-javascript.json index c4f5cd3e0a..a871f43675 100644 --- a/challenges/basic-javascript.json +++ b/challenges/basic-javascript.json @@ -925,7 +925,7 @@ "challengeSeed":[ "var ourArray = [];", "", - "for(var i = 1; i < 10; i += 2){", + "for(var i = 0; i < 10; i += 2){", " ourArray.push(i);", "}", "", From ab52fb61db42ee6b38afa64d9f1ddb25a6c63fa0 Mon Sep 17 00:00:00 2001 From: natac13 Date: Sat, 31 Oct 2015 18:03:21 -0400 Subject: [PATCH 14/24] fix unclear description and lack of usage in the editor. closes #4059 removed added code in the seed --- challenges/object-oriented-and-functional-programming.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/challenges/object-oriented-and-functional-programming.json b/challenges/object-oriented-and-functional-programming.json index 4570dd45ff..3be9cb4a20 100644 --- a/challenges/object-oriented-and-functional-programming.json +++ b/challenges/object-oriented-and-functional-programming.json @@ -189,8 +189,8 @@ "title":"Iterate over Arrays with .map", "description":[ "The map method is a convenient way to iterate through arrays. Here's an example usage:", - "var timesFour = array.map(function(val){", - "  return val*4;", + "var timesFour = oldArray.map(function(val){", + "  return val * 4;", "});", "", "The map method will iterate through every element of the array, creating a new array with values that have been modified by the callback function, and return it.", From 91ca185bdef48c9bb2a2cbdad7bdcaf909d6f298 Mon Sep 17 00:00:00 2001 From: Logan Tegman Date: Sun, 1 Nov 2015 09:31:06 -0800 Subject: [PATCH 15/24] Fix Waypoint Random Numbers in Range Wording Closes #3997 --- challenges/basic-javascript.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/challenges/basic-javascript.json b/challenges/basic-javascript.json index a871f43675..72108c52b8 100644 --- a/challenges/basic-javascript.json +++ b/challenges/basic-javascript.json @@ -1093,7 +1093,7 @@ "Here's the formula we'll use. Take a moment to read it and try to understand what this code is doing:", "Math.floor(Math.random() * (max - min + 1)) + min", "Define two variables: myMin and myMax, and set them both equal to numbers.", - "Then create a function called myFunction that returns a random number that's greater than or equal to myMin, and is less than myMax." + "Then create a function called myFunction that returns a random number that's greater than or equal to myMin, and is less than or equal to myMax." ], "tests": [ "assert(myFunction() >= myMin, 'message: The random number generated by myFunction should be greater than or equal to your minimum number, myMin.');", From dfea2ca1a98b19dcf4ef7548e0e1d4c40e1498e7 Mon Sep 17 00:00:00 2001 From: Berkeley Martinez Date: Sun, 1 Nov 2015 10:00:38 -0800 Subject: [PATCH 16/24] Remove old files --- challenge-migration.js | 44 -------- challengeMapping.json | 226 ----------------------------------------- jobs.json | 47 --------- storyCleanup.js | 47 --------- userMigration.js | 137 ------------------------- 5 files changed, 501 deletions(-) delete mode 100644 challenge-migration.js delete mode 100644 challengeMapping.json delete mode 100644 jobs.json delete mode 100644 storyCleanup.js delete mode 100644 userMigration.js diff --git a/challenge-migration.js b/challenge-migration.js deleted file mode 100644 index 7ef359781f..0000000000 --- a/challenge-migration.js +++ /dev/null @@ -1,44 +0,0 @@ -require('dotenv').load(); -var bonfires = require('./bonfires.json'), - app = require('../server/server'), - mongodb = require('mongodb'), - MongoClient = mongodb.MongoClient, - User = app.models.User, - UserIdentity = app.models.userIdentity, - oldUri='mongodb://localhost:27017/app30893198', - coursewares = require('./coursewares.json'); - -MongoClient.connect(oldUri, function(err, database) { - - database.collection('users').find({}).batchSize(20).toArray(function(err, users) { - if (users !== null && users.length !== 0) { - var mappedUserArray = users.map(function(user) { - Object.keys(user.profile).forEach(function(prop) { - user[prop] = user.profile[prop]; - }); - Object.keys(user.portfolio).forEach(function(prop) { - user[prop] = user.portfolio[prop]; - }); - - user.completedCoursewares = Object.keys(user.challengesHash) - .filter(function(key) { - return user.challengesHash[key] !== 0; - }) - .map(function(key) { - return({ - id: coursewares[key].id, - completedDate: user.challengesHash[key] - }); - }); - - return user; - }); - User.create(mappedUserArray, function(err) { - if (err) { - console.log(err); - } - console.log("a batch finished"); - }); - } - }); -}); diff --git a/challengeMapping.json b/challengeMapping.json deleted file mode 100644 index db6686d266..0000000000 --- a/challengeMapping.json +++ /dev/null @@ -1,226 +0,0 @@ -[ - { - "oldNumber": "0", - "newId": "bd7124d8c441eddfaeb5bdef" - }, - { - "oldNumber": "1", - "newId": "bd7125d8c441eddfaeb5bd0f" - }, - { - "oldNumber": "2", - "newId": "" - }, - { - "oldNumber": "3", - "newId": "bd7127d8c441eddfaeb5bdef" - }, - { - "oldNumber": "4", - "newId": "bd7128d8c441eddfaeb5bdef" - }, - { - "oldNumber": "5", - "newId": "bd8129d8c441eddfaeb5bdef" - }, - { - "oldNumber": "6", - "newId": "" - }, - { - "oldNumber": "7", - "newId": "" - }, - { - "oldNumber": "8", - "newId": "bd7112d8c441eddfaeb5bdef" - }, - { - "oldNumber": "9", - "newId": "bd7113d8c441eddfaeb5bdef" - }, - { - "oldNumber": "10", - "newId": "bd7114d8c441eddfaeb5bdef" - }, - { - "oldNumber": "11", - "newId": "bd7115d8c441eddfaeb5bdef" - }, - { - "oldNumber": "12", - "newId": "bd7116d8c441eddfaeb5bdef" - }, - { - "oldNumber": "13", - "newId": "bd7117d8c441eddfaeb5bdef" - }, - { - "oldNumber": "14", - "newId": "bd7118d8c441eddfaeb5bdef" - }, - { - "oldNumber": "15", - "newId": "" - }, - { - "oldNumber": "16", - "newId": "" - }, - { - "oldNumber": "17", - "newId": "" - }, - { - "oldNumber": "18", - "newId": "" - }, - { - "oldNumber": "19", - "newId": "bd7123d8c441eddfaeb5bdef" - }, - { - "oldNumber": "20", - "newId": "bd8124d8c441eddfaeb5bdef" - }, - { - "oldNumber": "21", - "newId": "bd8126d8c441eddfaeb5bdef" - }, - { - "oldNumber": "22", - "newId": "bd8127d8c441eddfaeb5bdef" - }, - { - "oldNumber": "23", - "newId": "bd8128d8c441eddfaeb5bdef" - }, - { - "oldNumber": "24", - "newId": "bd7129d8c441eddfaeb5bdef" - }, - { - "oldNumber": "25", - "newId": "bd7130d8c441eddfaeb5bdef" - }, - { - "oldNumber": "26", - "newId": "bd7131d8c441eddfaeb5bdef" - }, - { - "oldNumber": "27", - "newId": "bd7132d8c441eddfaeb5bdef" - }, - { - "oldNumber": "28", - "newId": "bd7133d8c441eddfaeb5bdef" - }, - { - "oldNumber": "29", - "newId": "bd7134d8c441eddfaeb5bdef" - }, - { - "oldNumber": "30", - "newId": "bd7135d8c441eddfaeb5bdef" - }, - { - "oldNumber": "31", - "newId": "bd7136d8c441eddfaeb5bdef" - }, - { - "oldNumber": "32", - "newId": "" - }, - { - "oldNumber": "33", - "newId": "bd7138d8c441eddfaeb5bdef" - }, - { - "oldNumber": "34", - "newId": "bd7137d8c441eddfaeb5bdef" - }, - { - "oldNumber": "35", - "newId": "bd7140d8c441eddfaeb5bdef" - }, - { - "oldNumber": "36", - "newId": "" - }, - { - "oldNumber": "37", - "newId": "" - }, - { - "oldNumber": "38", - "newId": "" - }, - { - "oldNumber": "39", - "newId": "" - }, - { - "oldNumber": "40", - "newId": "" - }, - { - "oldNumber": "41", - "newId": "" - }, - { - "oldNumber": "42", - "newId": "" - }, - { - "oldNumber": "43", - "newId": "" - }, - { - "oldNumber": "44", - "newId": "" - }, - { - "oldNumber": "45", - "newId": "" - }, - { - "oldNumber": "46", - "newId": "" - }, - { - "oldNumber": "47", - "newId": "" - }, - { - "oldNumber": "48", - "newId": "bd7153d8c441eddfaeb5bd2f" - }, - { - "oldNumber": "49", - "newId": "bd7154d8c441eddfaeb5bdef" - }, - { - "oldNumber": "50", - "newId": "bd7155d8c441eddfaeb5bdef" - }, - { - "oldNumber": "51", - "newId": "bd7156d8c441eddfaeb5bdef" - }, - { - "oldNumber": "52", - "newId": "bd7157d8c441eddfaeb5bdef" - }, - { - "oldNumber": "53", - "newId": "bd7158d8c441eddfaeb5bdef" - }, - { - "oldNumber": "54", - "newId": "" - }, - { - "oldNumber": "55", - "newId": "" - } -] diff --git a/jobs.json b/jobs.json deleted file mode 100644 index 5850dc8aba..0000000000 --- a/jobs.json +++ /dev/null @@ -1,47 +0,0 @@ -[ - { - "id": "bd7167d8c441cbafaeb5bdef", - "email": "Ada_Gerlach@gmail.com", - "phone": "1-140-557-0727", - "company": "Livestream", - "country": "Singapore", - "city": "Morar berg", - "state": "South Dakota", - "position": "Junior Backend Developer (Node.js)", - "logo": "https://s3.amazonaws.com/prod-heroku/greenhouse_job_boards/logos/000/001/189/resized/livestream_logo-rgb_standard-cc718e67ce1a0f6fa400f609bdefe605.png?1429547161", - "description": "Live life one inhalation and one exhalation at a time. May you be healthy. Let the muscles in your neck and shoulders relax. May you be safe. Reflect on the fragility and preciousness of life. Empty your mind; be formless, shapeless like water. May you be at peace. Take a deep breath. You can do what you set out to do; yes, you can. You can do what you set out to do; yes, you can. Watch each breath appear and disappear, just breathing. Give yourself a break. Live life one inhalation and one exhalation at a time. Give yourself a break. Just acknowledge what's there and let be. You can get through this. Open your heart to change, forgiveness and lovingkindness. Love is the first seed of the soul. It will be ok. Impermanence and change is a powerful teacher and teaching. Bring love into your heart, into your breath and into your being. Briefly notice any emotions, thoughts or sensations that may be driving fear and anxiety and let them be. This discomfort will pass. Bring love into your heart, into your breath and into your being. Take a deep breath. Reflect on the fragility and preciousness of life." - }, - { - "id": "bd7167d8c442cbafaeb5bdef", - "email": "Ada_Gerlach@gmail.com", - "company": "Adobe", - "country": "Singapore", - "city": "Morar berg", - "state": "South Dakota", - "position": "Junior JavaScript Engineer", - "logo": "http://cdn-3.famouslogos.us/images/adobe-logo.jpg", - "description": "Live life one inhalation and one exhalation at a time. May you be healthy. Let the muscles in your neck and shoulders relax. May you be safe. Reflect on the fragility and preciousness of life. Empty your mind; be formless, shapeless like water. May you be at peace. Take a deep breath. You can do what you set out to do; yes, you can. You can do what you set out to do; yes, you can. Watch each breath appear and disappear, just breathing. Give yourself a break. Live life one inhalation and one exhalation at a time. Give yourself a break. Just acknowledge what's there and let be. You can get through this. Open your heart to change, forgiveness and lovingkindness. Love is the first seed of the soul. It will be ok. Impermanence and change is a powerful teacher and teaching. Bring love into your heart, into your breath and into your being. Briefly notice any emotions, thoughts or sensations that may be driving fear and anxiety and let them be. This discomfort will pass. Bring love into your heart, into your breath and into your being. Take a deep breath. Reflect on the fragility and preciousness of life." - }, - { - "id": "bd7167d8c443cbafaeb5bdef", - "phone": "1-140-557-0727", - "company": "Bookspan", - "country": "Singapore", - "city": "Morar berg", - "state": "South Dakota", - "position": "Full Stack JavaScript Developer (Junior)", - "logo": "https://tm-prod.global.ssl.fastly.net/uploaded/companies/227/small_logo.png?v=db9dbe", - "description": "Live life one inhalation and one exhalation at a time. May you be healthy. Let the muscles in your neck and shoulders relax. May you be safe. Reflect on the fragility and preciousness of life. Empty your mind; be formless, shapeless like water. May you be at peace. Take a deep breath. You can do what you set out to do; yes, you can. You can do what you set out to do; yes, you can. Watch each breath appear and disappear, just breathing. Give yourself a break. Live life one inhalation and one exhalation at a time. Give yourself a break. Just acknowledge what's there and let be. You can get through this. Open your heart to change, forgiveness and lovingkindness. Love is the first seed of the soul. It will be ok. Impermanence and change is a powerful teacher and teaching. Bring love into your heart, into your breath and into your being. Briefly notice any emotions, thoughts or sensations that may be driving fear and anxiety and let them be. This discomfort will pass. Bring love into your heart, into your breath and into your being. Take a deep breath. Reflect on the fragility and preciousness of life." - }, - { - "id": "bd7167d8c444cbafaeb5bdef", - "email": "Ada_Gerlach@gmail.com", - "company": "Good Eggs", - "country": "Singapore", - "city": "Morar berg", - "state": "South Dakota", - "position": "Full Stack Developer", - "logo": "https://d1qb2nb5cznatu.cloudfront.net/startups/i/72165-64efbd521cdfe3357c811758f5436e7d-medium_jpg.jpg", - "description": "Live life one inhalation and one exhalation at a time. May you be healthy. Let the muscles in your neck and shoulders relax. May you be safe. Reflect on the fragility and preciousness of life. Empty your mind; be formless, shapeless like water. May you be at peace. Take a deep breath. You can do what you set out to do; yes, you can. You can do what you set out to do; yes, you can. Watch each breath appear and disappear, just breathing. Give yourself a break. Live life one inhalation and one exhalation at a time. Give yourself a break. Just acknowledge what's there and let be. You can get through this. Open your heart to change, forgiveness and lovingkindness. Love is the first seed of the soul. It will be ok. Impermanence and change is a powerful teacher and teaching. Bring love into your heart, into your breath and into your being. Briefly notice any emotions, thoughts or sensations that may be driving fear and anxiety and let them be. This discomfort will pass. Bring love into your heart, into your breath and into your being. Take a deep breath. Reflect on the fragility and preciousness of life." - } -] diff --git a/storyCleanup.js b/storyCleanup.js deleted file mode 100644 index 2598526c8a..0000000000 --- a/storyCleanup.js +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Created by nathanleniz on 4/25/15. - */ -require('dotenv').load(); -var mongodb = require('mongodb'), - Story = require('../models/Story.js'), - secrets = require('../config/secrets'); - mongoose = require('mongoose'); - -mongoose.connect(secrets.db); - -function storyLinkCleanup(cb) { - console.log('headLineCleanup'); - var i = 1; - var stream = Story.find({}).skip(0).limit(0).batchSize(20000).stream(); - - stream.on('data', function (story) { - console.log(i++); - this.pause(); - story.storyLink = story.storyLink. - replace(/[^a-z0-9\s]/gi, ''). - replace(/\s+/g, ' '). - toLowerCase(). - trim(); - story.save(function (err) { - if (err) { - console.log('woops'); - } - this.resume(); - }.bind(this)); - }) - .on('error', function (err) { - console.error(err); - }).on('close', function () { - console.log('done with set'); - stream.destroy(); - cb(); - }); -} - -function done() { - console.log('Migration script has completed'); - process.exit(0); -} - - -storyLinkCleanup(done); diff --git a/userMigration.js b/userMigration.js deleted file mode 100644 index 350a57ffe3..0000000000 --- a/userMigration.js +++ /dev/null @@ -1,137 +0,0 @@ -/*eslint-disable block-scoped-var */ -require('dotenv').load(); -var User = require('../models/User.js'), - secrets = require('../config/secrets'), - mongoose = require('mongoose'), - R = require('ramda'), - ziplines = require('./challenges/ziplines.json'), - basejumps = require('./challenges/basejumps.json'); - -mongoose.connect(secrets.db); - -var ziplineIds = ziplines.challenges.map(function(elem) { - return elem.id; -}); -var basejumpIds = basejumps.challenges.map(function(elem) { - return elem.id; -}); -var ziplineAndBaseJumpIds = R.concat(ziplineIds, basejumpIds); - -function userModelAssurity(cb) { - console.log('userModelAssurity'); - var i = 1; - var stream = User.find({}).skip(0).limit(0).batchSize(20000).stream(); - - stream.on('data', function (user) { - console.log(i++); - this.pause(); - user.needsMigration = true; - user.save(function (err) { - if (err) { - console.log('woops'); - } - this.resume(); - }.bind(this)); - }) - .on('error', function (err) { - console.log(err); - }).on('close', function () { - console.log('done with set'); - stream.destroy(); - cb(); - }); -} - -function migrateIt() { - console.log('migrateIt'); - var dones = 0; - var done = function() { - dones++; - if (dones === 2) { - process.exit(0); - } - if (dones === 1) { - userModelMigration(done); - } - }; - console.log('calling userModelAssurity'); - userModelAssurity(done); -} - -function userModelMigration(cb) { - - var i = 1; - - var stream = User.find({needsMigration: true}).skip(0).limit(0) - .batchSize(20000).stream(); - - stream.on('data', function (user) { - console.log(i++); - /* - if (user.challengesHash) { - this.pause(); - user.needsMigration = false; - var oldChallenges = Object.keys(user.challengesHash).filter(function (key) { - if (user.challengesHash[key]) { - user.progressTimestamps.push(user.challengesHash[key] * 1000); - } - return user.challengesHash[key]; - }); - - newChallenges.forEach(function (challenge) { - if (oldChallenges.indexOf(challenge.oldNumber) !== -1 && challenge.newId) { - user.completedCoursewares.push({ - id: challenge.newId, - completedDate: user.challengesHash[challenge.oldNumber] * 1000 - }); - } - }); - - user.completedCoursewares.forEach(function (course) { - var indexOfCourse = user.uncompletedCoursewares.indexOf(course.id) !== -1; - if (indexOfCourse !== -1) { - user.uncompletedCoursewares.splice(indexOfCourse, 1); - } - }); - - user.completedBonfires.forEach(function (bonfire) { - bonfire.completedDate = bonfire.completedDate * 1000; - user.progressTimestamps.push(bonfire.completedDate); - }); - } - */ - user.needsMigration = false; - user.completedChallenges = user.completedChallenges.map(function(elem) { - if (ziplineAndBaseJumpIds.indexOf(elem.id) > 0) { - return ({ - id: elem.id, - name: elem.name, - completedWith: elem.completedWith, - completedDate: elem.completedDate, - solution: elem.solution, - githubLink: elem.githubLink, - verified: elem.verified, - challengeType: typeof elem.githubLink === 'boolean' ? 4 : 3 - }); - } else { - return elem; - } - }); - - var self = this; - user.save(function (err) { - if (err) { - console.log('woops'); - } - self.resume(); - }); - }).on('error', function (err) { - console.log(err); - }).on('close', function () { - console.log('done with set'); - stream.destroy(); - cb(); - }); -} - -migrateIt(); From 3b27665b919b21b39e52fe5f131fa853dc2085c2 Mon Sep 17 00:00:00 2001 From: Logan Tegman Date: Sun, 1 Nov 2015 10:06:22 -0800 Subject: [PATCH 17/24] Fix Sift Through Test With Regex Wording Closes #3898 --- challenges/basic-javascript.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/challenges/basic-javascript.json b/challenges/basic-javascript.json index a871f43675..30663b5836 100644 --- a/challenges/basic-javascript.json +++ b/challenges/basic-javascript.json @@ -1183,7 +1183,7 @@ "i means that we want to ignore the case (uppercase or lowercase) when searching for the pattern.", "Regular expressions are written by surrounding the pattern with / symbols.", "Let's try selecting all the occurrences of the word and in the string Ada Lovelace and Charles Babbage designed the first computer and the software that would have run on it.", - "We can do this by replacing the . part of our regular expression with the current regular expression with the word and." + "We can do this by replacing the . part of our regular expression with the word and." ], "tests": [ "assert(test==2, 'message: Your regular expression should find two occurrences of the word and.');", From 186b37e3e57a484b4319c52f073458ee422ddf12 Mon Sep 17 00:00:00 2001 From: Logan Tegman Date: Sun, 1 Nov 2015 10:48:29 -0800 Subject: [PATCH 18/24] Fix Waypoint Unordered List Instructions Closes #3891 --- challenges/html5-and-css.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/challenges/html5-and-css.json b/challenges/html5-and-css.json index 82f2c72603..255b11ad08 100644 --- a/challenges/html5-and-css.json +++ b/challenges/html5-and-css.json @@ -1457,7 +1457,7 @@ "  <li>cheese</li>", "</ul>", "would create a bullet point-style list of \"milk\" and \"cheese\".", - "Replace your p elements with an unordered list of three things that cats love." + "Remove the last two p elements and create an unordered list of three things that cats love at the bottom of the page." ], "tests": [ "assert($(\"ul\").length > 0, 'Create a ul element.')", From 91ae0a9793439f64855ba56d9b52ef0b1773a5f8 Mon Sep 17 00:00:00 2001 From: Logan Tegman Date: Sun, 1 Nov 2015 11:07:44 -0800 Subject: [PATCH 19/24] Fix Waypoint Center Text With Bootstrap Test Closes #3864 --- challenges/bootstrap.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/challenges/bootstrap.json b/challenges/bootstrap.json index 4306f0b5f7..913d4a26db 100644 --- a/challenges/bootstrap.json +++ b/challenges/bootstrap.json @@ -183,7 +183,8 @@ "<h2 class=\"red-text text-center\">your text</h2>" ], "tests": [ - "assert($(\"h2\").hasClass(\"text-center\"), 'Your h2 element should be centered by applying the class text-center')" + "assert($(\"h2\").hasClass(\"text-center\"), 'Your h2 element should be centered by applying the class text-center')", + "assert($(\"h2\").hasClass(\"red-text\"), 'Your h2 element should still have the class red-text')" ], "challengeSeed": [ "", From 6582b5ce1af67adbf11752c804e395ff0677d69f Mon Sep 17 00:00:00 2001 From: Logan Tegman Date: Sun, 1 Nov 2015 11:22:27 -0800 Subject: [PATCH 20/24] Fix Create Radio Buttons Redundant Wording Closes #3856 --- challenges/html5-and-css.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/challenges/html5-and-css.json b/challenges/html5-and-css.json index 82f2c72603..b56fe174d4 100644 --- a/challenges/html5-and-css.json +++ b/challenges/html5-and-css.json @@ -2024,7 +2024,7 @@ "All related radio buttons should have the same name attribute.", "Here's an example of a radio button:", "<label><input type=\"radio\" name=\"indoor-outdoor\"> Indoor</label>", - "Add to your form a pair of radio buttons. Each radio button should be nested within its own label element. They should share a common name attribute. One should have the option of indoor and the other should have the option of outdoor." + "Add a pair of radio buttons to your form. One should have the option of indoor and the other should have the option of outdoor." ], "tests": [ "assert($('input[type=\"radio\"]').length > 1, 'Your page should have two radio button elements.')", From f448e83aa7c37e00eef7c095af88fc997e9a7541 Mon Sep 17 00:00:00 2001 From: Logan Tegman Date: Sun, 1 Nov 2015 11:39:12 -0800 Subject: [PATCH 21/24] Fix waypoint target html with jquery selectors wording Closes #3842 --- challenges/jquery.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/challenges/jquery.json b/challenges/jquery.json index 37a0899018..0026d2bb02 100644 --- a/challenges/jquery.json +++ b/challenges/jquery.json @@ -59,7 +59,7 @@ "jQuery often selects an HTML element with a selector, then does something to that element.", "For example, let's make all of your button elements bounce. Just add this code inside your document ready function:", "$(\"button\").addClass(\"animated bounce\")", - "Note that we've already included both the jQuery library and the Animate.css library in your code editor. So you are using jQuery to apply the Animate.css bounce class to your button elements." + "Note that we've already included both the jQuery library and the Animate.css library in the background so that you can use them in the editor. So you are using jQuery to apply the Animate.css bounce class to your button elements." ], "tests": [ "assert($(\"button\").hasClass(\"animated\") && $(\"button\").hasClass(\"bounce\"), 'Use the jQuery addClass() function to give the classes animated and bounce to your button elements.')", From 0c82d363a3f7f65983a1db6af15181ea72ef6d3b Mon Sep 17 00:00:00 2001 From: Logan Tegman Date: Sun, 1 Nov 2015 17:11:23 -0800 Subject: [PATCH 22/24] Fix Sidebar Code Indentation Character Closes #3988 --- challenges/basic-javascript.json | 34 ++++++------- challenges/html5-and-css.json | 48 +++++++++---------- challenges/json-apis-and-ajax.json | 30 ++++++------ ...t-oriented-and-functional-programming.json | 14 +++--- 4 files changed, 63 insertions(+), 63 deletions(-) diff --git a/challenges/basic-javascript.json b/challenges/basic-javascript.json index a871f43675..6eaf92406d 100644 --- a/challenges/basic-javascript.json +++ b/challenges/basic-javascript.json @@ -653,7 +653,7 @@ "In JavaScript, we can divide up our code into reusable parts called functions.", "Here's an example of a function:", "function functionName(a, b) {", - "  return a + b;", + "  return a + b;", "}", "After writing the above lines in our code, we can then pass values to our function and the result following the return statement will be returned.", "For example, we can pass numbers 4 and 2 by “calling” the function later in our code like this: functionName(4, 2).", @@ -694,10 +694,10 @@ "Objects are similar to arrays, except that instead of using indexes to access and modify their data, you access the data in objects through what are called properties.", "Here's a sample object:", "var cat = {", - "  \"name\": \"Whiskers\",", - "  \"legs\": 4,", - "  \"tails\": 1,", - "  \"enemies\": [\"Water\", \"Dogs\"]", + "  \"name\": \"Whiskers\",", + "  \"legs\": 4,", + "  \"tails\": 1,", + "  \"enemies\": [\"Water\", \"Dogs\"]", "};", "", "Objects are useful for storing data in a structured way, and can represent real world objects, like a cat.", @@ -741,10 +741,10 @@ "After you've created a JavaScript object, you can update its properties at any time just like you would update any other variable.", "For example, let's look at ourDog:", "var ourDog = {", - "  \"name\": \"Camper\",", - "  \"legs\": 4,", - "  \"tails\": 1,,", - "  \"friends\": [\"everything!\"]", + "  \"name\": \"Camper\",", + "  \"legs\": 4,", + "  \"tails\": 1,,", + "  \"friends\": [\"everything!\"]", "};", "Since he's a particularly happy dog, let's change his name to \"Happy Camper\". Here's how we update his object's name property:", "ourDog.name = \"Happy Camper\";", @@ -874,7 +874,7 @@ "In the following example we initialize with i = 0 and iterate while our condition i < 5 is true. We'll increment i by 1 in each loop iteration with i++ as our final-expression.", "var ourArray = [];", "for(var i = 0; i < 5; i++) {", - "  ourArray.push(i);", + "  ourArray.push(i);", "}", "ourArray will now contain [0,1,2,3,4].", "Let's try getting a for loop to work by pushing values to an array." @@ -912,7 +912,7 @@ "We'll start at i = 0 and loop while i < 10. We'll increment i by 2 each loop with i += 2.", "var ourArray = [];", "for(var i = 0; i < 10; i += 2) {", - "  ourArray.push(i);", + "  ourArray.push(i);", "}", "ourArray will now contain [0,2,4,6,8] ", "Let's change our initialization and final-expression so we can count by odd numbers.", @@ -952,7 +952,7 @@ "We'll start at i = 10 and loop while i > 0. We'll decrement i by 2 each loop with i -= 2.", "var ourArray = [];", "for(var i = 10; i > 0; i -= 2) {", - "  ourArray.push(i);", + "  ourArray.push(i);", "}", "ourArray will now contain [10,8,6,4,2]", "Let's change our initialization and final-expression so we can count backward by twos for numbers.", @@ -992,8 +992,8 @@ "var ourArray = [];", "var i = 0;", "while(i < 5) {", - "  ourArray.push(i);", - "  i++;", + "  ourArray.push(i);", + "  i++;", "}", "Let's try getting a while loop to work by pushing values to an array.", "Push the numbers 0 through 4 to myArray using a while loop." @@ -1140,9 +1140,9 @@ "if statements require some sort of boolean condition to evaluate.", "For example:", "if (1 === 2) {", - "  return true;", + "  return true;", "} else {", - "  return false;", + "  return false;", "}", "Let's use if and else statements to make a coin-flip game.", "Create if and else statements to return the string \"heads\" if the flip variable is zero, or else return the string \"tails\" if the flip variable is not zero." @@ -1460,7 +1460,7 @@ "If all three numbers match, we should return the number that we have in three of slots or leave it as null.", "Let's create an if statement with multiple conditions in order to check whether all numbers are equal.", "if(slotOne !== slotTwo || slotTwo !== slotThree){", - "  return null;", + "  return null;", "}" ], "tests": [ diff --git a/challenges/html5-and-css.json b/challenges/html5-and-css.json index 82f2c72603..dc5fd59eed 100644 --- a/challenges/html5-and-css.json +++ b/challenges/html5-and-css.json @@ -381,7 +381,7 @@ "</style>", "Inside that style element, you can create a CSS selector for all h2 elements. For example, if you wanted all h2 elements to be red, your style element would look like this:", "<style>", - "  h2 {color: red;}", + "  h2 {color: red;}", "</style>", "Note that it's important to have both opening and closing curly braces ({ and }) around each element's style. You also need to make sure your element's style is between the opening and closing style tags. Finally, be sure to add the semicolon to the end of each of your element's styles.", "Delete your h2 element's style attribute and instead create a CSS style element. Add the necessary CSS to turn all h2 elements blue." @@ -436,9 +436,9 @@ "Classes are reusable styles that can be added to HTML elements.", "Here's an example CSS class declaration:", "<style>", - "  .blue-text {", - "    color: blue;", - "  }", + "  .blue-text {", + "    color: blue;", + "  }", "</style>", "You can see that we've created a CSS class called blue-text within the <style> tag.", "You can apply a class to an HTML element like this:", @@ -504,7 +504,7 @@ "Remember that you can attach classes to HTML elements by using class=\"your-class-here\" within the relevant element's opening tag.", "Remember that CSS class selectors require a period at the beginning like this:", ".blue-text {", - "  color: blue;", + "  color: blue;", "}", "But also remember that class declarations don't use a period, like this:", "<h2 class=\"blue-text\">CatPhotoApp<h2>", @@ -556,7 +556,7 @@ "description": [ "Font size is controlled by the font-size CSS property, like this:", "h1 {", - "  font-size: 30px;", + "  font-size: 30px;", "}", "See if you can figure out how to give both of your p elements the font-size of 16 pixels (16px). You can do this inside the same <style> tag that we created for your red-text class.", "Create a second p element with the following kitty ipsum text: Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.", @@ -611,7 +611,7 @@ "You can set an element's font by using the font-family property.", "For example, if you wanted to set your h2 element's font to Sans-serif, you would use the following CSS:", "h2 {", - "  font-family: Sans-serif;", + "  font-family: Sans-serif;", "}", "Make all of your p elements use the Monospace font." ], @@ -715,7 +715,7 @@ "When one font isn't available, you can tell the browser to \"degrade\" to another font.", "For example, if you wanted an element to use the Helvetica font, but also degrade to the Sans-Serif font when Helvetica wasn't available, you could use this CSS style:", "p {", - "  font-family: Helvetica, Sans-Serif;", + "  font-family: Helvetica, Sans-Serif;", "}", "Now comment out your call to Google Fonts, so that the Lobster font isn't available. Notice how it degrades to the Monospace font." ], @@ -832,9 +832,9 @@ "CSS has a property called width that controls an element's width. Just like with fonts, we'll use px (pixels) to specify the image's width.", "For example, if we wanted to create a CSS class called larger-image that gave HTML elements a width of 500 pixels, we'd use:", "<style>", - "  .larger-image {", - "    width: 500px;", - "  }", + "  .larger-image {", + "    width: 500px;", + "  }", "</style>", "Create a class called smaller-image and use it to resize the image so that it's only 100 pixels wide." ], @@ -892,11 +892,11 @@ "CSS borders have properties like style, color and width", "For example, if we wanted to create a red, 5 pixel border around an HTML element, we could use this class:", "<style>", - "  .thin-red-border {", - "    border-color: red;", - "    border-width: 5px;", - "    border-style: solid;", - "  }", + "  .thin-red-border {", + "    border-color: red;", + "    border-width: 5px;", + "    border-style: solid;", + "  }", "</style>", "Create a class called thick-green-border that puts a 10-pixel-wide green border with a style of solid around an HTML element, and apply that class to your cat photo.", "Remember that you can apply multiple classes to an element by separating each class with a space within its class attribute. For example:", @@ -1453,8 +1453,8 @@ "Unordered lists start with a <ul> element. Then they contain some number of <li> elements.", "For example: ", "<ul>", - "  <li>milk</li>", - "  <li>cheese</li>", + "  <li>milk</li>", + "  <li>cheese</li>", "</ul>", "would create a bullet point-style list of \"milk\" and \"cheese\".", "Replace your p elements with an unordered list of three things that cats love." @@ -1530,8 +1530,8 @@ "Ordered lists start with a <ol> element. Then they contain some number of <li> elements.", "For example:", "<ol>", - "  <li>Garfield</li>", - "  <li>Sylvester</li>", + "  <li>Garfield</li>", + "  <li>Sylvester</li>", "</ol>", "would create a numbered list of \"Garfield\" and \"Sylvester\".", "Create an ordered list of the top 3 things cats hate the most." @@ -2386,7 +2386,7 @@ "You can set an element's background color with the background-color property.", "For example, if you wanted an element's background color to be green, you'd put this within your style element:", ".green-background {", - "  background-color: green;", + "  background-color: green;", "}", "Create a class called gray-background with the background-color of gray. Assign this class to your div element." ], @@ -2566,7 +2566,7 @@ "One cool thing about id attributes is that, like classes, you can style them using CSS.", "Here's an example of how you can take your element with the id attribute of cat-photo-element and give it the background color of green. In your style element:", "#cat-photo-element {", - "  background-color: green;", + "  background-color: green;", "}", "Note that inside your style element, you always reference classes by putting a . in front of their names. You always reference ids by putting a # in front of their names.", "Try giving your form, which now has the id attribute of cat-photo-form, a green background." @@ -3153,7 +3153,7 @@ "We can prove that the body element exists here by giving it a background-color of black.", "We can do this by adding the following to our style element:", "body {", - "  background-color: black;", + "  background-color: black;", "}" ], "tests": [ @@ -3316,7 +3316,7 @@ "Leave the blue-text and pink-text classes on your h1 element.", "Create a CSS declaration for your orange-text id in your style element. Here's an example of what this looks like:", "#brown-text {", - "  color: brown;", + "  color: brown;", "}" ], "tests": [ diff --git a/challenges/json-apis-and-ajax.json b/challenges/json-apis-and-ajax.json index 6c44cabac4..5d3b0a5e6f 100644 --- a/challenges/json-apis-and-ajax.json +++ b/challenges/json-apis-and-ajax.json @@ -58,7 +58,7 @@ "When our click event happens, we can use Ajax to update an HTML element.", "Let's make it so that when a user clicks the \"Get Message\" button, we change the text of the element with the class message to say \"Here is the message\".", "We can do this by adding the following code within our click event:", - "  $(\".message\").html(\"Here is the message\");" + "  $(\".message\").html(\"Here is the message\");" ], "tests": [ "assert(editor.match(/\\$\\s*?\\(\\s*?(?:'|\")\\.message(?:'|\")\\s*?\\)\\s*?\\.html\\s*?\\(\\s*?(?:'|\")Here\\sis\\sthe\\smessage(?:'|\")\\s*?\\);/gi), 'Clicking the \"Get Message\" button should give the element with the class message the text \"Here is the message\".')" @@ -107,9 +107,9 @@ "These properties and their values are often referred to as \"key-value pairs\".", "Let's get the JSON from Free Code Camp's Cat Photo API.", "Here's the code you can put in your click event to do this:", - "  $.getJSON(\"/json/cats.json\", function(json) {", - "    $(\".message\").html(JSON.stringify(json));", - "  });", + "  $.getJSON(\"/json/cats.json\", function(json) {", + "    $(\".message\").html(JSON.stringify(json));", + "  });", "Once you've added this, click the \"Get Message\" button. Your Ajax function will replace the \"The message will go here\" text with the raw JSON output from the Free Code Camp Cat Photo API." ], "tests": [ @@ -165,12 +165,12 @@ "Then, let's loop through our JSON, adding more HTML to that variable. When the loop is finished, we'll render it.", "Here's the code that does this:", "json.map(function(val) {", - "  var keys = Object.keys(val);", - "  html += \"<div class = 'cat'>\";", - "  keys.map(function(key) {", - "    html += \"<b>\" + key + \"</b>: \" + val[key] + \"<br>\";", - "  });", - "  html += \"</div><br>\";", + "  var keys = Object.keys(val);", + "  html += \"<div class = 'cat'>\";", + "  keys.map(function(key) {", + "    html += \"<b>\" + key + \"</b>: \" + val[key] + \"<br>\";", + "  });", + "  html += \"</div><br>\";", "});" ], "tests": [ @@ -225,7 +225,7 @@ "We've seen from the last two lessons that each object in our JSON array contains an imageLink key with a value that is the url of a cat's image.", "When we're looping through these objects, let's use this imageLink property to display this image in an img element.", "Here's the code that does this:", - "  html += \"<img src = '\" + val.imageLink + \"'>\";" + "  html += \"<img src = '\" + val.imageLink + \"'>\";" ], "tests": [ "assert(editor.match(/val.imageLink/gi), 'You should have used the imageLink property to display the images.')" @@ -289,7 +289,7 @@ "Let's filter out the cat who's \"id\" key has a value of 1.", "Here's the code to do this:", "json = json.filter(function(val) {", - "  return(val.id !== 1);", + "  return(val.id !== 1);", "});" ], "tests": [ @@ -358,9 +358,9 @@ "By selecting allow you will see the text on the output phone change to your latitude and longitude", "Here's some code that does this:", "if (navigator.geolocation) {", - "  navigator.geolocation.getCurrentPosition(function(position) {", - "    $(\"#data\").html(\"latitude: \" + position.coords.latitude + \"<br>longitude: \" + position.coords.longitude);", - "  });", + "  navigator.geolocation.getCurrentPosition(function(position) {", + "    $(\"#data\").html(\"latitude: \" + position.coords.latitude + \"<br>longitude: \" + position.coords.longitude);", + "  });", "}" ], "tests": [ diff --git a/challenges/object-oriented-and-functional-programming.json b/challenges/object-oriented-and-functional-programming.json index 3be9cb4a20..810fc81323 100644 --- a/challenges/object-oriented-and-functional-programming.json +++ b/challenges/object-oriented-and-functional-programming.json @@ -54,9 +54,9 @@ "We are also able to create objects using constructor functions.", "Here's an example of a constructor function:", "var Car = function() {", - "  this.wheels = 4;", - "  this.engines = 1;", - "  this.seats = 1;", + "  this.wheels = 4;", + "  this.engines = 1;", + "  this.seats = 1;", "};", "Give your myMotorBike object a wheels, engines and seats attribute and set them to numbers.", "You may be confused by the this keyword here. Don't worry, we will get to that very soon." @@ -190,7 +190,7 @@ "description":[ "The map method is a convenient way to iterate through arrays. Here's an example usage:", "var timesFour = oldArray.map(function(val){", - "  return val * 4;", + "  return val * 4;", "});", "", "The map method will iterate through every element of the array, creating a new array with values that have been modified by the callback function, and return it.", @@ -228,7 +228,7 @@ "reduce has an optional second argument which can be used to set the initial value of the accumulator. If no initial value is specified it will be the first array element and currentVal will start with the second array element.", "Here is an example of reduce being used to subtract all the values of an array:", "var singleVal = array.reduce(function(previousVal, currentVal) {", - "  return previousVal - currentVal;", + "  return previousVal - currentVal;", "}, 0);", "Use the reduce method to sum all the values in array and assign it to singleVal." ], @@ -263,7 +263,7 @@ "The following code is an example of using filter to remove array elements that are not even numbers:", "Note: We omit the second and third arguments since we only need the value", "array = array.filter(function(val) {", - "  return val % 2 === 0;", + "  return val % 2 === 0;", "});", "Use filter to remove all elements from array that are greater than 5." ], @@ -296,7 +296,7 @@ "Here is an example of using sort with a compare function that will sort the elements from smallest to largest number:", "var array = [1, 12, 21, 2];", "array.sort(function(a, b) {", - "  return a - b;", + "  return a - b;", "});", "Use sort to sort array from largest to smallest." ], From 28790899afac2a7e61e12c66c5f6348897fd0711 Mon Sep 17 00:00:00 2001 From: Berkeley Martinez Date: Sun, 1 Nov 2015 17:20:03 -0800 Subject: [PATCH 23/24] Add challenge testing --- challenges/advanced-bonfires.json | 1 - challenges/angularjs.json | 35 +++++++-- challenges/basic-bonfires.json | 8 +- challenges/intermediate-bonfires.json | 43 +++++----- getChallenges.js | 19 +++++ index.js | 16 ++-- test-challenges.js | 108 ++++++++++++++++++++++++++ 7 files changed, 185 insertions(+), 45 deletions(-) create mode 100644 getChallenges.js create mode 100644 test-challenges.js diff --git a/challenges/advanced-bonfires.json b/challenges/advanced-bonfires.json index 04ab7c18b2..115b236eba 100644 --- a/challenges/advanced-bonfires.json +++ b/challenges/advanced-bonfires.json @@ -157,7 +157,6 @@ "Global Object" ], "solutions": [ - "var VALUES = [1, 5, 10, 25, 100, 500, 1000, 2000, 10000];\n\nfunction drawer(price, cash, cid) {\n cash = ~~(cash * 100);\n price = ~~(price * 100);\n var diff = cash-price;\n cid.forEach(function(c) {\n c[1] = ~~(c[1] * 100);\n });\n var totalCid = cid.reduce(function(a, c) {\n return a + c[1];\n }, 0);\n if (diff > totalCid) {\n return \"Insufficient Funds\";\n }\n if (diff === totalCid) {\n return \"Closed\";\n }\n \n var change = []; \n var index = cid.length;\n while (diff > 0 && --index > -1) {\n var t = 0;\n var value = VALUES[index];\n while (diff >= value && cid[index][1] > 0) {\n t += value;\n cid[index][1] -= value;\n diff -= value;\n }\n if (t) {\n change.push([cid[index][0], t/100]);\n }\n console.log(JSON.stringify(change));\n }\n // Here is your change, ma'am.\n return change;\n}\n\n// Example cash-in-drawer array:\n// [['PENNY', 1.01],\n// ['NICKEL', 2.05],\n// ['DIME', 3.10],\n// ['QUARTER', 4.25],\n// ['ONE', 90.00],\n// ['FIVE', 55.00],\n// ['TEN', 20.00],\n// ['TWENTY', 60.00],\n// ['ONE HUNDRED', 100.00]]\n\ndrawer(19.50, 20.00, [['PENNY', 1.01], ['NICKEL', 2.05], ['DIME', 3.10], ['QUARTER', 4.25], ['ONE', 90.00], ['FIVE', 55.00], ['TEN', 20.00], ['TWENTY', 60.00], ['ONE HUNDRED', 100.00]]);\n" ], "type": "bonfire", "challengeType": 5, diff --git a/challenges/angularjs.json b/challenges/angularjs.json index 905c120f33..c55221e0fe 100644 --- a/challenges/angularjs.json +++ b/challenges/angularjs.json @@ -14,7 +14,12 @@ ], "type": "waypoint", "challengeType": 2, - "tests": [], + "tests": [ + "assert(true, 'No test needed');" + ], + "solutions": [ + "/* no test needed */" + ], "nameCn": "", "descriptionCn": [], "nameFr": "", @@ -37,7 +42,12 @@ ], "type": "waypoint", "challengeType": 2, - "tests": [], + "tests": [ + "assert(true, 'No test needed');" + ], + "solutions": [ + "/* no test needed */" + ], "nameCn": "", "descriptionCn": [], "nameFr": "", @@ -60,7 +70,12 @@ ], "type": "waypoint", "challengeType": 2, - "tests": [], + "tests": [ + "assert(true, 'No test needed');" + ], + "solutions": [ + "/* no test needed */" + ], "nameCn": "", "descriptionCn": [], "nameFr": "", @@ -82,7 +97,12 @@ ], "type": "waypoint", "challengeType": 2, - "tests": [], + "tests": [ + "assert(true, 'No test needed');" + ], + "solutions": [ + "/* no test needed */" + ], "nameCn": "", "descriptionCn": [], "nameFr": "", @@ -105,7 +125,12 @@ ], "type": "waypoint", "challengeType": 2, - "tests": [], + "tests": [ + "assert(true, 'No test needed');" + ], + "solutions": [ + "/* no test needed */" + ], "nameCn": "", "descriptionCn": [], "nameFr": "", diff --git a/challenges/basic-bonfires.json b/challenges/basic-bonfires.json index 8cef5e19ca..505b91fd5e 100644 --- a/challenges/basic-bonfires.json +++ b/challenges/basic-bonfires.json @@ -116,7 +116,7 @@ "Arithmetic Operators" ], "solutions": [ - "function factorialize(num) {\n return num === 1 ? 1 : num * factorialize(num-1);\n}\n\nfactorialize(5);\n" + "function factorialize(num) {\n return num < 1 ? 1 : num * factorialize(num-1);\n}\n\nfactorialize(5);\n" ], "type": "bonfire", "challengeType": 5, @@ -169,7 +169,6 @@ "String.toLowerCase()" ], "solutions": [ - "function palindrome(str) {\n var a = str.toLowerCase().replace(/[^a-z]/g, '');\n console.log(a.split('').reverse().join(''));\n return a == a.split('').reverse().join('');\n}\n\n\n\npalindrome(\"eye\");\npalindrome(\"A man, a plan, a canal. Panama\");\n" ], "type": "bonfire", "challengeType": 5, @@ -417,7 +416,6 @@ "String.slice()" ], "solutions": [ - "function truncate(str, num) {\n if (str.length > num) {\n return str.substring(0, num-3) + '...';\n }\n return str;\n}\n\ntruncate('A-tisket a-tasket A green and yellow basket', 11);\n" ], "type": "bonfire", "challengeType": 5, @@ -663,9 +661,7 @@ "MDNlinks": [ "Array.sort()" ], - "solutions": [ - "function where(arr, num) {\n // Find my place in this sorted array.\n return num;\n}\n\nwhere([40, 60], 50);\n" - ], + "solutions": [], "tests": [ "assert(where([10, 20, 30, 40, 50], 35) === 3, 'message: where([10, 20, 30, 40, 50], 35) should return 3.');", "assert(where([10, 20, 30, 40, 50], 30) === 2, 'message: where([10, 20, 30, 40, 50], 30) should return 2.');", diff --git a/challenges/intermediate-bonfires.json b/challenges/intermediate-bonfires.json index 9ae783a1a5..6d90d9fdd7 100644 --- a/challenges/intermediate-bonfires.json +++ b/challenges/intermediate-bonfires.json @@ -31,7 +31,7 @@ "Array.reduce()" ], "solutions": [ - "function sumAll(arr) {\n var sum = 0;\n arr.sort(function(a,b) {return a-b;});\n for (var i = arr[0]; i <= arr[1]; i++) {\n sum += i; \n }\n return sum;\n}\n\nsumAll([1, 4]);\n" + "function sumAll(arr) {\n var sum = 0;\n arr.sort(function(a,b) {return a-b;});\n for (var i = arr[0]; i <= arr[1]; i++) {\n sum += i; \n }\n return sum;\n}" ], "type": "bonfire", "challengeType": 5, @@ -80,7 +80,7 @@ "Array.concat()" ], "solutions": [ - "function diff(arr1, arr2) {\n var newArr = [];\n var h1 = Object.create(null);\n arr1.forEach(function(e) {\n h1[e] = e;\n });\n \n var h2 = Object.create(null);\n arr2.forEach(function(e) {\n h2[e] = e;\n });\n \n Object.keys(h1).forEach(function(e) {\n if (!(e in h2)) newArr.push(h1[e]);\n });\n Object.keys(h2).forEach(function(e) {\n if (!(e in h1)) newArr.push(h2[e]);\n });\n // Same, same; but different.\n return newArr;\n}\n\ndiff([1, 2, 3, 5], [1, 2, 3, 4, 5]);\n" + "function diff(arr1, arr2) {\n var newArr = [];\n var h1 = Object.create(null);\n arr1.forEach(function(e) {\n h1[e] = e;\n });\n \n var h2 = Object.create(null);\n arr2.forEach(function(e) {\n h2[e] = e;\n });\n \n Object.keys(h1).forEach(function(e) {\n if (!(e in h2)) newArr.push(h1[e]);\n });\n Object.keys(h2).forEach(function(e) {\n if (!(e in h1)) newArr.push(h2[e]);\n });\n // Same, same; but different.\n return newArr;\n}" ], "type": "bonfire", "challengeType": 5, @@ -138,7 +138,7 @@ "Array.join()" ], "solutions": [ - "function convert(num) {\n var ref = [['M', 1000], ['CM', 900], ['D', 500], ['CD', 400], ['C', 100], ['XC', 90], ['L', 50], ['XL', 40], ['X', 10], ['IX', 9], ['V', 5], ['IV', 4], ['I', 1]];\n var res = [];\n ref.forEach(function(p) {\n while (num >= p[1]) {\n res.push(p[0]);\n num -= p[1];\n }\n });\n return res.join('');\n}\n\nconvert(36);\n" + "function convert(num) {\n var ref = [['M', 1000], ['CM', 900], ['D', 500], ['CD', 400], ['C', 100], ['XC', 90], ['L', 50], ['XL', 40], ['X', 10], ['IX', 9], ['V', 5], ['IV', 4], ['I', 1]];\n var res = [];\n ref.forEach(function(p) {\n while (num >= p[1]) {\n res.push(p[0]);\n num -= p[1];\n }\n });\n return res.join('');\n}" ], "type": "bonfire", "challengeType": 5, @@ -181,7 +181,7 @@ "Object.keys()" ], "solutions": [ - "function where(collection, source) {\n var arr = [];\n var keys = Object.keys(source);\n collection.forEach(function(e) {\n if(keys.every(function(key) {return e[key] === source[key];})) {\n arr.push(e); \n }\n });\n return arr;\n}\n\nwhere([{ first: 'Romeo', last: 'Montague' }, { first: 'Mercutio', last: null }, { first: 'Tybalt', last: 'Capulet' }], { last: 'Capulet' });\n" + "function where(collection, source) {\n var arr = [];\n var keys = Object.keys(source);\n collection.forEach(function(e) {\n if(keys.every(function(key) {return e[key] === source[key];})) {\n arr.push(e); \n }\n });\n return arr;\n}" ], "type": "bonfire", "challengeType": 5, @@ -227,7 +227,7 @@ "Array.join()" ], "solutions": [ - "function replace(str, before, after) {\n if (before.charAt(0) === before.charAt(0).toUpperCase()) {\n after = after.charAt(0).toUpperCase() + after.substring(1);\n } else {\n after = after.charAt(0).toLowerCase() + after.substring(1);\n }\n return str.replace(before, after);\n}\n\nreplace(\"A quick brown fox jumped over the lazy dog\", \"jumped\", \"leaped\");\n" + "function myReplace(str, before, after) {\n if (before.charAt(0) === before.charAt(0).toUpperCase()) {\n after = after.charAt(0).toUpperCase() + after.substring(1);\n } else {\n after = after.charAt(0).toLowerCase() + after.substring(1);\n }\n return str.replace(before, after);\n}" ], "type": "bonfire", "challengeType": 5, @@ -273,7 +273,7 @@ "String.split()" ], "solutions": [ - "function translate(str) {\n if (isVowel(str.charAt(0))) return str + \"way\";\n var front = [];\n str = str.split('');\n while (str.length && !isVowel(str[0])) {\n front.push(str.shift());\n }\n return [].concat(str, front).join('') + 'ay';\n}\n\nfunction isVowel(c) {\n return ['a', 'e', 'i', 'o', 'u'].indexOf(c.toLowerCase()) !== -1;\n}\n\ntranslate(\"consonant\");\n" + "function translate(str) {\n if (isVowel(str.charAt(0))) return str + \"way\";\n var front = [];\n str = str.split('');\n while (str.length && !isVowel(str[0])) {\n front.push(str.shift());\n }\n return [].concat(str, front).join('') + 'ay';\n}\n\nfunction isVowel(c) {\n return ['a', 'e', 'i', 'o', 'u'].indexOf(c.toLowerCase()) !== -1;\n}" ], "type": "bonfire", "challengeType": 5, @@ -316,7 +316,7 @@ "String.split()" ], "solutions": [ - "var lookup = Object.create(null);\nlookup.A = 'T';\nlookup.T = 'A';\nlookup.C = 'G';\nlookup.G = 'C';\n\nfunction pair(str) {\n return str.split('').map(function(p) {return [p, lookup[p]];});\n}\n\npair(\"GCG\");\n" + "var lookup = Object.create(null);\nlookup.A = 'T';\nlookup.T = 'A';\nlookup.C = 'G';\nlookup.G = 'C';\n\nfunction pair(str) {\n return str.split('').map(function(p) {return [p, lookup[p]];});\n}" ], "type": "bonfire", "challengeType": 5, @@ -357,7 +357,7 @@ "String.fromCharCode()" ], "solutions": [ - "function fearNotLetter(str) {\n var s = str.split('').map(function(c) {return c.charCodeAt(0);});\n for (var i = 1; i < s.length; i++) {\n if (s[i]-1 != s[i-1]) {\n return String.fromCharCode(s[i]-1);\n }\n }\n}\n\nfearNotLetter('abce');\n" + "function fearNotLetter(str) {\n var s = str.split('').map(function(c) {return c.charCodeAt(0);});\n for (var i = 1; i < s.length; i++) {\n if (s[i]-1 != s[i-1]) {\n return String.fromCharCode(s[i]-1);\n }\n }\n}" ], "type": "bonfire", "challengeType": 5, @@ -402,7 +402,7 @@ "Boolean Objects" ], "solutions": [ - "function boo(bool) {\n // What is the new fad diet for ghost developers? The Boolean.\n return typeof(bool) === \"boolean\";\n}\n\nboo(null);\n" + "function boo(bool) {\n // What is the new fad diet for ghost developers? The Boolean.\n return typeof(bool) === \"boolean\";\n}\n\nboo(null);" ], "type": "bonfire", "challengeType": 5, @@ -445,7 +445,7 @@ "Array.reduce()" ], "solutions": [ - "function unite(arr1, arr2, arr3) {\n return [].slice.call(arguments).reduce(function(a, b) {\n return [].concat(a, b.filter(function(e) {return a.indexOf(e) === -1;}));\n }, []);\n}\n\nunite([1, 2, 3], [5, 2, 1, 4], [2, 1]);\n" + "function unite(arr1, arr2, arr3) {\n return [].slice.call(arguments).reduce(function(a, b) {\n return [].concat(a, b.filter(function(e) {return a.indexOf(e) === -1;}));\n }, []);\n}" ], "type": "bonfire", "challengeType": 5, @@ -489,7 +489,7 @@ "HTML Entities" ], "solutions": [ - "var MAP = { '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": '''};\n\nfunction convert(str) {\n return str.replace(/[&<>\"']/g, function(c) {\n return MAP[c];\n });\n}\n\nconvert('Dolce & Gabbana');\n" + "var MAP = { '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": '''};\n\nfunction convert(str) {\n return str.replace(/[&<>\"']/g, function(c) {\n return MAP[c];\n });\n}" ], "type": "bonfire", "challengeType": 5, @@ -531,7 +531,7 @@ "String.replace()" ], "solutions": [ - "function spinalCase(str) {\n // \"It's such a fine line between stupid, and clever.\"\n // --David St. Hubbins\n str = str.replace(/([a-z](?=[A-Z]))/g, '$1 ');\n return str.toLowerCase().replace(/\\ |\\_/g, '-');\n}\n\nspinalCase('This Is Spinal Tap');\n" + "function spinalCase(str) {\n // \"It's such a fine line between stupid, and clever.\"\n // --David St. Hubbins\n str = str.replace(/([a-z](?=[A-Z]))/g, '$1 ');\n return str.toLowerCase().replace(/\\ |\\_/g, '-');\n}" ], "type": "bonfire", "challengeType": 5, @@ -574,7 +574,7 @@ "Remainder" ], "solutions": [ - "function sumFibs(num) {\n var a = 1; \n var b = 1;\n var s = 0;\n while (a <= num) {\n if (a % 2 !== 0) { \n s += a; \n }\n a = [b, b=b+a][0];\n }\n return s;\n}\n\nsumFibs(4);\n" + "function sumFibs(num) {\n var a = 1; \n var b = 1;\n var s = 0;\n while (a <= num) {\n if (a % 2 !== 0) { \n s += a; \n }\n a = [b, b=b+a][0];\n }\n return s;\n}" ], "type": "bonfire", "challengeType": 5, @@ -615,7 +615,7 @@ "Array.push()" ], "solutions": [ - "function eratosthenesArray(n) {\n var primes = [];\n if (n > 2) {\n var half = n>>1;\n var sieve = Array(half);\n for (var i = 1, limit = Math.sqrt(n)>>1; i <= limit; i++) {\n if (!sieve[i]) {\n for (var step = 2*i+1, j = (step*step)>>1; j < half; j+=step) {\n sieve[j] = true;\n }\n }\n }\n primes.push(2);\n for (var p = 1; p < half; p++) {\n if (!sieve[p]) primes.push(2*p+1);\n }\n }\n return primes;\n}\n\nfunction sumPrimes(num) {\n return eratosthenesArray(num+1).reduce(function(a,b) {return a+b;}, 0);\n}\n\nsumPrimes(10);\n" + "function eratosthenesArray(n) {\n var primes = [];\n if (n > 2) {\n var half = n>>1;\n var sieve = Array(half);\n for (var i = 1, limit = Math.sqrt(n)>>1; i <= limit; i++) {\n if (!sieve[i]) {\n for (var step = 2*i+1, j = (step*step)>>1; j < half; j+=step) {\n sieve[j] = true;\n }\n }\n }\n primes.push(2);\n for (var p = 1; p < half; p++) {\n if (!sieve[p]) primes.push(2*p+1);\n }\n }\n return primes;\n}\n\nfunction sumPrimes(num) {\n return eratosthenesArray(num+1).reduce(function(a,b) {return a+b;}, 0);\n}\n\nsumPrimes(10);" ], "type": "bonfire", "challengeType": 5, @@ -657,7 +657,7 @@ "Smallest Common Multiple" ], "solutions": [ - "function gcd(a, b) {\n while (b !== 0) {\n a = [b, b = a % b][0];\n }\n return a;\n}\n\nfunction lcm(a, b) {\n return (a * b) / gcd(a, b);\n}\n\nfunction smallestCommons(arr) {\n arr.sort(function(a,b) {return a-b;});\n var rng = [];\n for (var i = arr[0]; i <= arr[1]; i++) {\n rng.push(i);\n }\n return rng.reduce(lcm);\n}\n\n\nsmallestCommons([1,5]);\n" + "function gcd(a, b) {\n while (b !== 0) {\n a = [b, b = a % b][0];\n }\n return a;\n}\n\nfunction lcm(a, b) {\n return (a * b) / gcd(a, b);\n}\n\nfunction smallestCommons(arr) {\n arr.sort(function(a,b) {return a-b;});\n var rng = [];\n for (var i = arr[0]; i <= arr[1]; i++) {\n rng.push(i);\n }\n return rng.reduce(lcm);\n}" ], "type": "bonfire", "challengeType": 5, @@ -695,7 +695,7 @@ "Array.filter()" ], "solutions": [ - "function find(arr, func) {\n var num;\n arr.some(function(e) {\n if (func(e)) {\n num = e;\n return true;\n }\n });\n return num;\n}\n\nfind([1, 2, 3, 4], function(num){ return num % 2 === 0; });\n" + "function find(arr, func) {\n var num;\n arr.some(function(e) {\n if (func(e)) {\n num = e;\n return true;\n }\n });\n return num;\n}" ], "type": "bonfire", "challengeType": 5, @@ -736,7 +736,7 @@ "Array.shift()" ], "solutions": [ - "(function drop(arr, func) {\n // Drop them elements.\n while (arr.length && !func(arr[0])) {\n arr.shift();\n }\n return arr;\n}\n\ndrop([1, 2, 3], function(n) {return n < 3; });\n)" + "function drop(arr, func) {\n // Drop them elements.\n while (arr.length && !func(arr[0])) {\n arr.shift();\n }\n return arr;\n}" ], "type": "bonfire", "challengeType": 5, @@ -776,7 +776,7 @@ "Array.isArray()" ], "solutions": [ - "function steamroller(arr) {\n if (!Array.isArray(arr)) {\n return [arr];\n }\n var out = [];\n arr.forEach(function(e) {\n steamroller(e).forEach(function(v) {\n out.push(v);\n });\n });\n return out;\n}\n\nsteamroller([1, [2], [3, [[4]]]]);\n" + "function steamroller(arr) {\n if (!Array.isArray(arr)) {\n return [arr];\n }\n var out = [];\n arr.forEach(function(e) {\n steamroller(e).forEach(function(v) {\n out.push(v);\n });\n });\n return out;\n}" ], "type": "bonfire", "challengeType": 5, @@ -815,7 +815,7 @@ "String.fromCharCode()" ], "solutions": [ - "function binaryAgent(str) {\n return str.split(' ').map(function(s) { return parseInt(s, 2); }).map(function(b) { return String.fromCharCode(b);}).join('');\n}\n\nbinaryAgent('01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111');\n" + "function binaryAgent(str) {\n return str.split(' ').map(function(s) { return parseInt(s, 2); }).map(function(b) { return String.fromCharCode(b);}).join('');\n}" ], "type": "bonfire", "challengeType": 5, @@ -858,7 +858,7 @@ "assert.strictEqual(every([{\"single\": \"double\"}, {\"single\": NaN}], \"single\"), false, 'message: every([{\"single\": \"double\"}, {\"single\": NaN}], \"single\") should return false');" ], "solutions": [ - "function every(collection, pre) {\n // Does everyone have one of these?\n return collection.every(function(e) { return e[pre]; });\n}\n\nevery([{'user': 'Tinky-Winky', 'sex': 'male'}, {'user': 'Dipsy', 'sex': 'male'}, {'user': 'Laa-Laa', 'sex': 'female'}, {'user': 'Po', 'sex': 'female'}], 'sex');\n" + "function every(collection, pre) {\n // Does everyone have one of these?\n return collection.every(function(e) { return e[pre]; });\n}" ], "type": "bonfire", "challengeType": 5, @@ -904,8 +904,7 @@ "Arguments object" ], "solutions": [ - "function add() {\n if (arguments.length == 1) {\n var a = arguments[0];\n if (!isNumber(a)) return;\n return function(b) {\n if (!isNumber(b)) return;\n return a+b;\n };\n }\n if (![].slice.call(arguments).every(isNumber)) return;\n return arguments[0] + arguments[1];\n}\n \nfunction isNumber(obj) {\n return toString.call(obj) == '[object Number]';\n}\n\nadd(2,3);\n", - "function add() {\n var a = arguments[0];\n if (toString.call(a) !== '[object Number]') return; \n if (arguments.length === 1) {\n return function(b) {\n if (toString.call(b) !== '[object Number]') return;\n return a + b;\n };\n }\n var b = arguments[1];\n if (toString.call(b) !== '[object Number]') return; \n return a + arguments[1];\n}\n\nadd(2,3);\n" + "function add() {\n var a = arguments[0];\n if (toString.call(a) !== '[object Number]') return; \n if (arguments.length === 1) {\n return function(b) {\n if (toString.call(b) !== '[object Number]') return;\n return a + b;\n };\n }\n var b = arguments[1];\n if (toString.call(b) !== '[object Number]') return; \n return a + arguments[1];\n}" ], "type": "bonfire", "challengeType": 5, diff --git a/getChallenges.js b/getChallenges.js new file mode 100644 index 0000000000..f86a3fc8c6 --- /dev/null +++ b/getChallenges.js @@ -0,0 +1,19 @@ +var fs = require('fs'); +var path = require('path'); + + +function getFilesFor(dir) { + return fs.readdirSync(path.join(__dirname, '/' + dir)); +} + +module.exports = function getChallenges() { + try { + return getFilesFor('challenges') + .map(function(file) { + return require('./challenges/' + file); + }); + } catch (e) { + console.log('error', e); + return []; + } +}; diff --git a/index.js b/index.js index 8300b97245..c11360d6a7 100644 --- a/index.js +++ b/index.js @@ -2,29 +2,23 @@ require('babel/register'); require('dotenv').load(); -var fs = require('fs'), - Rx = require('rx'), +var Rx = require('rx'), _ = require('lodash'), - path = require('path'), + getChallenges = require('./getChallenges'), app = require('../server/server'); -function getFilesFor(dir) { - return fs.readdirSync(path.join(__dirname, '/' + dir)); -} var Challenge = app.models.Challenge; -var challenges = getFilesFor('challenges'); var destroy = Rx.Observable.fromNodeCallback(Challenge.destroyAll, Challenge); var create = Rx.Observable.fromNodeCallback(Challenge.create, Challenge); destroy() - .flatMap(function() { return Rx.Observable.from(challenges); }) - .flatMap(function(file) { - var challengeSpec = require('./challenges/' + file); + .flatMap(function() { return Rx.Observable.from(getChallenges()); }) + .flatMap(function(challengeSpec) { var order = challengeSpec.order; var block = challengeSpec.name; var isBeta = !!challengeSpec.isBeta; - console.log('parsed %s successfully', file); + console.log('parsed %s successfully', block); // challenge file has no challenges... if (challengeSpec.challenges.length === 0) { diff --git a/test-challenges.js b/test-challenges.js new file mode 100644 index 0000000000..e47ed22fbc --- /dev/null +++ b/test-challenges.js @@ -0,0 +1,108 @@ +/* eslint-disable no-eval, no-process-exit */ +import _ from 'lodash'; +import { Observable } from 'rx'; +import tape from 'tape'; +import getChallenges from './getChallenges'; + + +function createIsAssert(t, isThing) { + const { assert } = t; + return function() { + const args = [...arguments]; + args[0] = isThing(args[0]); + assert.apply(t, args); + }; +} + +function fillAssert(t) { + const assert = t.assert; + + assert.isArray = createIsAssert(t, _.isArray); + assert.isBoolean = createIsAssert(t, _.isBoolean); + assert.isString = createIsAssert(t, _.isString); + assert.isNumber = createIsAssert(t, _.isNumber); + assert.isUndefined = createIsAssert(t, _.isUndefined); + + assert.deepEqual = t.deepEqual; + assert.equal = t.equal; + assert.strictEqual = t.equal; + + assert.sameMembers = function sameMembers() { + const [ first, second, ...args] = arguments; + assert.apply( + t, + [ + _.difference(first, second).length === 0 && + _.difference(second, first).length === 0 + ].concat(args) + ); + }; + + assert.includeMembers = function includeMembers() { + const [ first, second, ...args] = arguments; + assert.apply(t, [_.difference(second, first).length === 0].concat(args)); + }; + + assert.match = function match() { + const [value, regex, ...args] = arguments; + assert.apply(t, [regex.test(value)].concat(args)); + }; + + return assert; +} + +function createTest({ title, tests = [], solutions = [] }) { + const plan = tests.length; + return Observable.fromCallback(tape)(title) + .doOnNext(t => solutions.length ? t.plan(plan) : t.end()) + .flatMap(t => { + if (solutions.length <= 0) { + t.comment('No solutions for ' + title); + return Observable.just({ + title, + type: 'missing' + }); + } + + return Observable.just(t) + .map(fillAssert) + /* eslint-disable no-unused-vars */ + // assert is used within the eval + .doOnNext(assert => { + /* eslint-enable no-unused-vars */ + solutions.forEach(solution => { + tests.forEach(test => { + eval(solution + ';;' + test); + }); + }); + }) + .map(() => ({ title })); + }); +} + +Observable.from(getChallenges()) + .flatMap(challengeSpec => { + return Observable.from(challengeSpec.challenges); + }) + .flatMap(challenge => { + return createTest(challenge); + }) + .map(({ title, type }) => { + if (type === 'missing') { + return title; + } + return false; + }) + .filter(title => !!title) + .toArray() + .subscribe( + (noSolutions) => { + console.log( + '# These challenges have no solutions\n- [ ] ' + + noSolutions.join('\n- [ ] ') + ); + }, + err => { throw err; }, + () => process.exit(0) + ); + From 266d653bf2ec7164e6e420bc2a40e87ad5ee0dbf Mon Sep 17 00:00:00 2001 From: Berkeley Martinez Date: Sun, 1 Nov 2015 21:18:00 -0800 Subject: [PATCH 24/24] Fix uncaught exceptions when testing --- test-challenges.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test-challenges.js b/test-challenges.js index e47ed22fbc..93a994c30c 100644 --- a/test-challenges.js +++ b/test-challenges.js @@ -72,7 +72,11 @@ function createTest({ title, tests = [], solutions = [] }) { /* eslint-enable no-unused-vars */ solutions.forEach(solution => { tests.forEach(test => { - eval(solution + ';;' + test); + try { + eval(solution + ';;' + test); + } catch (e) { + t.fail(e); + } }); }); })