From b71453f4e2c278b635988269cae1c42d8e7bd614 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Sun, 8 Feb 2015 23:46:08 -0800 Subject: [PATCH 01/68] update the first 13 courseware challenges and remove some silly compliments --- controllers/resources.json | 22 +------ seed_data/coursewares.json | 122 ++++++++++++++++++++++--------------- 2 files changed, 76 insertions(+), 68 deletions(-) diff --git a/controllers/resources.json b/controllers/resources.json index 58b2a1bcf1..2026d8015e 100644 --- a/controllers/resources.json +++ b/controllers/resources.json @@ -162,12 +162,6 @@ "compliments": [ "Over the top!", "Down the rabbit hole we go!", - "Well, isn't that special!", - "Somewhere over the rainbow!", - "Follow the white rabbit!", - "Eye of the tiger!", - "Run, Forest, run!", - "Welcome to the Rock!", "Bring that rain!", "Target acquired!", "Feel that need for speed!", @@ -186,8 +180,7 @@ "The town is now red!", "To the nines!", "Nothing but net!", - "Grumpy cat approves!", - "The world rejoices!", + "The world rejoices!", "That's the way it's done!", "You rock!", "Woo-hoo!", @@ -216,38 +209,27 @@ "Sonic Boom!", "Here's looking at you, Code!", "Ride like the wind!", - "The more you code!", "Legen - wait for it - dary!", "Ludicrous Speed! Go!", "Yes you can!", "Most triumphant!", "One loop to rule them all!", - "Ain't got time to bleed!", "By the power of Grayskull!", "You did it!", "Storm that castle!", "Face-melting guitar Solo!", "Checkmate!", - "Remember the Alamo!", "Bodacious!", - "You're the man now, dog!", "Tubular!", "You're outta sight!", "Keep calm and code on!", "Even sad panda smiles!", "Even grumpy cat approves!", - "Koolaid Man says oh yeah!", + "Kool Aid Man says oh yeah!", "Bullseye!", - "You stay classy, San Diego!", - "Loud noises!", - "Me want cookie!", "Far out!", "You're heating up!", - "Crash override!", - "This is Sparta!", - "You ARE the law!", "Hasta la vista, challenge!", - "Huh? It's just a box..." ], "phrases": [ "Shout it from on top of a mountain", diff --git a/seed_data/coursewares.json b/seed_data/coursewares.json index d743390948..27454518f6 100644 --- a/seed_data/coursewares.json +++ b/seed_data/coursewares.json @@ -12,7 +12,7 @@ "To advance to the next exercise, change the h1 tag's text to say \"hello world\" instead of \"hello\"." ], "tests": [ - "expect($('h1')).to.have.text('hello world');" + "expect((/hello(\\s)+world/gi).test($('h1').text())).to.be.true;" ], "challengeSeed": [ "

hello

" @@ -30,8 +30,8 @@ "h2 elements are slightly smaller than h1 elements. There are also an h3, h4, h5 and h6 elements." ], "tests": [ - "expect($('h1')).to.have.text('hello world');", - "expect($('h2')).to.have.text('cat photo app');" + "expect((/hello(\\s)+world/gi).test($('h1').text())).to.be.true;", + "expect((/cat(\\s)+photo(\\s)+app/gi).test($('h2').text())).to.be.true;" ], "challengeSeed": [ "

hello world

" @@ -48,7 +48,7 @@ "You can create a p element like so: <p>I'm a p tag!</p>" ], "tests": [ - "expect($('p')).to.have.text('hello paragraph');" + "expect((/hello(\\s)+paragraph/gi).test($('p').text())).to.be.true;" ], "challengeSeed": [ "

hello world

", @@ -67,7 +67,7 @@ "You can start a comment with <!-- and end a comment with -->." ], "tests": [ - "expect($('h1')).to.have.text('hello world');" + "expect((/hello(\\s)+world/gi).test($('h1').text())).to.be.true;" ], "challengeSeed": [ "", "", "", "

hello world

", - "

hello html

", - "

hello paragraph

" + "

cat photo app

", + "

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

" ], "challengeType": 0 }, @@ -305,15 +310,36 @@ "name": "Using Important to Override Styles", "difficulty" : "0.13", "description": [ - "", - "" + "Apply both the \"blue-text\" and \"urgently-red\" classes to all h2 elements, but use !important to ensure the element is rendered as being red.", + "Sometimes HTML elements will receive conflicting information from CSS classes as to how they should be styled.", + "If there's a conflict in the CSS, the browser will use whichever style declaration is closest to the bottom of the CSS document (whichever declaration comes last). Note that in-line style declarations are the final authority in how an HTML element will be rendered.", + "There's one way to ensure that an element is rendered with a certain style, regardless of where that declaration is located. That one way is to use !important.", + "Look at the example in the editor's style tag to see how you can use !important.", + "Now see if you can make sure the h2 element is rendered in the color red without removing the \"blue-text\" class, doing an in-line styling, or changing the sequence of CSS class declarations." ], "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" + "expect($('h2')).to.have.class('urgently-red');", + "expect($('h2')).to.have.class('blue-text');", + "expect($('h2')).to.have.css('color', 'rgb(255, 0, 0)');" ], "challengeSeed": [ - "

hello world

" + "", + "", + "

hello world

", + "

cat photo app

", + "

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

" ], "challengeType": 0 }, From b32d0219af3a0605cf8acba53c573cf597866f18 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Mon, 9 Feb 2015 07:57:53 -0800 Subject: [PATCH 02/68] remove errant comma --- controllers/resources.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/resources.json b/controllers/resources.json index 2026d8015e..1c3ea9abe2 100644 --- a/controllers/resources.json +++ b/controllers/resources.json @@ -229,7 +229,7 @@ "Bullseye!", "Far out!", "You're heating up!", - "Hasta la vista, challenge!", + "Hasta la vista, challenge!" ], "phrases": [ "Shout it from on top of a mountain", From c1e2af95250afbd7d116b080a0f30336b1e06cde Mon Sep 17 00:00:00 2001 From: Branden Byers Date: Mon, 9 Feb 2015 10:18:05 -0600 Subject: [PATCH 03/68] Fix typos The only none obvious fix was this one: 'Lobster' to "Lobster" with double quotes for consistency. The first reference to Lobster was with single quotes and the next challenge had them in double quotes. --- seed_data/coursewares.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/seed_data/coursewares.json b/seed_data/coursewares.json index 27454518f6..9e17304357 100644 --- a/seed_data/coursewares.json +++ b/seed_data/coursewares.json @@ -6,9 +6,9 @@ "description": [ "Welcome to Free Code Camp's first challenge! Click on the button below for further instructions.", "Awesome. Now you can read the rest of this challenge's instructions.", - "You can edit code in text editor we've embedded into this web page.", + "You can edit code in the text editor we've embedded into this web page.", "Do you see the code in the text editor that says <h1>hello</h1>? That's an HTML element.", - "Most HTML elements have an opening tag and a closing tag. Opening tags look like this: <h1>. Closing tags look like this: </h1>. Note that the only difference between opening and is that closing tags have a slash after their opening angle bracket.", + "Most HTML elements have an opening tag and a closing tag. Opening tags look like this: <h1>. Closing tags look like this: </h1>. Note that the only difference between opening and closing tags is that closing tags have a slash after their opening angle bracket.", "To advance to the next exercise, change the h1 tag's text to say \"hello world\" instead of \"hello\"." ], "tests": [ @@ -194,7 +194,7 @@ }, { "_id" : "bad87fee1348bd9aeff08806", - "name": "Use a CSS Classes to Style Multiple Elements", + "name": "Use a CSS Class to Style Multiple Elements", "difficulty" : "0.09", "description": [ "Apply the \"red-text\" class to the h1, h2 and p elements.", @@ -264,7 +264,7 @@ " h2 {", " color: red;", " font-size: 24px;", - " font-family: 'Lobster'", + " font-family: \"Lobster\"", " }", " p {", " font-size: 16px;", @@ -1856,4 +1856,4 @@ ], "challengeType": 0 } -] \ No newline at end of file +] From b8ef6f3fb245e72e7e5354888684f964b57c67b3 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Mon, 9 Feb 2015 11:22:53 -0800 Subject: [PATCH 04/68] move navbar below content to improve screen reading experience --- views/layout-wide.jade | 2 +- views/layout.jade | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/views/layout-wide.jade b/views/layout-wide.jade index 33873b2bf2..683ea973b2 100644 --- a/views/layout-wide.jade +++ b/views/layout-wide.jade @@ -17,9 +17,9 @@ html(ng-app='profileValidation', lang='en') != css('main') body.no-top-and-bottom-margins.full-screen-body-background - include partials/navbar-wide include partials/flash block content + include partials/navbar-wide include partials/footer != js('application') script. diff --git a/views/layout.jade b/views/layout.jade index 6e5cadeefd..ddce7f6011 100644 --- a/views/layout.jade +++ b/views/layout.jade @@ -15,10 +15,10 @@ html(ng-app='profileValidation', lang='en') != css('main') body.top-and-bottom-margins - include partials/navbar-narrow .container include partials/flash block content + include partials/navbar-narrow include partials/footer != js('application') script. From d8baf3d5881713aa5df7d7d81d151face2c9b2fd Mon Sep 17 00:00:00 2001 From: Nathan Leniz Date: Mon, 9 Feb 2015 14:29:03 -0500 Subject: [PATCH 05/68] Fix so routing handles /coursewares and /coursewares/ --- controllers/courseware.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/courseware.js b/controllers/courseware.js index 7e2c85f0a2..fe48720a35 100644 --- a/controllers/courseware.js +++ b/controllers/courseware.js @@ -16,7 +16,7 @@ exports.coursewareNames = function(req, res) { exports.returnNextCourseware = function(req, res) { if (!req.user) { - return res.redirect('coursewares/start-our-challenges'); + return res.redirect('../coursewares/start-our-challenges'); } var completed = req.user.completedCoursewares.map(function (elem) { return elem._id; From d466c704c2de747d885742ae4cca797f73a48c04 Mon Sep 17 00:00:00 2001 From: Branden Byers Date: Mon, 9 Feb 2015 23:29:12 -0600 Subject: [PATCH 06/68] Add 18 new bonfire challenges Finders Keepers Where art thou Chunky Monkey Falsey Bouncer Slasher Flick Drop it like its hot Steamroller Seek and Destroy Where do I belong? Sorted Union Symmetric Difference Everything Be True Boo who? Confirm the Ending Convert HTML Entities Spinal-Tap-Case Repeat a string repeat a string Truncate a string --- seed_data/bonfires.json | 280 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 280 insertions(+) diff --git a/seed_data/bonfires.json b/seed_data/bonfires.json index 7508492dff..f4a334f52b 100644 --- a/seed_data/bonfires.json +++ b/seed_data/bonfires.json @@ -323,6 +323,286 @@ "assert.deepEqual(inventory([], [[2, 'Hair Pin'], [3, 'Half-Eaten Apple'], [67, 'Bowling Ball'], [7, 'Toothpaste']]), [[2, 'Hair Pin'], [3, 'Half-Eaten Apple'], [67, 'Bowling Ball'], [7, 'Toothpaste']]);", "assert.deepEqual(inventory([[0, 'Bowling Ball'], [0, 'Dirty Sock'], [0, 'Hair pin'], [0, 'Microphone']], [[1, 'Hair Pin'], [1, 'Half-Eaten Apple'], [1, 'Bowling Ball'], [1, 'Toothpaste']]), [[1, 'Bowling Ball'], [1, 'Dirty Sock'], [1, 'Hair pin'], [1, 'Half-Eaten Apple'], [1, 'Microphone'], [1, 'Toothpaste']]);" ] + }, + { + "_id":"6ee40f1041b06c996f7b2406", + "name":"Finders Keepers", + "difficulty":"2", + "description":[ + "Create a function that looks through an array (first argument) and returns the first element in the array that passes a truth test (second argument)." + ], + "challengeEntryPoint":"find([1, 2, 3, 4], function(num){ return num % 2 === 0; });", + "challengeSeed":"function find(arr, func) {\n var num = 0;\r\n return num;\r\n}", + "tests":[ + "assert.strictEqual(find([1, 3, 5, 8, 9, 10], function(num) { return num % 2 === 0; }), 8, 'should return first found value');", + "assert.strictEqual(find([1, 3, 5, 9], function(num) { return num % 2 === 0; }), undefined, 'should return undefined if not found');" + ] +}, +{ + "_id":"38e512fbe388ac2f9198f0fa", + "name":"Where art thou", + "difficulty":"1", + "description":[ + "Maketh a function that looks through a list (first argument) and returns an array of all objects that have equivalent property values (second argument)." + ], + "challengeEntryPoint":"where([{ first: 'Romeo', last: 'Montague' }, { first: 'Mercutio', last: null }, { first: 'Tybalt', last: 'Capulet' }], { last: 'Capulet' });", + "challengeSeed":"function where(collection, source) {\n var arr = [];\r\n // What's in a name?\r\n return arr;\r\n}", + "tests":[ + "assert.deepEqual(where([{ first: 'Romeo', last: 'Montague' }, { first: 'Mercutio', last: null }, { first: 'Tybalt', last: 'Capulet' }], { last: 'Capulet' }), [{ first: 'Tybalt', last: 'Capulet' }], 'should return an array of objects');", + "assert.deepEqual(where([{ 'a': 1 }, { 'a': 1 }, { 'a': 1, 'b': 2 }], { 'a': 1 }), [{ 'a': 1 }, { 'a': 1 }, { 'a': 1 }], 'should return with multiples');" + ] +}, +{ + "_id":"e9bd25c716030ec90084d8a1", + "name":"Chunky Monkey", + "difficulty":"1", + "description":[ + "Write a function that splits an array (first argument) into groups the length of size (second argument) and returns them as a multidimensional array." + ], + "challengeEntryPoint":"chunk((['a', 'b', 'c', 'd'], 2));", + "challengeSeed":"function chunk(arr, size) {\n // Break it up.\r\n return arr;\r\n}", + "tests":[ + "assert.deepEqual(chunk(['a', 'b', 'c', 'd'], 2), [['a', 'b'], ['c', 'd']], 'should return chunked arrays');", + "assert.deepEqual(chunk([0, 1, 2, 3, 4, 5], 3), [[0, 1, 2], [3, 4, 5]], 'should return chunked arrays');", + "assert.deepEqual(chunk([0, 1, 2, 3, 4, 5], 4), [[0, 1, 2, 3], [4, 5]], 'should return cthe last chunk as remaining elements');" + ] +}, +{ + "_id":"9df08ec01beb4f99fc7a68f2", + "name":"Falsey Bouncer", + "difficulty":"1", + "description":[ + "Remove all falsey values from an array.", + "Falsey values in javascript are false, null, 0, \"\", undefined, and NaN." + ], + "challengeEntryPoint":"bouncer([7, 'ate', '', false, 9]);", + "challengeSeed":"function bouncer(arr) {\n // Don't show a false ID to this bouncer.\r\n return arr;\r\n}", + "tests":[ + "assert.deepEqual(bouncer([7, 'ate', '', false, 9]), [7, 'ate', 9], 'should remove falsey values');", + "assert.deepEqual(bouncer(['a', 'b', 'c']), ['a', 'b', 'c'], 'should return full array if no falsey elements');", + "assert.deepEqual(bouncer([false, null, 0]), [], 'should return empty array if all elements are falsey');" + ] +}, +{ + "_id":"fb31c21b530c0dafa9e241ee", + "name":"Slasher Flick", + "difficulty":"1", + "description":[ + "Return the remaining elements of an array after chopping off n elements from the head." + ], + "challengeEntryPoint":"slasher([1, 2, 3], 2);", + "challengeSeed":"function slasher(arr) {\n // it doesn't allways pay to be first\r\n return arr;\r\n}", + "tests":[ + "assert.deepEqual(slasher([1, 2, 3], 2), [3], 'should drop the first two elements');", + "assert.deepEqual(slasher([1, 2, 3], 0), [1, 2, 3], 'should return all elements when n < 1');", + "assert.deepEqual(slasher([1, 2, 3], 9), [], 'should return an empty array when n >= array.length');" + ] +}, +{ + "_id":"5edeed1811a43193f9f1c841", + "name":"Drop it like it's hot", + "difficulty":"2", + "description":[ + "Drop the elements of an array (first argument), starting from the front, until the predicate (second argument) returns true." + ], + "challengeEntryPoint":"drop([1, 2, 3], function(n) {return n < 3; });", + "challengeSeed":"function drop(arr, func) {\n // Drop them elements.\r\n return arr;\r\n}", + "tests":[ + "assert.deepEqual(drop([1, 2, 3, 4], function(n) {return n < 3; }), [3, 4], 'should return remaining array');", + "assert.deepEqual(drop([1, 2, 3], function(n) {return n < 0; }), [1, 2, 3], 'should return complete array if predicate met in first element.');", + "assert.deepEqual(drop([1, 2, 3, 4], function(n) {return n < 5; }), [], 'should return an empty array if predicate does not return true');" + ] +}, +{ + "_id":"db306dbdcc907c7ddfc30830", + "name":"Steamroller", + "difficulty":"2", + "description":[ + "Flatten a nested array. You must account for varying levels of nesting." + ], + "challengeEntryPoint":"steamroller([1, [2], [3, [[4]]]]);", + "challengeSeed":"function steamroller(arr) {\n // I'm a steamroller, baby\r\n return arr;\r\n}", + "tests":[ + "assert.deepEqual(steamroller([[['a']], [['b']]]), ['a', 'b'], 'should flatten nested arrays');", + "assert.deepEqual(steamroller([1, [2], [3, [[4]]]]), [1, 2, 3, 4], 'should flatten nested arrays');", + "assert.deepEqual(steamroller([1, [], [3, [[4]]]]), [1, 3, 4], 'should work with empty arrays');" + ] +}, +{ + "_id":"b39963a4c10bc8b4d4f06d7e", + "name":"Seek and Destroy", + "difficulty":"1", + "description":[ + "Remove all values (last argument(s)) from an array (first argument) and return as a new array." + ], + "challengeEntryPoint":"destroyer([1, 2, 3, 1, 2, 3], 2, 3);", + "challengeSeed":"function destroyer(arr) {\n // Remove all the values\r\n return arr;\r\n}", + "tests":[ + "assert.strictEqual(destroyer([1, 2, 3, 1, 2, 3], 2, 3), [1, 1], 'should remove correct values from an array');", + "assert.strictEqual(destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3), [1, 5, 1], 'should remove correct values from an array');" + ] +}, +{ + "_id":"b24c1a4622e3c05097f71d67", + "name":"Where do I belong?", + "difficulty":"1", + "description":[ + "Return the lowest index at which a value (second argument) should be inserted into a sorted array (first argument)." + ], + "challengeEntryPoint":"where([40, 60], 50);", + "challengeSeed":"function where(arr, num) {\n // Find my place in this sorted array.\r\n return num;\r\n}", + "tests":[ + "var numbers = [10, 20, 30, 40, 50], num = 35;", + "var indexForNum = where(numbers, num);", + "assert.equal(indexForNum, 3, '35 should be inserted at index 3');", + "var indexFor30 = where(numbers, 30);", + "assert.equal(indexFor30, 2, '30 should be inserted at index 2');" + ] +}, +{ + "_id":"5105e963526e7de52b219be9", + "name":"Sorted Union", + "difficulty":"2", + "description":[ + "Write a function that takes two or more arrays and returns a new array of unique values sorted in order." + ], + "challengeEntryPoint":"unite([1, 2, 3], [5, 2, 1, 4], [2, 1]);", + "challengeSeed":"function unite(arr) {\n return arr;\r\n}", + "tests":[ + "assert.deepEqual(unite([1, 3, 2], [5, 2, 1, 4], [2, 1]), [1, 3, 2, 5, 4], 'should return the union of the given arrays');", + "assert.deepEqual(unite([1, 3, 2], [1, [5]], [2, [4]]), [1, 3, 2, [5], [4]], 'should not flatten nested arrays');" + ] +}, +{ + "_id":"42f503de51cf954ede28891d", + "name":"Symmetric Difference", + "difficulty":"2", + "description":[ + "Create a function that takes two or more arrays and returns an array of the symmetric difference of the provided arrays.", + "The mathematical term symmetric difference refers to the elements in two sets that are in either the first or second set, but not in both." + ], + "challengeEntryPoint":"sym([1, 2, 3], [5, 2, 1, 4]);", + "challengeSeed":"function sym(arr) {\n return arr;\r\n}", + "tests":[ + "assert.deepEqual(sym([1, 2, 5], [2, 3, 5], [3, 4, 5]), [1, 4, 5], 'should return the symmetric difference of the given arrays');", + "assert.deepEqual(sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]), [1, 4, 5], 'should return an array of unique values');", + "assert.deepEqual(sym([1, 1]), [1], 'should return an array of unique values');" + ] +}, +{ + "_id":"920d2431ad0c6a099a4b8b52", + "name":"Everything Be True", + "difficulty":"2", + "description":[ + "Check if the predicate (second argument) returns truthy for all elements of a collection (first argument)." + ], + "challengeEntryPoint":"every([{'user': 'Tinky-Winky', 'sex': 'male'}, {'user': 'Dipsy', 'sex': 'male'}, {'user': 'Laa-Laa', 'sex': 'female'}, {'user': 'Po', 'sex': 'female'}], 'sex');", + "challengeSeed":"function every(collection, pre) {\n // Does everyone have one of these?\r\n return pre;\r\n}", + "tests":[ + "assert.strictEqual(every([{'user': 'Tinky-Winky', 'sex': 'male'}, {'user': 'Dipsy', 'sex': 'male'}, {'user': 'Laa-Laa', 'sex': 'female'}, {'user': 'Po', 'sex': 'female'}], 'sex'), true, 'should return true if predicate returns truthy for all elements in the collection');", + "assert.strictEqual(every([{'user': 'Tinky-Winky', 'sex': 'male'}, {'user': 'Dipsy', 'sex': 'male'}, {'user': 'Laa-Laa', 'sex': 'female'}, {'user': 'Po', 'sex': 'female'}], {'sex', 'female'}), false, 'should return false if predicate returns falsey for any element in the collection');" + ] +}, +{ + "_id":"c77dbc43c33f39daa4429b4f", + "name":"Boo who?", + "difficulty":"2", + "description":[ + "Check if a value is classified as a boolean primitive. Return true or false.", + "Boolean primitives are true and false." + ], + "challengeEntryPoint":"boo(null);", + "challengeSeed":"function boo(boolean) {\n // What is the new fad diet for ghost developers? The Boolean.\r\n return boolean;\r\n}", + "tests":[ + "assert.strictEqual(boo(true), true);", + "assert.strictEqual(boo(false), true);", + "assert.strictEqual(boo(Object(true)), true);", + "assert.strictEqual(boo(Object(false)), true);", + "assert.strictEqual(boo(args), false);", + "assert.strictEqual(boo([1, 2, 3]), false);", + "assert.strictEqual(boo(slice), false);", + "assert.strictEqual(boo({ 'a': 1 }), false);", + "assert.strictEqual(boo(1), false);", + "assert.strictEqual(boo(NaN), false);", + "assert.strictEqual(boo('a'), false);" + ] +}, +{ + "_id":"8cda2fb1324d9b0fa741e6b5", + "name":"Confirm the Ending", + "difficulty":"1", + "description":[ + "Check if a string (first argument) ends with the given target string (second argument)." + ], + "challengeEntryPoint":"end('Bastian', 'n');", + "challengeSeed":"function end(str, target) {\n // \"Never give up and good luck will find you.\"\r\n // -- Falcor\r\n return str;\r\n}", + "tests":[ + "assert.strictEqual(end('Bastian', 'n'), true, 'should equal true if target equals end of string');", + "assert.strictEqual(end('He has to give me a new name', 'name'), true, 'should equal true if target equals end of string');", + "assert.strictEqual(end('If you want to save our world, you must hurry. We dont know how much longer we can withstand the nothing', 'mountain'), false, 'should equal false if target does not equal end of string');" + ] +}, +{ + "_id":"26b0bb188d873cb2c8729495", + "name":"Convert HTML Entities", + "difficulty":"1", + "description":[ + "Convert the characters \"&\", \"<\", \">\", '\"', and \"'\", in a string to their corresponding HTML entities." + ], + "challengeEntryPoint":"convert('Dolce & Gabbana');", + "challengeSeed":"function convert(str) {\n // :)\r\n return str;\r\n}", + "tests":[ + "assert.strictEqual(convert('Dolce & Gabbana'), 'Dolce & Gabbana', 'should escape characters');", + "assert.strictEqual(convert('abc'), 'abc', 'should handle strings with nothing to escape');" + ] +}, +{ + "_id":"5103376db3ba46b2d50db289", + "name":"Spinal-Tap-Case", + "difficulty":"2", + "description":[ + "Convert a string to spinal case." + ], + "challengeEntryPoint":"spinalCase('This Is Spinal Tap');", + "challengeSeed":"function spinalCase(str) {\n // \"It's such a fine line between stupid, and clever.\"\r\n // --David St. Hubbins\r\n return str;\r\n}", + "tests":[ + "assert.strictEqual(spinalCase('This Is Spinal Tap'), 'this-is-spinal-tap', 'should return spinal case from string with spaces');", + "assert.strictEqual(spinalCase('thisIsSpinalTap'), 'this-is-spinal-tap', 'should return spinal case from string with camel case');", + "assert.strictEqual(spinalCase('The_Andy_Griffith_Show'), 'the-andy-griffith-show', 'should return spinal case from string with snake case');", + "assert.strictEqual(spinalCase('Teletubbies say Eh-oh'), 'teletubbies-say-eh-oh', 'should return spinal case from string with spaces and hyphens');" + ] +}, +{ + "_id":"afcc8d540bea9ea2669306b6", + "name":"Repeat a string repeat a string", + "difficulty":"1", + "description":[ + "Repeat a given string (first argument) n times (second argument). Return an empty string if n is a negative number." + ], + "challengeEntryPoint":"repeat('abc', 3);", + "challengeSeed":"function repeat(str, num) {\n // repeat after me\r\n return str;\r\n}", + "tests":[ + "assert.strictEqual(repeat('*', 3), '***', 'should repeat a string n times');", + "assert.strictEqual(repeat('abc', 3), 'abcabcabc', 'should repeat a string n times');", + "assert.strictEqual(repeat('abc', -2), '', 'should return an empty string for negative numbers');" + ] +}, +{ + "_id":"cc6993d51946422351508a41", + "name":"Truncate a string", + "difficulty":"1", + "description":[ + "Truncate a string (first argument) if it is longer than the given maximum string length (second argument). Return the truncated string with a '...' ending.", + "Note that the three dots at the end add to the string length." + ], + "challengeEntryPoint":"truncate('A-tisket a-tasket A green and yellow basket', 11);", + "challengeSeed":"function truncate(str, num) {\n // Clear out that junk in your trunc\r\n return str;\r\n}", + "tests":[ + "var string = 'A-tisket a-tasket A green and yellow basket’;", + "assert.strictEqual(truncate('A-tisket a-tasket A green and yellow basket’, 24), 'A-tisket…’, ’should truncate string the given length');", + "assert.strictEqual(truncate('A-tisket a-tasket A green and yellow basket’, 'A-tisket a-tasket A green and yellow basket’.length), string, 'should not truncate if string is = length');", + "assert.strictEqual(truncate('A-tisket a-tasket A green and yellow basket’, 'A-tisket a-tasket A green and yellow basket’.length + 2), string, 'should not truncate if string is < length');" + ] } ] From 6a631c1f6d6d204ff9e0bb1f2079f939c080bd20 Mon Sep 17 00:00:00 2001 From: alicekamada Date: Mon, 9 Feb 2015 22:23:28 -0800 Subject: [PATCH 07/68] Update bonfires.json Fixed a test case for "Sum All Primes" --- seed_data/bonfires.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seed_data/bonfires.json b/seed_data/bonfires.json index 7508492dff..72a783091b 100644 --- a/seed_data/bonfires.json +++ b/seed_data/bonfires.json @@ -201,7 +201,7 @@ "challengeSeed": "function sumPrimes(num) {\n return num;\r\n}", "tests": [ "expect(sumPrimes(10)).to.be.a('number');", - "expect(sumPrimes(10)).to.equal(27);", + "expect(sumPrimes(10)).to.equal(17);", "expect(sumPrimes(977)).to.equal(73156);" ] }, From c07a75e4baf115ff52b6ae042e284f3b45aeb4a2 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Tue, 10 Feb 2015 12:46:34 -0800 Subject: [PATCH 08/68] add several more coursewares --- public/css/main.less | 1 + seed_data/coursewares.json | 168 ++++++++++++++++++++++++++++++++---- views/coursewares/show.jade | 2 +- 3 files changed, 155 insertions(+), 16 deletions(-) diff --git a/public/css/main.less b/public/css/main.less index a6ea2233ff..9d263f32aa 100644 --- a/public/css/main.less +++ b/public/css/main.less @@ -508,6 +508,7 @@ thead { border-radius: 5px; height: 200px; width: 200px; + color: #009900 } .testimonial-copy { diff --git a/seed_data/coursewares.json b/seed_data/coursewares.json index 27454518f6..937956321c 100644 --- a/seed_data/coursewares.json +++ b/seed_data/coursewares.json @@ -56,6 +56,25 @@ ], "challengeType": 0 }, + { + "_id" : "bad87fee1348bd9aeaf08801", + "name": "Add a Line Break to Visually Separate Elements", + "difficulty" : "0.021", + "description": [ + "Add a line break between the <h2> and <p> elements.", + "You can create an line break element with <br/>.", + "Note that <br/> has no closing tag. It is a self-closing element. See how a forward-slash precedes the closing bracket?" + ], + "tests": [ + "expect($('br')).to.exist;" + ], + "challengeSeed": [ + "

hello world

", + "

hello html

", + "

hello paragraph

" + ], + "challengeType": 0 + }, { "_id" : "bad87fee1348bd9aedf08802", "name": "Uncomment HTML", @@ -348,15 +367,53 @@ "name": "Use Hex Codes for Precise Colors", "difficulty" : "0.14", "description": [ - "", - "" + "Change the hex code in the \"red-text\" class to hex code for the color red.", + "Hexadecimal (hex) code is a popular way of specifying color in CSS.", + "Hex code is called \"hex\" because each digit has 16 possible values: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, and f", + "The six hex code correspond to red-red-green-green-blue-blue.", + "You can change these six values to make more than 16 million colors!", + "The higher the value in a field, the more intense its color. For example, #000000 is black, #ffffff is white, and #00ff00 is bright green. You can also get less intense colors by using values lower than f. For example, #00f000 with the second green digit set to 0 is a light green, and #00f900 is a slightly brighter green", + "Now figure out how to make the bright green in the \"red-text\" class into a bright red." ], "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" + "expect($('h2')).to.have.css('color', 'rgb(255, 0, 0)');", + "expect($('h2')).to.have.class('red-text');" ], "challengeSeed": [ - "

hello world

" + "", + "", + "

hello world

", + "

cat photo app

", + "

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

" + ], + "challengeType": 0 + }, + { + "_id" : "bad87fee1348bd9bedf08810", + "name": "Use Shortened 3 Digit Hex Codes", + "difficulty" : "0.15", + "description": [ + "Change the hex code in the \"red-text\" class to the shortened 3-digit hex code for the color red.", + "You can also shorten the 6-digit color hex code to a 3-digit code. For example, #00ff00 becomes #0f0. This is less precise, but equally effective." + ], + "tests": [ + "expect($('h2')).to.have.css('color', 'rgb(255, 0, 0)');", + "expect($('h2')).to.have.class('red-text');" + ], + "challengeSeed": [ + "", + "", + "

hello world

", + "

cat photo app

", + "

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

" ], "challengeType": 0 }, @@ -365,32 +422,113 @@ "name": "Use RGB Codes for Precise Colors", "difficulty" : "0.15", "description": [ - "", - "" + "Change the RGB code to be red.", + "Another way to represent color in CSS is with RGB, or red-green-blue notation.", + "For each of the three colors, you specify a value between 0 and 256.", + "For example, black is rgb(0, 0, 0), white is rgb(255, 255, 255), bright green is rgb(0, 255, 0). You can also get less intense colors by using values lower than 255. For example, light green is rgb(0, 123, 0).", + "If you think about it, this is just as precise as using hex code, because 16 times 16 is 256. In practice, most developers use hex code since it's faster to say out loud and to type." ], "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" + "expect($('h2')).to.have.css('color', 'rgb(255, 0, 0)');", + "expect($('h2')).to.have.class('red-text');" ], "challengeSeed": [ - "

hello world

" + "", + "", + "

hello world

", + "

cat photo app

", + "

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

" ], "challengeType": 0 }, { "_id" : "bad87fee1348bd9aedf08812", - "name": "Include images", + "name": "Add an Image to your Website", "difficulty" : "0.13", "description": [ + "", "", - "" + "Use an img element to add the image http://bit.ly/cutegraycat to the website.", + "You can add images to your website by using the img element.", + "An example of this would be <img src=\"www.your-image-source.com/your-image.jpg\"></img>.", + "Try it with this image: http://bit.ly/cutegraycat." ], "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" + "expect($('img').attr('src')).to.equal('http://bit.ly/cutegraycat');" ], "challengeSeed": [ - "

hello world

" + "

hello world

", + "

cat photo app

", + "

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

" + ], + "challengeType": 0 + }, + { + "_id" : "bad87fee1348bd9acdf08812", + "name": "Specify an Image Size", + "difficulty" : "0.13", + "description": [ + "Create a class called narrow-image and use it to resize the image so that it's only 200 pixels wide", + "Uh-oh, our image is too big to fit on a mobile phone. As a result, our user will need to scroll horizontally to view the image. But we can fix this by specifying an image size.", + "CSS has an attribute called width that controls an element's width. Just like with fonts, we'll use pixels(px) to specify the images width.", + "Create a class called narrow-image and added it to the image element. Change the width to 200 pixels." + ], + "tests": [ + "expect($('img')).to.have.class('narrow-image');", + "expect($('img')).to.have.css('width', 200px)" + + ], + "challengeSeed": [ + "", + "

hello world

", + "

cat photo app

", + "

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

", + "" + ], + "challengeType": 0 + }, + { + "_id" : "bad87fee1348bd9aedf08813", + "name": "Add Alt Text to an Image", + "difficulty" : "0.14", + "description": [ + "Add the alt text \"A picture of a gray cat\" to the image.", + "Alt text is a useful way to tell people (and web crawlers like Google) what is pictured in a photo. It's extremely important for helping blind or visually impaired people understand the content of your website.", + "You can add alt text right in the img element like this: <img src=\"www.your-image-source.com/your-image.jpg\" alt=\"your alt text\"></img>." + ], + "tests": [ + "expect((/cat/gi).test($('img').attr('alt')).to.be.true;" + ], + "challengeSeed": [ + "", + "

hello world

", + "

cat photo app

", + "

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

", + "" ], "challengeType": 0 }, diff --git a/views/coursewares/show.jade b/views/coursewares/show.jade index 8535677cd5..2756cf2923 100644 --- a/views/coursewares/show.jade +++ b/views/coursewares/show.jade @@ -25,7 +25,7 @@ block content .col-xs-12 h2.text-center= name .bonfire-instructions - p= brief + p!= brief #brief-instructions .text-center button#more-info.btn.btn-info From 4307c6659eb2c6836ea7d113938acd641f5576ae Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Tue, 10 Feb 2015 13:44:38 -0800 Subject: [PATCH 09/68] further improvements to coursewares --- seed_data/coursewares.json | 112 +++++++++++++++++++++++++++---------- 1 file changed, 83 insertions(+), 29 deletions(-) diff --git a/seed_data/coursewares.json b/seed_data/coursewares.json index 937956321c..db62d24c37 100644 --- a/seed_data/coursewares.json +++ b/seed_data/coursewares.json @@ -450,21 +450,21 @@ "name": "Add an Image to your Website", "difficulty" : "0.13", "description": [ - "", - "", - "Use an img element to add the image http://bit.ly/cutegraycat to the website.", + "Use an img element to add the image http://bit.ly/cutegraycat to your website.", "You can add images to your website by using the img element.", - "An example of this would be <img src=\"www.your-image-source.com/your-image.jpg\"></img>.", + "An example of this would be <img src=\"www.your-image-source.com/your-image.jpg\"/>. Note that in most cases, img elements are self-closing.", "Try it with this image: http://bit.ly/cutegraycat." ], "tests": [ "expect($('img').attr('src')).to.equal('http://bit.ly/cutegraycat');" ], "challengeSeed": [ + "", + "", "

hello world

", "

cat photo app

", "

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

" @@ -473,8 +473,8 @@ }, { "_id" : "bad87fee1348bd9acdf08812", - "name": "Specify an Image Size", - "difficulty" : "0.13", + "name": "Specify an Image Size TEST", + "difficulty" : "0.131", "description": [ "Create a class called narrow-image and use it to resize the image so that it's only 200 pixels wide", "Uh-oh, our image is too big to fit on a mobile phone. As a result, our user will need to scroll horizontally to view the image. But we can fix this by specifying an image size.", @@ -484,7 +484,6 @@ "tests": [ "expect($('img')).to.have.class('narrow-image');", "expect($('img')).to.have.css('width', 200px)" - ], "challengeSeed": [ "", + "

hello world

", + "

cat photo app

", + "

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

", + "" ], "challengeType": 0 }, { "_id" : "bad87fee1348bd9aedf08813", - "name": "Add Alt Text to an Image", + "name": "Add Alt Text to an Image TEST", "difficulty" : "0.14", "description": [ "Add the alt text \"A picture of a gray cat\" to the image.", "Alt text is a useful way to tell people (and web crawlers like Google) what is pictured in a photo. It's extremely important for helping blind or visually impaired people understand the content of your website.", - "You can add alt text right in the img element like this: <img src=\"www.your-image-source.com/your-image.jpg\" alt=\"your alt text\"></img>." + "You can add alt text right in the img element like this: <img src=\"www.your-image-source.com/your-image.jpg\" alt=\"your alt text\"/>." ], "tests": [ "expect((/cat/gi).test($('img').attr('alt')).to.be.true;" @@ -520,32 +547,44 @@ " .red-text {", " color: #ff0000;", " }", - "", - " .narrow-image {", - " width: 200px;", - " }", "", "

hello world

", "

cat photo app

", "

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

", - "" + "" ], "challengeType": 0 }, { - "_id" : "bad87fee1348bd9aedf08813", + "_id" : "bad87fee1348bd9bedf08813", "name": "Add a Border Around an Element", - "difficulty" : "0.14", + "difficulty" : "0.141", "description": [ - "", - "" + "Create a class called \"thick-green-border\" that puts a 5-pixel-wide black border around your cat photo.", + "CSS Borders have attributes like style, color and width.", + "We've created an example border around your h1 element. See if you can add a 5-pixel-wide green border around your cat photo." ], "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" + "expect($('img')).to.have.class('thick-black-border');", + "expect($('img')).to.have.css('border-color', 'rgb(0,255,0)'));", + "expect($('img')).to.have.css('border-width', '5px');" ], "challengeSeed": [ - "

hello world

" + "", + "

hello world

", + "

cat photo app

", + "

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

", + "" ], "challengeType": 0 }, @@ -558,11 +597,26 @@ "" ], "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" + ], "challengeSeed": [ - "

hello world

" + "", + "

hello world

", + "

cat photo app

", + "

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

", + "" ], "challengeType": 0 }, From dd0c202024d986e304afcc103cf27e3c54c4e7e4 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Tue, 10 Feb 2015 15:24:14 -0800 Subject: [PATCH 10/68] Revert "move navbar below content to improve screen reading experience" This reverts commit b8ef6f3fb245e72e7e5354888684f964b57c67b3. --- views/layout-wide.jade | 2 +- views/layout.jade | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/views/layout-wide.jade b/views/layout-wide.jade index 683ea973b2..33873b2bf2 100644 --- a/views/layout-wide.jade +++ b/views/layout-wide.jade @@ -17,9 +17,9 @@ html(ng-app='profileValidation', lang='en') != css('main') body.no-top-and-bottom-margins.full-screen-body-background + include partials/navbar-wide include partials/flash block content - include partials/navbar-wide include partials/footer != js('application') script. diff --git a/views/layout.jade b/views/layout.jade index ddce7f6011..6e5cadeefd 100644 --- a/views/layout.jade +++ b/views/layout.jade @@ -15,10 +15,10 @@ html(ng-app='profileValidation', lang='en') != css('main') body.top-and-bottom-margins + include partials/navbar-narrow .container include partials/flash block content - include partials/navbar-narrow include partials/footer != js('application') script. From 5f4fe74b16ff85a0ac91d1acf179422f7bd4e2be Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Tue, 10 Feb 2015 16:26:59 -0800 Subject: [PATCH 11/68] attempt to make footer more accessible --- public/css/main.less | 5 ++++ seed_data/coursewares.json | 27 ++++++++++++++++++++ views/partials/footer.jade | 52 +++++++++++++++++++++++++------------- 3 files changed, 67 insertions(+), 17 deletions(-) diff --git a/public/css/main.less b/public/css/main.less index 9d263f32aa..50058c04f5 100644 --- a/public/css/main.less +++ b/public/css/main.less @@ -685,6 +685,11 @@ iframe.iphone { min-height: 650px; } +// This is used to give icons text for screen readers to read out, without needing the text to actually appear. +.icon-lock{ + font-size: 0px; +} + //uncomment this to see the dimensions of all elements outlined in red //* { diff --git a/seed_data/coursewares.json b/seed_data/coursewares.json index db62d24c37..3c00dce820 100644 --- a/seed_data/coursewares.json +++ b/seed_data/coursewares.json @@ -530,6 +530,33 @@ ], "challengeType": 0 }, + { + "_id" : "bad87fee1348bd8acde08812", + "name": "Center Text with Bootstrap", + "difficulty" : "0.133", + "description": [ + "Add Bootstrap's text-center class to your h1 and h2 elements.", + "Now that we're using Bootstrap, we can center our heading elements (h1 and h2) to make them look better. All we need to do is add the class text-center to the h1 and h2 elements.", + "Note that you can add several classes to the same element by seperating each of them with a space, like this: <h2 class=\"text-red text-center\">your text</h2>." + ], + "tests": [ + "expect($('h1')).to.have.class('text-center');", + "expect($('h2')).to.have.class('text-center');" + ], + "challengeSeed": [ + "", + "

hello world

", + "

cat photo app

", + "

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

", + "" + ], + "challengeType": 0 + }, { "_id" : "bad87fee1348bd9aedf08813", "name": "Add Alt Text to an Image TEST", diff --git a/views/partials/footer.jade b/views/partials/footer.jade index 7eab9a6f40..0b76142449 100644 --- a/views/partials/footer.jade +++ b/views/partials/footer.jade @@ -1,19 +1,37 @@ .fcc-footer .col-xs-12 - a.ion-speakerphone(title="Free Code Camp's Blog", href='http://blog.freecodecamp.com', target='_blank') - |   - a.ion-social-twitch-outline(title="Free Code Camp Live Pair Programming on Twitch.TV", href="http://www.twitch.tv/freecodecamp", target='_blank') - |   - a.ion-social-github(title="Free Code Camp on GitHub", href="http://github.com/freecodecamp", target='_blank') - |   - a.ion-social-twitter(title="Free Code Camp on Twitter", href="http://twitter.com/freecodecamp", target='_blank') - |   - a.ion-social-facebook(title="Free Code Camp on Facebook", href="http://facebook.com/freecodecamp", target='_blank') - |   - a.ion-social-linkedin(title="Free Code Camp on LinkedIn", href="http://linkedin.com/company/4831032?free-code-camp", target='_blank') - |   - a.ion-information-circled(title="About Free Code Camp", href="/learn-to-code") - |   - a.ion-locked(title="Free Code Camp's Privacy Policy", href="/privacy") - |   - a.ion-code-working(title="Bonfire Coding Playground", href="/playground") \ No newline at end of file + span + a.ion-speakerphone(title="Free Code Camp's Blog", href='http://blog.freecodecamp.com', target='_blank') + span.icon-lock Free Code Camp's Blog + |   + span + a.ion-social-twitch-outline(title="Free Code Camp Live Pair Programming on Twitch.TV", href="http://www.twitch.tv/freecodecamp", target='_blank') + span.icon-lock Free Code Camp Live Pair Programming on Twitch.TV + |   + span + a.ion-social-github(title="Free Code Camp on GitHub", href="http://github.com/freecodecamp", target='_blank') + span.icon-lock Free Code Camp on GitHub + |   + span + a.ion-social-twitter(title="Free Code Camp on Twitter", href="http://twitter.com/freecodecamp", target='_blank') + span.icon-lock Free Code Camp on Twitter + |   + span + a.ion-social-facebook(title="Free Code Camp on Facebook", href="http://facebook.com/freecodecamp", target='_blank') + span.icon-lock Free Code Camp on Facebook + |   + span + a.ion-social-linkedin(title="Free Code Camp on LinkedIn", href="http://linkedin.com/company/4831032?free-code-camp", target='_blank') + span.icon-lock Free Code Camp on LinkedIn + |   + span + a.ion-information-circled(title="About Free Code Camp", href="/learn-to-code") + span.icon-lock About Free Code Camp + |   + span + a.ion-locked(title="Free Code Camp's Privacy Policy", href="/privacy") + span.icon-lock Free Code Camp's Privacy Policy + |   + span + a.ion-code-working(title="Code Editor Playground", href="/playground") + span.icon-lock Code Editor Playground \ No newline at end of file From 44c5761f6ac62cb38808d875b64044d6343151c2 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Tue, 10 Feb 2015 19:12:51 -0800 Subject: [PATCH 12/68] do more work on organizing and adding coursewares --- seed_data/coursewares.json | 794 +++++++++++++++++++++++-------------- 1 file changed, 504 insertions(+), 290 deletions(-) diff --git a/seed_data/coursewares.json b/seed_data/coursewares.json index 3c00dce820..e8a1487ade 100644 --- a/seed_data/coursewares.json +++ b/seed_data/coursewares.json @@ -19,6 +19,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf0887a", "name": "Use the h2 Element", @@ -38,6 +39,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08801", "name": "Use the P Element", @@ -56,10 +58,11 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aeaf08801", "name": "Add a Line Break to Visually Separate Elements", - "difficulty" : "0.021", + "difficulty" : "0.03", "description": [ "Add a line break between the <h2> and <p> elements.", "You can create an line break element with <br/>.", @@ -75,10 +78,11 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08802", "name": "Uncomment HTML", - "difficulty" : "0.03", + "difficulty" : "0.04", "description": [ "Uncomment the h1, h2 and p elements.", "Commenting is a way that you can leave comments within your code without affecting the code itself.", @@ -98,10 +102,11 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08804", "name": "Comment out HTML", - "difficulty" : "0.04", + "difficulty" : "0.05", "description": [ "Comment out the h1 element and the p element, but leave the h2 element uncommented.", "Remember that in order to start a comment, you need to use <!-- and to end a comment, you need to use -->.", @@ -122,10 +127,11 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08833", "name": "Use Lorem Ipsum Text as a Placeholder", - "difficulty" : "0.05", + "difficulty" : "0.06", "description": [ "Change the text in the p element to use the first few words of lorem ipsum text.", "Designers use lorem ipsum as placeholder text. It's called lorem ipsum text because it's those are the first two words of a passage by Cicero of Ancient Rome.", @@ -142,10 +148,11 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08803", "name": "Change the Color of Text", - "difficulty" : "0.06", + "difficulty" : "0.07", "description": [ "Change the h2 element's style so that its text color is red.", "We can do this by changing the style of the h2 element.", @@ -162,10 +169,11 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08805", "name": "Create a Style Tag for CSS", - "difficulty" : "0.07", + "difficulty" : "0.08", "description": [ "Create a style tag and write the CSS to make all h2 elements blue.", "With CSS, there are hundreds of CSS attributes that you can use to change the way an element looks on a web page.", @@ -185,10 +193,11 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aecf08806", "name": "Use a CSS Class to Style an Element", - "difficulty" : "0.08", + "difficulty" : "0.09", "description": [ "Create a CSS class called \"red-text\" and apply it to the h2 element.", "Classes are reusable styles that can be added to HTML elements.", @@ -211,10 +220,11 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aeff08806", "name": "Use a CSS Classes to Style Multiple Elements", - "difficulty" : "0.09", + "difficulty" : "0.10", "description": [ "Apply the \"red-text\" class to the h1, h2 and p elements.", "Remember that you can attach classes to HTML elements by using the class=\"class\" within the relevant element's opening tag." @@ -239,10 +249,11 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08806", "name": "Change the Font Size of an Element", - "difficulty" : "0.10", + "difficulty" : "0.11", "description": [ "Set the font size of all p elements to 16 pixels", "Font size is controlled by the font-size CSS attribute.", @@ -265,10 +276,11 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08807", "name": "Import a Google Font", - "difficulty" : "0.11", + "difficulty" : "0.12", "description": [ "Apply the font-family of Lobster to all h1 elements.", "The first line of code in your text editor is a call to Google that grabs a font called Lobster and loads it into your HTML.", @@ -296,10 +308,11 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08808", "name": "Specify How Fonts Should Degrade", - "difficulty" : "0.12", + "difficulty" : "0.13", "description": [ "Make all h2 elements use Lobster as their font family, but degrade to the Serif font when the Lobster font isn't available.", "We commented out our call to Google Fonts, and now our lobter isn't available.", @@ -324,10 +337,11 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08809", "name": "Using Important to Override Styles", - "difficulty" : "0.13", + "difficulty" : "0.14", "description": [ "Apply both the \"blue-text\" and \"urgently-red\" classes to all h2 elements, but use !important to ensure the element is rendered as being red.", "Sometimes HTML elements will receive conflicting information from CSS classes as to how they should be styled.", @@ -362,10 +376,11 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08810", "name": "Use Hex Codes for Precise Colors", - "difficulty" : "0.14", + "difficulty" : "0.15", "description": [ "Change the hex code in the \"red-text\" class to hex code for the color red.", "Hexadecimal (hex) code is a popular way of specifying color in CSS.", @@ -392,10 +407,11 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9bedf08810", "name": "Use Shortened 3 Digit Hex Codes", - "difficulty" : "0.15", + "difficulty" : "0.16", "description": [ "Change the hex code in the \"red-text\" class to the shortened 3-digit hex code for the color red.", "You can also shorten the 6-digit color hex code to a 3-digit code. For example, #00ff00 becomes #0f0. This is less precise, but equally effective." @@ -417,10 +433,11 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08811", "name": "Use RGB Codes for Precise Colors", - "difficulty" : "0.15", + "difficulty" : "0.17", "description": [ "Change the RGB code to be red.", "Another way to represent color in CSS is with RGB, or red-green-blue notation.", @@ -445,10 +462,11 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08812", "name": "Add an Image to your Website", - "difficulty" : "0.13", + "difficulty" : "0.18", "description": [ "Use an img element to add the image http://bit.ly/cutegraycat to your website.", "You can add images to your website by using the img element.", @@ -471,10 +489,11 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9acdf08812", "name": "Specify an Image Size TEST", - "difficulty" : "0.131", + "difficulty" : "0.19", "description": [ "Create a class called narrow-image and use it to resize the image so that it's only 200 pixels wide", "Uh-oh, our image is too big to fit on a mobile phone. As a result, our user will need to scroll horizontally to view the image. But we can fix this by specifying an image size.", @@ -502,10 +521,373 @@ ], "challengeType": 0 }, + + { + "_id" : "bad87fee1348bd9bedf08813", + "name": "Add a Border Around an Element", + "difficulty" : "0.20", + "description": [ + "Create a class called \"thick-green-border\" that puts a 5-pixel-wide black border around your cat photo.", + "CSS Borders have attributes like style, color and width.", + "We've created an example border around your h1 element. See if you can add a 10-pixel-wide green border around your cat photo." + ], + "tests": [ + "expect($('img')).to.have.class('thick-green-border');", + "expect($('img')).to.have.css('border-color', 'rgb(0,255,0)'));", + "expect($('img')).to.have.css('border-width', '10px');" + ], + "challengeSeed": [ + "", + "

hello world

", + "

cat photo app

", + "

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

", + "" + ], + "challengeType": 0 + }, + + { + "_id" : "bad87fee1348bd9aedf08814", + "name": "Add Rounded Corners with a Border Radius", + "difficulty" : "0.21", + "description": [ + "Give your cat photo a border radius of 10 pixels.", + "Your cat photo currently has sharp corners. We can round out those corners with a CSS attribute called border-radius.", + "You can specify a border-radius with pixels. This will affect how rounded the corners are. Add this attribute to your thick-green-border class and set it to 10 pixels." + ], + "tests": [ + "expect($('img')).to.have.class('thick-green-border');", + "expect($('img')).to.have.css('border-radius', '10px');" + ], + "challengeSeed": [ + "", + "

hello world

", + "

cat photo app

", + "

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

", + "" + ], + "challengeType": 0 + }, + + { + "_id" : "bad87fee1348bd9aedf08815", + "name": "Make an Image Circular with a Border Radius", + "difficulty" : "0.22", + "description": [ + "Give your cat photo a border-radius of 50%.", + "In addition to pixels, you can also specify a border-radius of a percentage." + ], + "tests": [ + "expect($('img')).to.have.css('border-radius', '50%');" + ], + "challengeSeed": [ + "", + "

hello world

", + "

cat photo app

", + "

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

", + "" + ], + "challengeType": 0 + }, + + { + "_id" : "bad87fee1348bd9aedf08816", + "name": "Use an Anchor Tag to Link to an External Page", + "difficulty" : "0.23", + "description": [ + "Create an anchor tag hyperlink that links to freecodecamp.com", + "" + ], + "tests": [ + "expect((/free(\\s+)?code(\\s+)?camp(\\s+)?/gi).test($('a').text())).to.be.true;", + "expect((/free(\\s+)?code(\\s+)?camp(\\s+)?/gi).test($('a').attr('href').text())).to.be.true;" + ], + "challengeSeed": [ + "", + "

hello world

", + "

cat photo app

", + "

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

", + "", + "This is a link to Google", + "
" + ], + "challengeType": 0 + }, + + { + "_id" : "bad87fee1348bd9aedf08817", + "name": "Make Dead Links with the Hash Symbol", + "difficulty" : "0.24", + "description": [ + "", + "" + ], + "tests": [ + "expect($('h1')).to.have.class('text-center');", + "expect($('h1')).to.have.text('hello world');" + ], + "challengeSeed": [ + "", + "

hello world

", + "

cat photo app

", + "

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

", + "" + ], + "challengeType": 0 + }, + + { + "_id" : "bad87fee1348bd9aedf08818", + "name": "Add Alt Text to a Link", + "difficulty" : "0.25", + "description": [ + "", + "" + ], + "tests": [ + "expect($('h1')).to.have.class('text-center');", + "expect($('h1')).to.have.text('hello world');" + ], + "challengeSeed": [ + "

hello world

" + ], + "challengeType": 0 + }, + + { + "_id" : "bad87fee1348bd9aedf08819", + "name": "Include Links that Open in a New Browser Tab", + "difficulty" : "0.26", + "description": [ + "", + "" + ], + "tests": [ + "expect($('h1')).to.have.class('text-center');", + "expect($('h1')).to.have.text('hello world');" + ], + "challengeSeed": [ + "

hello world

" + ], + "challengeType": 0 + }, + + { + "_id" : "bad87fee1348bd9aedf08820", + "name": "Turn Images into Links", + "difficulty" : "0.27", + "description": [ + "", + "" + ], + "tests": [ + "expect($('h1')).to.have.class('text-center');", + "expect($('h1')).to.have.text('hello world');" + ], + "challengeSeed": [ + "

hello world

" + ], + "challengeType": 0 + }, + + { + "_id" : "bad88fee1348bd9aedf08825", + "name": "Set the Background Color of an Element", + "difficulty" : "0.28", + "description": [ + "", + "" + ], + "tests": [ + "expect($('h1')).to.have.class('text-center');", + "expect($('h1')).to.have.text('hello world');" + ], + "challengeSeed": [ + "

hello world

" + ], + "challengeType": 0 + }, + + { + "_id" : "bad87fee1348bd9aedf08821", + "name": "Add Padding to an Element", + "difficulty" : "0.29", + "description": [ + "", + "" + ], + "tests": [ + "expect($('h1')).to.have.class('text-center');", + "expect($('h1')).to.have.text('hello world');" + ], + "challengeSeed": [ + "

hello world

" + ], + "challengeType": 0 + }, + + { + "_id" : "bad87fee1348bd9aedf08822", + "name": "Add a Margin to an Element", + "difficulty" : "0.30", + "description": [ + "", + "" + ], + "tests": [ + "expect($('h1')).to.have.class('text-center');", + "expect($('h1')).to.have.text('hello world');" + ], + "challengeSeed": [ + "

hello world

" + ], + "challengeType": 0 + }, + + { + "_id" : "bad87fee1348bd9aedf08823", + "name": "Add a Negative Margin to an Element", + "difficulty" : "0.31", + "description": [ + "", + "" + ], + "tests": [ + "expect($('h1')).to.have.class('text-center');", + "expect($('h1')).to.have.text('hello world');" + ], + "challengeSeed": [ + "

hello world

" + ], + "challengeType": 0 + }, + + { + "_id" : "bad87fee1348bd9aedf08824", + "name": "Add Padding Only to the Top and Bottom of an Element", + "difficulty" : "0.32", + "description": [ + "", + "" + ], + "tests": [ + "expect($('h1')).to.have.class('text-center');", + "expect($('h1')).to.have.text('hello world');" + ], + "challengeSeed": [ + "

hello world

" + ], + "challengeType": 0 + }, + + { + "_id" : "bad87fee1348bd9aedf08825", + "name": "Add Margin Only to the Left and Right of an Element", + "difficulty" : "0.33", + "description": [ + "", + "" + ], + "tests": [ + "expect($('h1')).to.have.class('text-center');", + "expect($('h1')).to.have.text('hello world');" + ], + "challengeSeed": [ + "

hello world

" + ], + "challengeType": 0 + }, + + { + "_id" : "bad87fee1348bd9aedf08826", + "name": "Use Clockwise Padding Notation", + "difficulty" : "0.34", + "description": [ + "", + "" + ], + "tests": [ + "expect($('h1')).to.have.class('text-center');", + "expect($('h1')).to.have.text('hello world');" + ], + "challengeSeed": [ + "

hello world

" + ], + "challengeType": 0 + }, + { "_id" : "bad87fee1348bd9acde08812", "name": "Use Bootstrap for Responsive Images", - "difficulty" : "0.132", + "difficulty" : "0.35", "description": [ "Add the img-responsive Bootstrap class to the image.", "Specifying a width of 200 pixels on our img element made it fit our phone's screen, but it's not a perfect fit. It would be great if the image could be exactly the width of our phone's screen.", @@ -521,7 +903,6 @@ " .red-text {", " color: #ff0000;", " }", - "", "", "

hello world

", "

cat photo app

", @@ -530,10 +911,11 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd8acde08812", "name": "Center Text with Bootstrap", - "difficulty" : "0.133", + "difficulty" : "0.36", "description": [ "Add Bootstrap's text-center class to your h1 and h2 elements.", "Now that we're using Bootstrap, we can center our heading elements (h1 and h2) to make them look better. All we need to do is add the class text-center to the h1 and h2 elements.", @@ -557,10 +939,39 @@ ], "challengeType": 0 }, + + { + "_id" : "bad87fee1348cd8acde08812", + "name": "Create a Button", + "difficulty" : "0.37", + "description": [ + "Create a bootstrap button with the class .", + "Now that we're using Bootstrap, we can center our heading elements (h1 and h2) to make them look better. All we need to do is add the class text-center to the h1 and h2 elements.", + "Note that you can add several classes to the same element by seperating each of them with a space, like this: <h2 class=\"text-red text-center\">your text</h2>." + ], + "tests": [ + "expect($('h1')).to.have.class('text-center');", + "expect($('h2')).to.have.class('text-center');" + ], + "challengeSeed": [ + "", + "

hello world

", + "

cat photo app

", + "

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

", + "" + ], + "challengeType": 0 + }, + { "_id" : "bad87fee1348bd9aedf08813", "name": "Add Alt Text to an Image TEST", - "difficulty" : "0.14", + "difficulty" : "0.38", "description": [ "Add the alt text \"A picture of a gray cat\" to the image.", "Alt text is a useful way to tell people (and web crawlers like Google) what is pictured in a photo. It's extremely important for helping blind or visually impaired people understand the content of your website.", @@ -582,279 +993,11 @@ ], "challengeType": 0 }, - { - "_id" : "bad87fee1348bd9bedf08813", - "name": "Add a Border Around an Element", - "difficulty" : "0.141", - "description": [ - "Create a class called \"thick-green-border\" that puts a 5-pixel-wide black border around your cat photo.", - "CSS Borders have attributes like style, color and width.", - "We've created an example border around your h1 element. See if you can add a 5-pixel-wide green border around your cat photo." - ], - "tests": [ - "expect($('img')).to.have.class('thick-black-border');", - "expect($('img')).to.have.css('border-color', 'rgb(0,255,0)'));", - "expect($('img')).to.have.css('border-width', '5px');" - ], - "challengeSeed": [ - "", - "

hello world

", - "

cat photo app

", - "

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

", - "" - ], - "challengeType": 0 - }, - { - "_id" : "bad87fee1348bd9aedf08814", - "name": "Add Rounded Corners with a Border Radius", - "difficulty" : "0.15", - "description": [ - "", - "" - ], - "tests": [ - ], - "challengeSeed": [ - "", - "

hello world

", - "

cat photo app

", - "

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

", - "" - ], - "challengeType": 0 - }, - { - "_id" : "bad87fee1348bd9aedf08815", - "name": "Make an Image Circular with a Border Radius", - "difficulty" : "0.16", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - { - "_id" : "bad87fee1348bd9aedf08816", - "name": "Create a Link", - "difficulty" : "0.17", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - { - "_id" : "bad87fee1348bd9aedf08817", - "name": "Make Dead Links with the Hash Symbol", - "difficulty" : "0.18", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - { - "_id" : "bad87fee1348bd9aedf08818", - "name": "Add Alt Text to a Link", - "difficulty" : "0.19", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - { - "_id" : "bad87fee1348bd9aedf08819", - "name": "Include Links that Open in a New Browser Tab", - "difficulty" : "0.20", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - { - "_id" : "bad87fee1348bd9aedf08820", - "name": "Turn Images into Links", - "difficulty" : "0.21", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - { - "_id" : "bad87fee1348bd9aedf08821", - "name": "Add Padding to an Element", - "difficulty" : "0.22", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - { - "_id" : "bad87fee1348bd9aedf08822", - "name": "Add a Margin to an Element", - "difficulty" : "0.23", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - { - "_id" : "bad87fee1348bd9aedf08823", - "name": "Add a Negative Margin to an Element", - "difficulty" : "0.24", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - { - "_id" : "bad87fee1348bd9aedf08824", - "name": "Add Padding Only to the Top and Bottom of an Element", - "difficulty" : "0.25", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - { - "_id" : "bad87fee1348bd9aedf08825", - "name": "Add Margin Only to the Left and Right of an Element", - "difficulty" : "0.26", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - { - "_id" : "bad87fee1348bd9aedf08826", - "name": "Use Clockwise Padding Notation", - "difficulty" : "0.27", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, { "_id" : "bad87fee1348bd9aedf08827", "name": "Create an Bulleted Unordered List", - "difficulty" : "0.28", + "difficulty" : "0.39", "description": [ "", "" @@ -868,6 +1011,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08828", "name": "Created a Numbered Ordered List", @@ -885,6 +1029,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08829", "name": "Create a Text Field", @@ -902,6 +1047,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08830", "name": "Use HTML5 to Make a Field Required", @@ -919,6 +1065,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08831", "name": "Use HTML5 to Specify an Input Type", @@ -936,6 +1083,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08832", "name": "Create a Text Area", @@ -953,6 +1101,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08834", "name": "Create a Set of Radio Buttons", @@ -970,6 +1119,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08835", "name": "Create a Set of Checkboxes", @@ -987,6 +1137,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08836", "name": "Create a HTML Form", @@ -1004,6 +1155,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08837", "name": "Use a Bootstrap Primary Button", @@ -1021,6 +1173,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08838", "name": "Apply Responsive Design with the Bootstrap Grid", @@ -1038,6 +1191,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08839", "name": "Create a Half Width Bootstrap Column", @@ -1055,6 +1209,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08840", "name": "Create a Row of Bootstrap Elements", @@ -1072,6 +1227,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08841", "name": "Change the background of element", @@ -1089,6 +1245,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08842", "name": "Make an element translucent", @@ -1106,6 +1263,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08843", "name": "Center an Image", @@ -1123,6 +1281,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08844", "name": "Add a Drop Shadow", @@ -1140,6 +1299,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08845", "name": "Make a Navbar", @@ -1157,6 +1317,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08847", "name": "Add a Logo to a Navbar", @@ -1174,6 +1335,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08848", "name": "Make a Footer", @@ -1191,6 +1353,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08849", "name": "Use Icons as Links", @@ -1208,6 +1371,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08850", "name": "Add Hover Effects to Icons", @@ -1225,6 +1389,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08851", "name": "Add Depth to a Page with a Well", @@ -1242,6 +1407,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08852", "name": "Add an ID to a Button", @@ -1259,6 +1425,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08853", "name": "Fire a Modal by Clicking a Button", @@ -1276,6 +1443,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08854", "name": "Style a Modal with a Header", @@ -1293,6 +1461,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08855", "name": "Style a Modal with a Body", @@ -1310,6 +1479,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08856", "name": "Make a Modal Dismissable", @@ -1327,6 +1497,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08857", "name": "Create an Accordian Menu", @@ -1344,6 +1515,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08858", "name": "Add a Bootstrap Info Button", @@ -1361,6 +1533,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08859", "name": "Add a Bootstrap Warning Button", @@ -1378,6 +1551,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08860", "name": "Add a Bootstrap Danger Button", @@ -1395,6 +1569,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08861", "name": "Add a Bootstrap Success Button", @@ -1412,6 +1587,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08862", "name": "Use a Block-width Button", @@ -1429,6 +1605,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08863", "name": "Add a Gradient to a Button", @@ -1446,6 +1623,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08864", "name": "Adjust the Line Height of Text", @@ -1463,6 +1641,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08865", "name": "Use Responsive Images to Fit Containing Elements", @@ -1480,6 +1659,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08866", "name": "", @@ -1497,6 +1677,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08867", "name": "", @@ -1514,6 +1695,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08868", "name": "", @@ -1531,6 +1713,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08869", "name": "", @@ -1548,6 +1731,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08870", "name": "", @@ -1565,6 +1749,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08871", "name": "", @@ -1582,6 +1767,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08872", "name": "", @@ -1599,6 +1785,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08873", "name": "", @@ -1616,6 +1803,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08874", "name": "", @@ -1633,6 +1821,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08875", "name": "", @@ -1650,6 +1839,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08876", "name": "", @@ -1667,6 +1857,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08877", "name": "", @@ -1684,6 +1875,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08878", "name": "", @@ -1701,6 +1893,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08879", "name": "", @@ -1718,6 +1911,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08880", "name": "", @@ -1735,6 +1929,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08881", "name": "", @@ -1752,6 +1947,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08882", "name": "", @@ -1769,6 +1965,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08883", "name": "", @@ -1786,6 +1983,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08884", "name": "", @@ -1803,6 +2001,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08885", "name": "", @@ -1820,6 +2019,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08886", "name": "", @@ -1837,6 +2037,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08887", "name": "", @@ -1854,6 +2055,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08888", "name": "", @@ -1871,6 +2073,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08889", "name": "", @@ -1888,6 +2091,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08890", "name": "", @@ -1905,6 +2109,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08891", "name": "", @@ -1922,6 +2127,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08892", "name": "", @@ -1939,6 +2145,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08893", "name": "", @@ -1956,6 +2163,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08894", "name": "", @@ -1973,6 +2181,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08895", "name": "", @@ -1990,6 +2199,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08896", "name": "", @@ -2007,6 +2217,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08897", "name": "", @@ -2024,6 +2235,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08898", "name": "", @@ -2041,6 +2253,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08899", "name": "", @@ -2058,6 +2271,7 @@ ], "challengeType": 0 }, + { "_id" : "bad87fee1348bd9aedf08100", "name": "", From 2308ce1eeba77ca77b2934bf0da7eeedd839de54 Mon Sep 17 00:00:00 2001 From: Steve Phillips Date: Tue, 10 Feb 2015 22:19:05 -0800 Subject: [PATCH 13/68] Check for Palindromes: Removed redundancy from description --- seed_data/bonfires.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/seed_data/bonfires.json b/seed_data/bonfires.json index 72a783091b..7a0d6abde7 100644 --- a/seed_data/bonfires.json +++ b/seed_data/bonfires.json @@ -58,11 +58,10 @@ "name": "Check for Palindromes", "difficulty": "1.03", "description": [ - "Return 'true' if a given string is a palindrome.", + "Return true if the given string is a palindrome. Otherwise, return false." "A palindrome is a word or sentence that's spelled the same way both forward and backward, ignoring punctuation, case, and spacing.", "You'll need to remove punctuation and turn everything lower case in order to check for palindromes.", "We'll pass strings with varying formats, such as \"racecar\", \"RaceCar\", and \"race CAR\" among others.", - "Return true if the string is a palindrome. Otherwise, return false." ], "tests": [ "expect(palindrome(\"eye\")).to.be.a(\"boolean\");", From a1507a969b99d08460f3f3b687ed3e9025c4118b Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Tue, 10 Feb 2015 22:22:40 -0800 Subject: [PATCH 14/68] Add should and assert to coursewares and write code to test multiple instances of an element for a condition --- public/js/lib/coursewares/coursewaresFramework_v0.1.0.js | 3 ++- seed_data/coursewares.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/public/js/lib/coursewares/coursewaresFramework_v0.1.0.js b/public/js/lib/coursewares/coursewaresFramework_v0.1.0.js index 8d39c02f79..a2877aa51c 100644 --- a/public/js/lib/coursewares/coursewaresFramework_v0.1.0.js +++ b/public/js/lib/coursewares/coursewaresFramework_v0.1.0.js @@ -40,7 +40,8 @@ var libraryIncludes = ""; var allTests = ''; (function() { diff --git a/seed_data/coursewares.json b/seed_data/coursewares.json index e8a1487ade..b242fa98aa 100644 --- a/seed_data/coursewares.json +++ b/seed_data/coursewares.json @@ -646,7 +646,7 @@ ], "tests": [ "expect((/free(\\s+)?code(\\s+)?camp(\\s+)?/gi).test($('a').text())).to.be.true;", - "expect((/free(\\s+)?code(\\s+)?camp(\\s+)?/gi).test($('a').attr('href').text())).to.be.true;" + "expect($('a').filter(function(index) { return /freecodecamp\\.com/gi.test($('a')[index]); }).length).to.eql(1);" ], "challengeSeed": [ "", - "

hello world

", - "

cat photo app

", + "

cat photo app

", "

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

", "" ], @@ -661,10 +660,10 @@ " border-radius: 50%;", " }", "", - "

hello world

", "

cat photo app

", "

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

", "", + "
", "This is a link to Google", "
" ], @@ -673,15 +672,17 @@ { "_id" : "bad87fee1348bd9aedf08817", - "name": "Make Dead Links with the Hash Symbol", + "name": "Make Named Anchors using the Hash Symbol", "difficulty" : "0.24", "description": [ - "", - "" + "Use the hash symbol(#) to turn the link to the bottom of the page into a named anchor.", + "Sometimes you want to add anchor elements to your website before you know where they will link.", + "This is also handy when you're changing the behavior of a link using jQuery, which we'll learn about later.", + "Replace the href in the link to freecodecamp.com with a hash symbol to turn it into a named anchor." ], "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" + "expect((/this link leads nowhere/gi).test($('a').text())).to.be.true;", + "expect($('a').filter(function(index) { return /#/gi.test($('a')[index]); }).length).to.eql(1);" ], "challengeSeed": [ "", - "

hello world

", "

cat photo app

", "

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

", + "", + "
", + "This named anchor leads nowhere", + "
" + ], + "challengeType": 0 + }, + + { + "_id" : "bad87fee1348bd9aedf08820", + "name": "Turn an Image into a Link", + "difficulty" : "0.27", + "description": [ + "Wrap the gray cat's image with an anchor tag that leads nowhere.", + "You can make elements into links by wrapping them in an anchor tag.", + "Check out the example snow-colored cat's photo. When you hover over it with your cursor, you'll see the finger pointer you usually see when you hover over a link. The photo is now a link.", + "Wrap your gray cat's photo in an anchor tag", + "Use the hash symbol as the anchor tag's href." + ], + "tests": [ + "expect($('a').filter(function(index) { return /#/gi.test($('a')[index]); }).length).to.eql(2);" + ], + "challengeSeed": [ + "", + "

cat photo app

", + "", "" ], "challengeType": 0 @@ -706,54 +743,31 @@ { "_id" : "bad87fee1348bd9aedf08818", - "name": "Add Alt Text to a Link", + "name": "Add Alt Text to an image", "difficulty" : "0.25", "description": [ - "", + "Add the alt text \"a photo of a cute gray cat\" to our cat photo", "" ], "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" + "expect($('img').filter(function(){ return /cat/gi.test(this.alt) }).length).to.eql(2);" ], "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - - { - "_id" : "bad87fee1348bd9aedf08819", - "name": "Include Links that Open in a New Browser Tab", - "difficulty" : "0.26", - "description": [ + "", + "

cat photo app

", + "\"a", + "" ], "challengeType": 0 }, From da4deb77ff6176b8b45f1976bf1aee80c9722973 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Wed, 11 Feb 2015 17:13:00 -0800 Subject: [PATCH 19/68] create box model and working test for padding and margin training --- seed_data/coursewares.json | 54 +++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/seed_data/coursewares.json b/seed_data/coursewares.json index 93bd74a5d3..e6970aa28b 100644 --- a/seed_data/coursewares.json +++ b/seed_data/coursewares.json @@ -710,7 +710,7 @@ { "_id" : "bad87fee1348bd9aedf08820", "name": "Turn an Image into a Link", - "difficulty" : "0.27", + "difficulty" : "0.271", "description": [ "Wrap the gray cat's image with an anchor tag that leads nowhere.", "You can make elements into links by wrapping them in an anchor tag.", @@ -746,8 +746,10 @@ "name": "Add Alt Text to an image", "difficulty" : "0.25", "description": [ - "Add the alt text \"a photo of a cute gray cat\" to our cat photo", - "" + "Add the alt text \"a photo of a cute gray cat\" to our cat photo", + "alt text is what browsers will display if they fail to load the image. alt text is also important for blind or visually impaired users to understand what an image portrays. Search engines also look at alt text.", + "In short, every image should have alt text!", + "You can add alt text right in the image tag, like we've done here with the \"cute white cat\" image." ], "tests": [ "expect($('img').filter(function(){ return /cat/gi.test(this.alt) }).length).to.eql(2);" @@ -774,18 +776,52 @@ { "_id" : "bad88fee1348bd9aedf08825", - "name": "Set the Background Color of an Element", + "name": "Adjusting the Padding of an Element", "difficulty" : "0.28", "description": [ - "", - "" + "Change the padding of the yellow box to 20 pixels.", + "An element's padding controls the amount of space between an element and its border.", + "Here, we can see that the green box and the red box and the green box are nested within the blue box.", + "When you increase the green box's padding, it will increase the distance between the word \"padding\" and the border around the text." ], "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" + "expect($('.green-box')).to.have.css('padding', '20px')" ], "challengeSeed": [ - "

hello world

" + "", + "
margin
", + "", + "
", + "
padding
", + "
padding
", + "
" ], "challengeType": 0 }, From 23a0c33c81969ceb760bf13747fc7a0cbae84076 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Wed, 11 Feb 2015 22:31:57 -0800 Subject: [PATCH 20/68] add screen reader only copy --- views/partials/footer.jade | 53 +++++++++++++------------------------- 1 file changed, 18 insertions(+), 35 deletions(-) diff --git a/views/partials/footer.jade b/views/partials/footer.jade index 0b76142449..d1cc9f6d17 100644 --- a/views/partials/footer.jade +++ b/views/partials/footer.jade @@ -1,37 +1,20 @@ .fcc-footer .col-xs-12 - span - a.ion-speakerphone(title="Free Code Camp's Blog", href='http://blog.freecodecamp.com', target='_blank') - span.icon-lock Free Code Camp's Blog - |   - span - a.ion-social-twitch-outline(title="Free Code Camp Live Pair Programming on Twitch.TV", href="http://www.twitch.tv/freecodecamp", target='_blank') - span.icon-lock Free Code Camp Live Pair Programming on Twitch.TV - |   - span - a.ion-social-github(title="Free Code Camp on GitHub", href="http://github.com/freecodecamp", target='_blank') - span.icon-lock Free Code Camp on GitHub - |   - span - a.ion-social-twitter(title="Free Code Camp on Twitter", href="http://twitter.com/freecodecamp", target='_blank') - span.icon-lock Free Code Camp on Twitter - |   - span - a.ion-social-facebook(title="Free Code Camp on Facebook", href="http://facebook.com/freecodecamp", target='_blank') - span.icon-lock Free Code Camp on Facebook - |   - span - a.ion-social-linkedin(title="Free Code Camp on LinkedIn", href="http://linkedin.com/company/4831032?free-code-camp", target='_blank') - span.icon-lock Free Code Camp on LinkedIn - |   - span - a.ion-information-circled(title="About Free Code Camp", href="/learn-to-code") - span.icon-lock About Free Code Camp - |   - span - a.ion-locked(title="Free Code Camp's Privacy Policy", href="/privacy") - span.icon-lock Free Code Camp's Privacy Policy - |   - span - a.ion-code-working(title="Code Editor Playground", href="/playground") - span.icon-lock Code Editor Playground \ No newline at end of file + a.ion-speakerphone(href='http://blog.freecodecamp.com', target='_blank') + span.sr-only Free Code Camp's Blog + a.ion-social-twitch-outline(href="http://www.twitch.tv/freecodecamp", target='_blank') + span.sr-only Free Code Camp Live Pair Programming on Twitch.tv + a.ion-social-github(href="http://github.com/freecodecamp", target='_blank') + span.sr-only Free Code Camp on GitHub + a.ion-social-twitter(href="http://twitter.com/freecodecamp", target='_blank') + span.sr-only Free Code Camp on Twitter + a.ion-social-facebook(href="http://facebook.com/freecodecamp", target='_blank') + span.sr-only Free Code Camp on Facebook + a.ion-social-linkedin(href="http://linkedin.com/company/4831032?free-code-camp", target='_blank') + span.sr-only Free Code Camp on LinkedIn + a.ion-information-circled(href="/learn-to-code") + span.sr-only About Free Code Camp + a.ion-locked(href="/privacy") + span.sr-only Free Code Camp's Privacy Policy + a.ion-code-working(href="/playground") + span.sr-only Code Editor Playground \ No newline at end of file From 6455d80a6e1ba871ac0eb57a367ce9a4320e1759 Mon Sep 17 00:00:00 2001 From: phlacin Date: Wed, 11 Feb 2015 23:08:10 -0800 Subject: [PATCH 21/68] Added Moment.js library and added logic to the time for the next Live session. --- public/js/lib/moment/moment.js | 3 +++ public/js/lib/moment/nextTuesday.js | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 public/js/lib/moment/moment.js create mode 100644 public/js/lib/moment/nextTuesday.js diff --git a/public/js/lib/moment/moment.js b/public/js/lib/moment/moment.js new file mode 100644 index 0000000000..135be1ac41 --- /dev/null +++ b/public/js/lib/moment/moment.js @@ -0,0 +1,3 @@ +/** + * Created by jason on 2/11/15. + */ diff --git a/public/js/lib/moment/nextTuesday.js b/public/js/lib/moment/nextTuesday.js new file mode 100644 index 0000000000..135be1ac41 --- /dev/null +++ b/public/js/lib/moment/nextTuesday.js @@ -0,0 +1,3 @@ +/** + * Created by jason on 2/11/15. + */ From c826ac23414b8e4a77ff98381db20cad119859f9 Mon Sep 17 00:00:00 2001 From: Alex Dixon Date: Thu, 12 Feb 2015 04:04:18 -0800 Subject: [PATCH 22/68] Typos --- seed_data/bonfires.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/seed_data/bonfires.json b/seed_data/bonfires.json index 1584ef54fc..abe4f5fe39 100644 --- a/seed_data/bonfires.json +++ b/seed_data/bonfires.json @@ -116,7 +116,7 @@ "difficulty": "1.06", "description": [ "Return an array consisting of the largest numbers in the provided array. The array will contain 4 sub-arrays.", - "Remember, you an iterate through an array with a simple for loop, and access each member with array syntax arr[i] .", + "Remember, you can iterate through an array with a simple for loop, and access each member with array syntax arr[i] .", "If you are writing your own Chai.js tests, be sure to use a deep equal statement instead of an equal statement when comparing arrays." ], "challengeEntryPoint": "largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);", @@ -172,9 +172,9 @@ "name": "Sum All Odd Fibonacci Numbers", "difficulty": "2.09", "description": [ - "Return the sum of all odd fibonacci numbers up to and including the passed number if it is a fibonacci number.", + "Return the sum of all odd Fibonacci numbers up to and including the passed number if it is a Fibonacci number.", "The first few numbers of the Fibonacci sequence are 1, 1, 2, 3, 5 and 8, and each subsequent number is the sum of the previous two numbers.", - "As an example, passing 4 to the function should return 5 because all the odd fibonacci numbers under 4 are 1, 1, and 3." + "As an example, passing 4 to the function should return 5 because all the odd Fibonacci numbers under 4 are 1, 1, and 3." ], "challengeEntryPoint": "sumFibs(4);", "challengeSeed": "function sumFibs(num) {\n return num;\r\n}", @@ -193,7 +193,7 @@ "difficulty": "2.10", "description": [ "Sum all the prime numbers up to and including the provided number.", - "A prime number is defined as having only two divisors, 1 and itself. For example, 2 is a prime number because it's only divisible by 1 and 2. 1 isn't a prime number, because it's only divisible by itself.", + "A prime number is defined as having only two divisors, 1 and itself. For example, 2 is a prime number because it's only divisible by 1 and 2. 1 isn't a prime number, because it's only divisible by itself.", "The provided number may not be a prime." ], "challengeEntryPoint": "sumPrimes(10);", @@ -229,7 +229,7 @@ "Fill in the object constructor with the methods specified in the tests.", "Those methods are getFirstName(), getLastName(), getFullName(), setFirstName(), setLastName(), and setFullName().", "These methods must be the only available means for interacting with the object.", - "There will be some linting errors on the tests, you may safely ignore them. You should see undefined in the console output." + "There will be some linting errors on the tests. You may safely ignore them. You should see undefined in the console output." ], "challengeEntryPoint": "var bob = new Person('Bob Ross');", "challengeSeed": "var Person = function(firstAndLast) {\n return firstAndLast;\r\n};", @@ -257,7 +257,7 @@ "Return true if the passed string is a valid US phone number", "The user may fill out the form field any way they choose as long as it is a valid US number. The following are all valid formats for US numbers:", "555-555-5555, (555)555-5555, (555) 555-5555, 555 555 5555, 5555555555, 1 555 555 5555", - "For this challenge you will be presented with a string such as \"800-692-7753\" or \"8oo-six427676;laskdjf\". Your job is to validate or reject the US phone number based on any combination of the formats provided above. The area code is required. If the country code code is provided, you must confirm that the country code is \"1\". Return true if the string is a valid US phone number; otherwise false." + "For this challenge you will be presented with a string such as \"800-692-7753\" or \"8oo-six427676;laskdjf\". Your job is to validate or reject the US phone number based on any combination of the formats provided above. The area code is required. If the country code is provided, you must confirm that the country code is \"1\". Return true if the string is a valid US phone number; otherwise false." ], "tests": [ "expect(telephoneCheck(\"555-555-5555\")).to.be.a(\"boolean\");", From 51f75031de629ef13fb491c28af54aad504d664b Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Thu, 12 Feb 2015 15:21:48 -0800 Subject: [PATCH 23/68] add a bunch of padding and margin related courseware, and start bootstrap courseware --- seed_data/coursewares.json | 565 +++++++++++++++++++++++++++++++------ 1 file changed, 483 insertions(+), 82 deletions(-) diff --git a/seed_data/coursewares.json b/seed_data/coursewares.json index e6970aa28b..d42436c381 100644 --- a/seed_data/coursewares.json +++ b/seed_data/coursewares.json @@ -779,9 +779,9 @@ "name": "Adjusting the Padding of an Element", "difficulty" : "0.28", "description": [ - "Change the padding of the yellow box to 20 pixels.", + "Change the padding of the green box to match that of the red box.", "An element's padding controls the amount of space between an element and its border.", - "Here, we can see that the green box and the red box and the green box are nested within the blue box.", + "Here, we can see that the green box and the red box and the green box are nested within the yellow box. Note that the red box has more padding than the green box.", "When you increase the green box's padding, it will increase the distance between the word \"padding\" and the border around the text." ], "tests": [ @@ -801,8 +801,8 @@ " text-align: center;", " }", "", - " .blue-box {", - " background-color: blue;", + " .yellow-box {", + " background-color: yellow;", " padding:10px;", " }", " ", @@ -818,7 +818,7 @@ "", "
margin
", "", - "
", + "
", "
padding
", "
padding
", "
" @@ -826,38 +826,56 @@ "challengeType": 0 }, - { - "_id" : "bad87fee1348bd9aedf08821", - "name": "Add Padding to an Element", - "difficulty" : "0.29", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - { "_id" : "bad87fee1348bd9aedf08822", - "name": "Add a Margin to an Element", + "name": "Adjust the Margin of an Element", "difficulty" : "0.30", "description": [ - "", - "" + "Change the margin of the green box to match that of the red box.", + "An element's margin controls the amount of space between an element's border and surrounding elements.", + "Here, we can see that the green box and the red box and the green box are nested within the yellow box. Note that the red box has more margin than the green box, making it appear smaller.", + "When you increase the green box's padding, it will increase the distance between its border and surrounding elements." ], "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" + "expect($('.green-box')).to.have.css('margin', '20px')" ], "challengeSeed": [ - "

hello world

" + "", + "
margin
", + "", + "
", + "
padding
", + "
padding
", + "
" ], "challengeType": 0 }, @@ -867,69 +885,209 @@ "name": "Add a Negative Margin to an Element", "difficulty" : "0.31", "description": [ - "", - "" + "Change the margin of the green box to a negative value, so it fills the entire horizontal width of the blue box.", + "An element's margin controls the amount of space between an element's border and surrounding elements.", + "If you set an element's margin to a negative value, the element will grow larger.", + "Try to set the margin to a negative value like the one for the red box." ], "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" + "expect($('.green-box')).to.have.css('margin', '-15px')" ], "challengeSeed": [ - "

hello world

" + "", + "", + "
", + "
padding
", + "
padding
", + "
" ], "challengeType": 0 }, { "_id" : "bad87fee1348bd9aedf08824", - "name": "Add Padding Only to the Top and Bottom of an Element", + "name": "Add Different Padding to Each Side of an Element TEST", "difficulty" : "0.32", "description": [ - "", - "" + "Give the green box a padding of 40 pixels on its top and left side, but only 20 pixels on its bottom and right side.", + "Sometimes you will want to customize an element so that it has different padding on each of its sides.", + "CSS allows you to control the padding of an element on all four sides with padding-top, padding-right, padding-bottom, and padding-left attributes." ], "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" + "expect($('.green-box')).to.have.css('padding-bottom', '20px')", + "expect($('.green-box')).to.have.css('padding-left', '40px')" ], "challengeSeed": [ - "

hello world

" + "", + "
margin
", + "", + "
", + "
padding
", + "
padding
", + "
" ], "challengeType": 0 }, { - "_id" : "bad87fee1348bd9aedf08825", - "name": "Add Margin Only to the Left and Right of an Element", - "difficulty" : "0.33", + "_id" : "bad87fee1248bd9aedf08824", + "name": "Add Different a Margin to Each Side of an Element TEST", + "difficulty" : "0.32", "description": [ - "", - "" + "Give the green box a margin of 40 pixels on its top and left side, but only 20 pixels on its bottom and right side.", + "Sometimes you will want to customize an element so that it has a different margin on each of its sides.", + "CSS allows you to control the margin of an element on all four sides with margin-top, margin-right, margin-bottom, and margin-left attributes." ], "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" + "expect($('.green-box')).to.have.css('margin-bottom', '20px')", + "expect($('.green-box')).to.have.css('margin-left', '40px')" ], "challengeSeed": [ - "

hello world

" + "", + "
margin
", + "", + "
", + "
padding
", + "
padding
", + "
" ], "challengeType": 0 }, { "_id" : "bad87fee1348bd9aedf08826", - "name": "Use Clockwise Padding Notation", + "name": "Use Clockwise Notation to Specify an Element's Padding", "difficulty" : "0.34", "description": [ - "", - "" + "Use Clockwise Notation to give an element padding of 40 pixels on its top and left side, but only 20 pixels on its bottom and right side.", + "Instead of specifying an element's padding-top, padding-right, padding-bottom, and padding-left attributes, you can specify them all in one line, like this: padding: 10px 20px 10px 20px;.", + "These four values work like a clock: top, right, bottom, left, and will produce the exact same result as using the side-specific padding instructions.", + "You can also use this notation for margins!" ], "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" + "expect($('.green-box')).to.have.css('margin-bottom', '20px')", + "expect($('.green-box')).to.have.css('margin-left', '40px')" ], "challengeSeed": [ - "

hello world

" + "", + "
margin
", + "", + "
", + "
padding
", + "
padding
", + "
" ], "challengeType": 0 }, @@ -950,14 +1108,22 @@ ], "challengeSeed": [ "", - "

hello world

", - "

cat photo app

", - "

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

", - "" + "

cat photo app

", + "", + "
", + "This is a link to Google", + "
" ], "challengeType": 0 }, @@ -967,25 +1133,25 @@ "name": "Center Text with Bootstrap", "difficulty" : "0.36", "description": [ - "Add Bootstrap's text-center class to your h1 and h2 elements.", - "Now that we're using Bootstrap, we can center our heading elements (h1 and h2) to make them look better. All we need to do is add the class text-center to the h1 and h2 elements.", + "Add Bootstrap's text-center class to your h2 element.", + "Now that we're using Bootstrap, we can center our heading elements (h2) to make them look better. All we need to do is add the class text-center to the h1 and h2 elements.", "Note that you can add several classes to the same element by seperating each of them with a space, like this: <h2 class=\"text-red text-center\">your text</h2>." ], "tests": [ - "expect($('h1')).to.have.class('text-center');", "expect($('h2')).to.have.class('text-center');" ], "challengeSeed": [ "", - "

hello world

", - "

cat photo app

", - "

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

", - "" + "

cat photo app

", + "", + "
" ], "challengeType": 0 }, @@ -995,25 +1161,260 @@ "name": "Create a Button", "difficulty" : "0.37", "description": [ - "Create a bootstrap button with the class .", - "Now that we're using Bootstrap, we can center our heading elements (h1 and h2) to make them look better. All we need to do is add the class text-center to the h1 and h2 elements.", - "Note that you can add several classes to the same element by seperating each of them with a space, like this: <h2 class=\"text-red text-center\">your text</h2>." + "Create a button with the text \"Delete\" using the HTML button element.", + "HTML has special elements that function like links, but look like buttons. Let's creating a default HTML button." ], "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h2')).to.have.class('text-center');" + "expect((/delete/gi).test($('button').text())).to.be.true;" ], "challengeSeed": [ "", - "

hello world

", - "

cat photo app

", - "

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

", - "" + "

cat photo app

", + "", + "
", + "", + "
" + ], + "challengeType": 0 + }, + + { + "_id" : "bad87fee1348cd8acdf08812", + "name": "Create a Bootstrap Button", + "difficulty" : "0.37", + "description": [ + "Apply the Bootstrap's btn class to both of your buttons.", + "Bootstrap has its own button styles, which look much better than the plain HTML ones." + ], + "tests": [ + "expect($('.btn').length).to.eql(2);" + ], + "challengeSeed": [ + "", + "

cat photo app

", + "", + "
", + "", + "
", + "" + ], + "challengeType": 0 + }, + + { + "_id" : "bad87fee1348cd8acef08812", + "name": "Create a Block Element Bootstrap Button", + "difficulty" : "0.37", + "description": [ + "Add Bootstrap's btn-block class to both of your buttons.", + "Normally, your buttons are only as wide as the text they contain. By making them block elements, your button will stretch to fill your page's entire horizontal space.", + "Note that these buttons still need the btn class." + ], + "tests": [ + "expect($('.btn-block').length).to.eql(2);" + ], + "challengeSeed": [ + "", + "

cat photo app

", + "", + "
", + "", + "
", + "" + ], + "challengeType": 0 + }, + + { + "_id" : "bad87fee1348cd8acef08812", + "name": "Color a Bootstrap Button with Button Primary", + "difficulty" : "0.37", + "description": [ + "Add Bootstrap's btn-block class to both of your buttons.", + "Normally, your buttons are only as wide as the text they contain. By making them block elements, your button will stretch to fill your page's entire horizontal space.", + "Note that these buttons still need the btn class." + ], + "tests": [ + "expect($('.btn-block').length).to.eql(2);" + ], + "challengeSeed": [ + "", + "

cat photo app

", + "", + "
", + "", + "
", + "" + ], + "challengeType": 0 + }, + + { + "_id" : "bad87fee1348cd8acef08812", + "name": "Color a Bootstrap Button with Button Primary", + "difficulty" : "0.37", + "description": [ + "Add Bootstrap's btn-primary class to both of your buttons.", + "Bootstrap comes with several pre-defined colors for buttons. The btn-primary class is the main button color you'll use throughout your app.", + "Note that these buttons still need the btn and btn-block classes." + ], + "tests": [ + "expect($('.btn-primary').length).to.eql(2);" + ], + "challengeSeed": [ + "", + "

cat photo app

", + "", + "
", + "", + "
", + "" + ], + "challengeType": 0 + }, + + { + "_id" : "bad87fee1348ce8acef08812", + "name": "Warn your Users of a Dangerous Action with the Bootstrap Button Danger Class", + "difficulty" : "0.37", + "description": [ + "Change the \"Delete\" button from btn-primary to btn-danger.", + "Bootstrap comes with several pre-defined colors for buttons. The btn-danger class is the button color you'll use to notify users that the button performs a destructive action, such as deleting a cat photo.", + "Note that this button still needs the btn and btn-block classes." + ], + "tests": [ + "expect($('.btn-danger').length).to.eql(1);" + ], + "challengeSeed": [ + "", + "

cat photo app

", + "", + "
", + "", + "
", + "" + ], + "challengeType": 0 + }, + + { + "_id" : "bad88fee1348ce8acef08812", + "name": "Use the Bootstrap Grid to Put Two Elements Side By Side", + "difficulty" : "0.37", + "description": [ + "Put the \"Like\" and \"Delete\" buttons side-by-side by wrapping them in both in a <div class=\"row\"> element and each of them in a <div class=\"row\"> element.", + "Bootstrap uses a responsive grid system, which makes it easy to put elements into rows and specify each element's relative width. Most of Bootstrap's classes can be applied to a div element.", + "The row class is applied to a div, and the buttons themselves can be nested within it." + ], + "tests": [ + "expect($('.row').length).to.eql(2);", + "expect($('.col-xs-12').length).to.eql(4);" + ], + "challengeSeed": [ + "", + "

cat photo app

", + "", + "
", + "
", + "
", + " ", + "
", + "
", + " ", + "
", + "
", + "", + "
", + "" + ], + "challengeType": 0 + }, + + { + "_id" : "bad89fee1348ce8acef08812", + "name": "Wrap Side By Side Elements in a Bootstrap Row", + "difficulty" : "0.37", + "description": [ + "Put the \"Like\" and \"Delete\" buttons side-by-side by wrapping them in both in a <div class=\"row\"> element and each of them in a <div class=\"row\"> element.", + "Bootstrap uses a responsive grid system, which makes it easy to put elements into rows and specify each element's relative width. Most of Bootstrap's classes can be applied to a div element.", + "The row class is applied to a div, and the buttons themselves can be nested within it." + ], + "tests": [ + "expect($('.row').length).to.eql(2);", + "expect($('.col-xs-12').length).to.eql(4);" + ], + "challengeSeed": [ + "", + "

cat photo app

", + "", + "
", + "
", + "
", + " ", + "
", + "
", + " ", + "
", + "
", + "", + "
", + "" ], "challengeType": 0 }, From 93f4f6aa1960db23d323b25a5771abbf40550fcf Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Thu, 12 Feb 2015 16:00:34 -0800 Subject: [PATCH 24/68] resequence coursewares --- seed_data/coursewares.json | 296 ++++++------------------------------- 1 file changed, 49 insertions(+), 247 deletions(-) diff --git a/seed_data/coursewares.json b/seed_data/coursewares.json index d42436c381..10a7b45cad 100644 --- a/seed_data/coursewares.json +++ b/seed_data/coursewares.json @@ -710,7 +710,7 @@ { "_id" : "bad87fee1348bd9aedf08820", "name": "Turn an Image into a Link", - "difficulty" : "0.271", + "difficulty" : "0.25", "description": [ "Wrap the gray cat's image with an anchor tag that leads nowhere.", "You can make elements into links by wrapping them in an anchor tag.", @@ -744,7 +744,7 @@ { "_id" : "bad87fee1348bd9aedf08818", "name": "Add Alt Text to an image", - "difficulty" : "0.25", + "difficulty" : "0.26", "description": [ "Add the alt text \"a photo of a cute gray cat\" to our cat photo", "alt text is what browsers will display if they fail to load the image. alt text is also important for blind or visually impaired users to understand what an image portrays. Search engines also look at alt text.", @@ -777,7 +777,7 @@ { "_id" : "bad88fee1348bd9aedf08825", "name": "Adjusting the Padding of an Element", - "difficulty" : "0.28", + "difficulty" : "0.27", "description": [ "Change the padding of the green box to match that of the red box.", "An element's padding controls the amount of space between an element and its border.", @@ -829,7 +829,7 @@ { "_id" : "bad87fee1348bd9aedf08822", "name": "Adjust the Margin of an Element", - "difficulty" : "0.30", + "difficulty" : "0.28", "description": [ "Change the margin of the green box to match that of the red box.", "An element's margin controls the amount of space between an element's border and surrounding elements.", @@ -883,7 +883,7 @@ { "_id" : "bad87fee1348bd9aedf08823", "name": "Add a Negative Margin to an Element", - "difficulty" : "0.31", + "difficulty" : "0.29", "description": [ "Change the margin of the green box to a negative value, so it fills the entire horizontal width of the blue box.", "An element's margin controls the amount of space between an element's border and surrounding elements.", @@ -936,7 +936,7 @@ { "_id" : "bad87fee1348bd9aedf08824", "name": "Add Different Padding to Each Side of an Element TEST", - "difficulty" : "0.32", + "difficulty" : "0.30", "description": [ "Give the green box a padding of 40 pixels on its top and left side, but only 20 pixels on its bottom and right side.", "Sometimes you will want to customize an element so that it has different padding on each of its sides.", @@ -990,7 +990,7 @@ { "_id" : "bad87fee1248bd9aedf08824", "name": "Add Different a Margin to Each Side of an Element TEST", - "difficulty" : "0.32", + "difficulty" : "0.31", "description": [ "Give the green box a margin of 40 pixels on its top and left side, but only 20 pixels on its bottom and right side.", "Sometimes you will want to customize an element so that it has a different margin on each of its sides.", @@ -1044,7 +1044,7 @@ { "_id" : "bad87fee1348bd9aedf08826", "name": "Use Clockwise Notation to Specify an Element's Padding", - "difficulty" : "0.34", + "difficulty" : "0.32", "description": [ "Use Clockwise Notation to give an element padding of 40 pixels on its top and left side, but only 20 pixels on its bottom and right side.", "Instead of specifying an element's padding-top, padding-right, padding-bottom, and padding-left attributes, you can specify them all in one line, like this: padding: 10px 20px 10px 20px;.", @@ -1095,7 +1095,7 @@ { "_id" : "bad87fee1348bd9acde08812", "name": "Use Bootstrap for Responsive Images", - "difficulty" : "0.35", + "difficulty" : "0.33", "description": [ "Add the img-responsive Bootstrap class to the image.", "Specifying a width of 200 pixels on our img element made it fit our phone's screen, but it's not a perfect fit. It would be great if the image could be exactly the width of our phone's screen.", @@ -1131,7 +1131,7 @@ { "_id" : "bad87fee1348bd8acde08812", "name": "Center Text with Bootstrap", - "difficulty" : "0.36", + "difficulty" : "0.34", "description": [ "Add Bootstrap's text-center class to your h2 element.", "Now that we're using Bootstrap, we can center our heading elements (h2) to make them look better. All we need to do is add the class text-center to the h1 and h2 elements.", @@ -1159,7 +1159,7 @@ { "_id" : "bad87fee1348cd8acde08812", "name": "Create a Button", - "difficulty" : "0.37", + "difficulty" : "0.35", "description": [ "Create a button with the text \"Delete\" using the HTML button element.", "HTML has special elements that function like links, but look like buttons. Let's creating a default HTML button." @@ -1188,7 +1188,7 @@ { "_id" : "bad87fee1348cd8acdf08812", "name": "Create a Bootstrap Button", - "difficulty" : "0.37", + "difficulty" : "0.36", "description": [ "Apply the Bootstrap's btn class to both of your buttons.", "Bootstrap has its own button styles, which look much better than the plain HTML ones." @@ -1249,7 +1249,7 @@ { "_id" : "bad87fee1348cd8acef08812", "name": "Color a Bootstrap Button with Button Primary", - "difficulty" : "0.37", + "difficulty" : "0.38", "description": [ "Add Bootstrap's btn-block class to both of your buttons.", "Normally, your buttons are only as wide as the text they contain. By making them block elements, your button will stretch to fill your page's entire horizontal space.", @@ -1280,7 +1280,7 @@ { "_id" : "bad87fee1348cd8acef08812", "name": "Color a Bootstrap Button with Button Primary", - "difficulty" : "0.37", + "difficulty" : "0.39", "description": [ "Add Bootstrap's btn-primary class to both of your buttons.", "Bootstrap comes with several pre-defined colors for buttons. The btn-primary class is the main button color you'll use throughout your app.", @@ -1311,7 +1311,7 @@ { "_id" : "bad87fee1348ce8acef08812", "name": "Warn your Users of a Dangerous Action with the Bootstrap Button Danger Class", - "difficulty" : "0.37", + "difficulty" : "0.40", "description": [ "Change the \"Delete\" button from btn-primary to btn-danger.", "Bootstrap comes with several pre-defined colors for buttons. The btn-danger class is the button color you'll use to notify users that the button performs a destructive action, such as deleting a cat photo.", @@ -1342,7 +1342,7 @@ { "_id" : "bad88fee1348ce8acef08812", "name": "Use the Bootstrap Grid to Put Two Elements Side By Side", - "difficulty" : "0.37", + "difficulty" : "0.41", "description": [ "Put the \"Like\" and \"Delete\" buttons side-by-side by wrapping them in both in a <div class=\"row\"> element and each of them in a <div class=\"row\"> element.", "Bootstrap uses a responsive grid system, which makes it easy to put elements into rows and specify each element's relative width. Most of Bootstrap's classes can be applied to a div element.", @@ -1382,7 +1382,7 @@ { "_id" : "bad89fee1348ce8acef08812", "name": "Wrap Side By Side Elements in a Bootstrap Row", - "difficulty" : "0.37", + "difficulty" : "0.42", "description": [ "Put the \"Like\" and \"Delete\" buttons side-by-side by wrapping them in both in a <div class=\"row\"> element and each of them in a <div class=\"row\"> element.", "Bootstrap uses a responsive grid system, which makes it easy to put elements into rows and specify each element's relative width. Most of Bootstrap's classes can be applied to a div element.", @@ -1422,7 +1422,7 @@ { "_id" : "bad87fee1348bd9aedf08813", "name": "Add Alt Text to an Image TEST", - "difficulty" : "0.38", + "difficulty" : "0.43", "description": [ "Add the alt text \"A picture of a gray cat\" to the image.", "Alt text is a useful way to tell people (and web crawlers like Google) what is pictured in a photo. It's extremely important for helping blind or visually impaired people understand the content of your website.", @@ -1448,7 +1448,7 @@ { "_id" : "bad87fee1348bd9aedf08827", "name": "Create an Bulleted Unordered List", - "difficulty" : "0.39", + "difficulty" : "0.44", "description": [ "", "" @@ -1466,7 +1466,7 @@ { "_id" : "bad87fee1348bd9aedf08828", "name": "Created a Numbered Ordered List", - "difficulty" : "0.29", + "difficulty" : "0.45", "description": [ "", "" @@ -1484,7 +1484,7 @@ { "_id" : "bad87fee1348bd9aedf08829", "name": "Create a Text Field", - "difficulty" : "0.30", + "difficulty" : "0.46", "description": [ "", "" @@ -1502,7 +1502,7 @@ { "_id" : "bad87fee1348bd9aedf08830", "name": "Use HTML5 to Make a Field Required", - "difficulty" : "0.31", + "difficulty" : "0.47", "description": [ "", "" @@ -1520,7 +1520,7 @@ { "_id" : "bad87fee1348bd9aedf08831", "name": "Use HTML5 to Specify an Input Type", - "difficulty" : "0.32", + "difficulty" : "0.49", "description": [ "", "" @@ -1538,7 +1538,7 @@ { "_id" : "bad87fee1348bd9aedf08832", "name": "Create a Text Area", - "difficulty" : "0.33", + "difficulty" : "0.50", "description": [ "", "" @@ -1556,7 +1556,7 @@ { "_id" : "bad87fee1348bd9aedf08834", "name": "Create a Set of Radio Buttons", - "difficulty" : "0.35", + "difficulty" : "0.51", "description": [ "", "" @@ -1574,7 +1574,7 @@ { "_id" : "bad87fee1348bd9aedf08835", "name": "Create a Set of Checkboxes", - "difficulty" : "0.36", + "difficulty" : "0.52", "description": [ "", "" @@ -1592,79 +1592,7 @@ { "_id" : "bad87fee1348bd9aedf08836", "name": "Create a HTML Form", - "difficulty" : "0.37", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - - { - "_id" : "bad87fee1348bd9aedf08837", - "name": "Use a Bootstrap Primary Button", - "difficulty" : "0.38", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - - { - "_id" : "bad87fee1348bd9aedf08838", - "name": "Apply Responsive Design with the Bootstrap Grid", - "difficulty" : "0.39", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - - { - "_id" : "bad87fee1348bd9aedf08839", - "name": "Create a Half Width Bootstrap Column", - "difficulty" : "0.40", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - - { - "_id" : "bad87fee1348bd9aedf08840", - "name": "Create a Row of Bootstrap Elements", - "difficulty" : "0.41", + "difficulty" : "0.53", "description": [ "", "" @@ -1682,7 +1610,7 @@ { "_id" : "bad87fee1348bd9aedf08841", "name": "Change the background of element", - "difficulty" : "0.42", + "difficulty" : "0.54", "description": [ "", "" @@ -1700,25 +1628,7 @@ { "_id" : "bad87fee1348bd9aedf08842", "name": "Make an element translucent", - "difficulty" : "0.43", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - - { - "_id" : "bad87fee1348bd9aedf08843", - "name": "Center an Image", - "difficulty" : "0.44", + "difficulty" : "0.55", "description": [ "", "" @@ -1736,7 +1646,7 @@ { "_id" : "bad87fee1348bd9aedf08844", "name": "Add a Drop Shadow", - "difficulty" : "0.45", + "difficulty" : "0.56", "description": [ "", "" @@ -1754,7 +1664,7 @@ { "_id" : "bad87fee1348bd9aedf08845", "name": "Make a Navbar", - "difficulty" : "0.46", + "difficulty" : "0.57", "description": [ "", "" @@ -1772,7 +1682,7 @@ { "_id" : "bad87fee1348bd9aedf08847", "name": "Add a Logo to a Navbar", - "difficulty" : "0.47", + "difficulty" : "0.58", "description": [ "", "" @@ -1790,7 +1700,7 @@ { "_id" : "bad87fee1348bd9aedf08848", "name": "Make a Footer", - "difficulty" : "0.48", + "difficulty" : "0.59", "description": [ "", "" @@ -1808,7 +1718,7 @@ { "_id" : "bad87fee1348bd9aedf08849", "name": "Use Icons as Links", - "difficulty" : "0.49", + "difficulty" : "0.60", "description": [ "", "" @@ -1826,7 +1736,7 @@ { "_id" : "bad87fee1348bd9aedf08850", "name": "Add Hover Effects to Icons", - "difficulty" : "0.50", + "difficulty" : "0.61", "description": [ "", "" @@ -1844,7 +1754,7 @@ { "_id" : "bad87fee1348bd9aedf08851", "name": "Add Depth to a Page with a Well", - "difficulty" : "0.51", + "difficulty" : "0.62", "description": [ "", "" @@ -1880,7 +1790,7 @@ { "_id" : "bad87fee1348bd9aedf08853", "name": "Fire a Modal by Clicking a Button", - "difficulty" : "0.53", + "difficulty" : "0.63", "description": [ "", "" @@ -1898,7 +1808,7 @@ { "_id" : "bad87fee1348bd9aedf08854", "name": "Style a Modal with a Header", - "difficulty" : "0.54", + "difficulty" : "0.64", "description": [ "", "" @@ -1916,7 +1826,7 @@ { "_id" : "bad87fee1348bd9aedf08855", "name": "Style a Modal with a Body", - "difficulty" : "0.55", + "difficulty" : "0.65", "description": [ "", "" @@ -1934,7 +1844,7 @@ { "_id" : "bad87fee1348bd9aedf08856", "name": "Make a Modal Dismissable", - "difficulty" : "0.56", + "difficulty" : "0.66", "description": [ "", "" @@ -1952,97 +1862,7 @@ { "_id" : "bad87fee1348bd9aedf08857", "name": "Create an Accordian Menu", - "difficulty" : "0.57", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - - { - "_id" : "bad87fee1348bd9aedf08858", - "name": "Add a Bootstrap Info Button", - "difficulty" : "0.58", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - - { - "_id" : "bad87fee1348bd9aedf08859", - "name": "Add a Bootstrap Warning Button", - "difficulty" : "0.59", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - - { - "_id" : "bad87fee1348bd9aedf08860", - "name": "Add a Bootstrap Danger Button", - "difficulty" : "0.60", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - - { - "_id" : "bad87fee1348bd9aedf08861", - "name": "Add a Bootstrap Success Button", - "difficulty" : "0.61", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - - { - "_id" : "bad87fee1348bd9aedf08862", - "name": "Use a Block-width Button", - "difficulty" : "0.62", + "difficulty" : "0.67", "description": [ "", "" @@ -2060,7 +1880,7 @@ { "_id" : "bad87fee1348bd9aedf08863", "name": "Add a Gradient to a Button", - "difficulty" : "0.63", + "difficulty" : "0.68", "description": [ "", "" @@ -2078,25 +1898,7 @@ { "_id" : "bad87fee1348bd9aedf08864", "name": "Adjust the Line Height of Text", - "difficulty" : "0.64", - "description": [ - "", - "" - ], - "tests": [ - "expect($('h1')).to.have.class('text-center');", - "expect($('h1')).to.have.text('hello world');" - ], - "challengeSeed": [ - "

hello world

" - ], - "challengeType": 0 - }, - - { - "_id" : "bad87fee1348bd9aedf08865", - "name": "Use Responsive Images to Fit Containing Elements", - "difficulty" : "0.65", + "difficulty" : "0.69", "description": [ "", "" @@ -2114,7 +1916,7 @@ { "_id" : "bad87fee1348bd9aedf08866", "name": "", - "difficulty" : "0.66", + "difficulty" : "0.70", "description": [ "", "" @@ -2132,7 +1934,7 @@ { "_id" : "bad87fee1348bd9aedf08867", "name": "", - "difficulty" : "0.67", + "difficulty" : "0.71", "description": [ "", "" @@ -2150,7 +1952,7 @@ { "_id" : "bad87fee1348bd9aedf08868", "name": "", - "difficulty" : "0.68", + "difficulty" : "0.711", "description": [ "", "" @@ -2168,7 +1970,7 @@ { "_id" : "bad87fee1348bd9aedf08869", "name": "", - "difficulty" : "0.69", + "difficulty" : "0.712", "description": [ "", "" @@ -2186,7 +1988,7 @@ { "_id" : "bad87fee1348bd9aedf08870", "name": "", - "difficulty" : "0.70", + "difficulty" : "0.713", "description": [ "", "" @@ -2204,7 +2006,7 @@ { "_id" : "bad87fee1348bd9aedf08871", "name": "", - "difficulty" : "0.71", + "difficulty" : "0.714", "description": [ "", "" From f8f0c3454a7e51eb48a5b4af60a19ab370fc6cbd Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Thu, 12 Feb 2015 16:48:35 -0800 Subject: [PATCH 25/68] subtle completed challenge button for courseware and add completionMessage to coursewares --- models/Courseware.js | 1 + ....1.0.js => coursewaresFramework_v0.1.1.js} | 12 +- public/js/main.js | 2 +- seed_data/coursewares.json | 315 ++++++++++++------ views/coursewares/show.jade | 19 +- 5 files changed, 231 insertions(+), 118 deletions(-) rename public/js/lib/coursewares/{coursewaresFramework_v0.1.0.js => coursewaresFramework_v0.1.1.js} (92%) diff --git a/models/Courseware.js b/models/Courseware.js index 7baa6cc565..aa4f8ca5d4 100644 --- a/models/Courseware.js +++ b/models/Courseware.js @@ -15,6 +15,7 @@ var coursewareSchema = new mongoose.Schema({ description: Array, tests: Array, challengeSeed: Array, + completionMessage: String, // Congratulations! You've finished our HTML and CSS track! challengeType: Number // 0 = html, 1 = javascript only, 2 = video }); diff --git a/public/js/lib/coursewares/coursewaresFramework_v0.1.0.js b/public/js/lib/coursewares/coursewaresFramework_v0.1.1.js similarity index 92% rename from public/js/lib/coursewares/coursewaresFramework_v0.1.0.js rename to public/js/lib/coursewares/coursewaresFramework_v0.1.1.js index a2877aa51c..026f36c04e 100644 --- a/public/js/lib/coursewares/coursewaresFramework_v0.1.0.js +++ b/public/js/lib/coursewares/coursewaresFramework_v0.1.1.js @@ -26,7 +26,6 @@ editor.setOption("extraKeys", { cm.replaceSelection(spaces); }, "Ctrl-Enter": function() { - bonfireExecute(); return false; } }); @@ -120,10 +119,15 @@ function doLinting () { function showCompletion() { var time = Math.floor(Date.now() / 1000) - started; ga('send', 'event', 'Challenge', 'solved', challengeName + ', Time: ' + time); - $('#complete-courseware-dialog').modal('show'); - $('#complete-courseware-dialog').keydown(function(e) { + $('#next-courseware-button').removeAttr('disabled'); + $('#next-courseware-button').addClass('animated tada'); + console.log(!userLoggedIn); + if (!userLoggedIn) { + $('#complete-courseware-dialog').modal('show'); + } + $('body').keydown(function(e) { if (e.ctrlKey && e.keyCode == 13) { - $('.next-courseware-button').click(); + $('#next-courseware-button').click(); } }); } diff --git a/public/js/main.js b/public/js/main.js index 9b9eea7784..2d8d85b29e 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -74,7 +74,7 @@ $(document).ready(function() { $('#complete-courseware-dialog').on('hidden.bs.modal', function() { editor.focus(); }); - $('.next-courseware-button').on('click', function() { + $('#next-courseware-button').on('click', function() { if ($('.signup-btn-nav').length < 1) { $.post( '/completed-courseware', diff --git a/seed_data/coursewares.json b/seed_data/coursewares.json index 10a7b45cad..cfb32c6e38 100644 --- a/seed_data/coursewares.json +++ b/seed_data/coursewares.json @@ -17,7 +17,8 @@ "challengeSeed": [ "

hello

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

hello world

" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -56,7 +58,8 @@ "

hello world

", "

hello html

" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -76,7 +79,8 @@ "

hello html

", "

hello paragraph

" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -100,7 +104,8 @@ "", "

hello paragraph

" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -125,7 +130,8 @@ "", "

hello paragraph

" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -146,7 +152,8 @@ "

cat photo app

", "

hello paragraph

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

cat photo app

", "

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

" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -191,7 +199,8 @@ "

cat photo app

", "

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

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

cat photo app

", "

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

" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -247,7 +257,8 @@ "

cat photo app

", "

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

" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -274,7 +285,8 @@ "

cat photo app

", "

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

" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -306,7 +318,8 @@ "

cat photo app

", "

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

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

cat photo app

", "

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

" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -374,7 +388,8 @@ "

cat photo app

", "

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

" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -405,7 +420,8 @@ "

cat photo app

", "

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

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

cat photo app

", "

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

" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -460,7 +477,8 @@ "

cat photo app

", "

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

" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -487,7 +505,8 @@ "

cat photo app

", "

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

" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -519,7 +538,8 @@ "

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

", "" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -557,7 +577,8 @@ "

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

", "" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -595,7 +616,8 @@ "

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

", "" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -632,7 +654,8 @@ "

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

", "" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -667,7 +690,8 @@ "This is a link to Google", "
" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -704,7 +728,8 @@ "This named anchor leads nowhere", "
" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -738,7 +763,8 @@ "", "" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -771,7 +797,8 @@ "\"a", "" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -823,7 +850,8 @@ "
padding
", "
" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -877,7 +905,8 @@ "
padding
", "" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -930,7 +959,8 @@ "
padding
", "" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -984,7 +1014,8 @@ "
padding
", "" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -1038,7 +1069,8 @@ "
padding
", "" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -1089,7 +1121,8 @@ "
padding
", "" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -1125,7 +1158,8 @@ "This is a link to Google", "
" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -1153,7 +1187,8 @@ "", "
" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -1182,7 +1217,8 @@ "", "
" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -1212,7 +1248,8 @@ "
", "" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -1243,7 +1280,8 @@ "
", "" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -1274,7 +1312,8 @@ "
", "" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -1305,7 +1344,8 @@ "
", "" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -1336,7 +1376,8 @@ "
", "" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -1376,7 +1417,8 @@ "
", "" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -1416,7 +1458,8 @@ "
", "" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" }, { @@ -1442,7 +1485,8 @@ "

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

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

" ], - "challengeType": 0 + "challengeType": 0, + "completionMessage": "" } ] diff --git a/views/coursewares/show.jade b/views/coursewares/show.jade index 2756cf2923..17e3d9d905 100644 --- a/views/coursewares/show.jade +++ b/views/coursewares/show.jade @@ -39,6 +39,15 @@ block content button#less-info.btn.btn-info span.ion-help-circled | Less information + - if (cc) + a.btn.btn-primary.btn-lg.btn-block#next-courseware-button Go to my next challenge (ctrl + enter) + script. + var userLoggedIn = true; + + - else + a.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress + script. + var userLoggedIn = false; div.hidden #submitButton.btn.btn-primary.btn-big.btn-block Run code (ctrl + enter) br @@ -49,6 +58,7 @@ block content #testSuite br script(type="text/javascript"). + $('#next-courseware-button').attr('disabled', 'disabled'); var tests = !{JSON.stringify(tests)}; var challengeSeed = !{JSON.stringify(challengeSeed)}; var passedCoursewareHash = !{JSON.stringify(coursewareHash)}; @@ -60,7 +70,7 @@ block content form.code .form-group.codeMirrorView textarea#codeEditor(autofocus=true) - script(src='/js/lib/coursewares/coursewaresFramework_v0.1.0.js') + script(src='/js/lib/coursewares/coursewaresFramework_v0.1.1.js') .col-md-4.col-lg-3 .hidden-xs.hidden-sm img.iphone-position(src="https://s3.amazonaws.com/freecodecamp/iphone6-frame.png") @@ -77,11 +87,4 @@ block content .text-center .animated.zoomInDown.delay-half span.completion-icon.ion-checkmark-circled.text-primary - - if (cc) - a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block.next-courseware-button(name='_csrf', value=_csrf, aria-hidden='true') Go to my next challenge (ctrl + enter) - - if (points && points > 2) - a.animated.fadeIn.btn.btn-lg.btn-block.btn-twitter(href="https://twitter.com/intent/tweet?text=I%20just%20#{verb}%20%40FreeCodeCamp%20Challenge%20%23#{number}:%20#{name}&url=http%3A%2F%2Ffreecodecamp.com/challenges/#{number}&hashtags=LearnToCode, JavaScript" target="_blank") - i.fa.fa-twitter   - = phrase - - else a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress \ No newline at end of file From 2d447f0bb00e471d4c036618a718a6f6805e860e Mon Sep 17 00:00:00 2001 From: phlacin Date: Thu, 12 Feb 2015 20:31:11 -0800 Subject: [PATCH 26/68] added automatic time logic to live-pair-programming page --- public/js/lib/moment/moment.js | 3043 ++++++++++++++++++++ public/js/lib/moment/nextTuesday.js | 13 + views/layout-wide.jade | 2 + views/resources/live-pair-programming.jade | 8 +- 4 files changed, 3065 insertions(+), 1 deletion(-) diff --git a/public/js/lib/moment/moment.js b/public/js/lib/moment/moment.js index 135be1ac41..001e00c693 100644 --- a/public/js/lib/moment/moment.js +++ b/public/js/lib/moment/moment.js @@ -1,3 +1,3046 @@ /** * Created by jason on 2/11/15. */ +//! moment.js +//! version : 2.9.0 +//! authors : Tim Wood, Iskren Chernev, Moment.js contributors +//! license : MIT +//! momentjs.com + +(function (undefined) { + /************************************ + Constants + ************************************/ + + var moment, + VERSION = '2.9.0', + // the global-scope this is NOT the global object in Node.js + globalScope = (typeof global !== 'undefined' && (typeof window === 'undefined' || window === global.window)) ? global : this, + oldGlobalMoment, + round = Math.round, + hasOwnProperty = Object.prototype.hasOwnProperty, + i, + + YEAR = 0, + MONTH = 1, + DATE = 2, + HOUR = 3, + MINUTE = 4, + SECOND = 5, + MILLISECOND = 6, + + // internal storage for locale config files + locales = {}, + + // extra moment internal properties (plugins register props here) + momentProperties = [], + + // check for nodeJS + hasModule = (typeof module !== 'undefined' && module && module.exports), + + // ASP.NET json date format regex + aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, + aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/, + + // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html + // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere + isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/, + + // format tokens + formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|x|X|zz?|ZZ?|.)/g, + localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, + + // parsing token regexes + parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99 + parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999 + parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999 + parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999 + parseTokenDigits = /\d+/, // nonzero number of digits + parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic. + parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z + parseTokenT = /T/i, // T (ISO separator) + parseTokenOffsetMs = /[\+\-]?\d+/, // 1234567890123 + parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 + + //strict parsing regexes + parseTokenOneDigit = /\d/, // 0 - 9 + parseTokenTwoDigits = /\d\d/, // 00 - 99 + parseTokenThreeDigits = /\d{3}/, // 000 - 999 + parseTokenFourDigits = /\d{4}/, // 0000 - 9999 + parseTokenSixDigits = /[+-]?\d{6}/, // -999,999 - 999,999 + parseTokenSignedNumber = /[+-]?\d+/, // -inf - inf + + // iso 8601 regex + // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) + isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/, + + isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', + + isoDates = [ + ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/], + ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/], + ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/], + ['GGGG-[W]WW', /\d{4}-W\d{2}/], + ['YYYY-DDD', /\d{4}-\d{3}/] + ], + + // iso time formats and regexes + isoTimes = [ + ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d+/], + ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/], + ['HH:mm', /(T| )\d\d:\d\d/], + ['HH', /(T| )\d\d/] + ], + + // timezone chunker '+10:00' > ['10', '00'] or '-1530' > ['-', '15', '30'] + parseTimezoneChunker = /([\+\-]|\d\d)/gi, + + // getter and setter names + proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), + unitMillisecondFactors = { + 'Milliseconds' : 1, + 'Seconds' : 1e3, + 'Minutes' : 6e4, + 'Hours' : 36e5, + 'Days' : 864e5, + 'Months' : 2592e6, + 'Years' : 31536e6 + }, + + unitAliases = { + ms : 'millisecond', + s : 'second', + m : 'minute', + h : 'hour', + d : 'day', + D : 'date', + w : 'week', + W : 'isoWeek', + M : 'month', + Q : 'quarter', + y : 'year', + DDD : 'dayOfYear', + e : 'weekday', + E : 'isoWeekday', + gg: 'weekYear', + GG: 'isoWeekYear' + }, + + camelFunctions = { + dayofyear : 'dayOfYear', + isoweekday : 'isoWeekday', + isoweek : 'isoWeek', + weekyear : 'weekYear', + isoweekyear : 'isoWeekYear' + }, + + // format function strings + formatFunctions = {}, + + // default relative time thresholds + relativeTimeThresholds = { + s: 45, // seconds to minute + m: 45, // minutes to hour + h: 22, // hours to day + d: 26, // days to month + M: 11 // months to year + }, + + // tokens to ordinalize and pad + ordinalizeTokens = 'DDD w W M D d'.split(' '), + paddedTokens = 'M D H h m s w W'.split(' '), + + formatTokenFunctions = { + M : function () { + return this.month() + 1; + }, + MMM : function (format) { + return this.localeData().monthsShort(this, format); + }, + MMMM : function (format) { + return this.localeData().months(this, format); + }, + D : function () { + return this.date(); + }, + DDD : function () { + return this.dayOfYear(); + }, + d : function () { + return this.day(); + }, + dd : function (format) { + return this.localeData().weekdaysMin(this, format); + }, + ddd : function (format) { + return this.localeData().weekdaysShort(this, format); + }, + dddd : function (format) { + return this.localeData().weekdays(this, format); + }, + w : function () { + return this.week(); + }, + W : function () { + return this.isoWeek(); + }, + YY : function () { + return leftZeroFill(this.year() % 100, 2); + }, + YYYY : function () { + return leftZeroFill(this.year(), 4); + }, + YYYYY : function () { + return leftZeroFill(this.year(), 5); + }, + YYYYYY : function () { + var y = this.year(), sign = y >= 0 ? '+' : '-'; + return sign + leftZeroFill(Math.abs(y), 6); + }, + gg : function () { + return leftZeroFill(this.weekYear() % 100, 2); + }, + gggg : function () { + return leftZeroFill(this.weekYear(), 4); + }, + ggggg : function () { + return leftZeroFill(this.weekYear(), 5); + }, + GG : function () { + return leftZeroFill(this.isoWeekYear() % 100, 2); + }, + GGGG : function () { + return leftZeroFill(this.isoWeekYear(), 4); + }, + GGGGG : function () { + return leftZeroFill(this.isoWeekYear(), 5); + }, + e : function () { + return this.weekday(); + }, + E : function () { + return this.isoWeekday(); + }, + a : function () { + return this.localeData().meridiem(this.hours(), this.minutes(), true); + }, + A : function () { + return this.localeData().meridiem(this.hours(), this.minutes(), false); + }, + H : function () { + return this.hours(); + }, + h : function () { + return this.hours() % 12 || 12; + }, + m : function () { + return this.minutes(); + }, + s : function () { + return this.seconds(); + }, + S : function () { + return toInt(this.milliseconds() / 100); + }, + SS : function () { + return leftZeroFill(toInt(this.milliseconds() / 10), 2); + }, + SSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, + SSSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, + Z : function () { + var a = this.utcOffset(), + b = '+'; + if (a < 0) { + a = -a; + b = '-'; + } + return b + leftZeroFill(toInt(a / 60), 2) + ':' + leftZeroFill(toInt(a) % 60, 2); + }, + ZZ : function () { + var a = this.utcOffset(), + b = '+'; + if (a < 0) { + a = -a; + b = '-'; + } + return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2); + }, + z : function () { + return this.zoneAbbr(); + }, + zz : function () { + return this.zoneName(); + }, + x : function () { + return this.valueOf(); + }, + X : function () { + return this.unix(); + }, + Q : function () { + return this.quarter(); + } + }, + + deprecations = {}, + + lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin'], + + updateInProgress = false; + + // Pick the first defined of two or three arguments. dfl comes from + // default. + function dfl(a, b, c) { + switch (arguments.length) { + case 2: return a != null ? a : b; + case 3: return a != null ? a : b != null ? b : c; + default: throw new Error('Implement me'); + } + } + + function hasOwnProp(a, b) { + return hasOwnProperty.call(a, b); + } + + function defaultParsingFlags() { + // We need to deep clone this object, and es5 standard is not very + // helpful. + return { + empty : false, + unusedTokens : [], + unusedInput : [], + overflow : -2, + charsLeftOver : 0, + nullInput : false, + invalidMonth : null, + invalidFormat : false, + userInvalidated : false, + iso: false + }; + } + + function printMsg(msg) { + if (moment.suppressDeprecationWarnings === false && + typeof console !== 'undefined' && console.warn) { + console.warn('Deprecation warning: ' + msg); + } + } + + function deprecate(msg, fn) { + var firstTime = true; + return extend(function () { + if (firstTime) { + printMsg(msg); + firstTime = false; + } + return fn.apply(this, arguments); + }, fn); + } + + function deprecateSimple(name, msg) { + if (!deprecations[name]) { + printMsg(msg); + deprecations[name] = true; + } + } + + function padToken(func, count) { + return function (a) { + return leftZeroFill(func.call(this, a), count); + }; + } + function ordinalizeToken(func, period) { + return function (a) { + return this.localeData().ordinal(func.call(this, a), period); + }; + } + + function monthDiff(a, b) { + // difference in months + var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()), + // b is in (anchor - 1 month, anchor + 1 month) + anchor = a.clone().add(wholeMonthDiff, 'months'), + anchor2, adjust; + + if (b - anchor < 0) { + anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor - anchor2); + } else { + anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor2 - anchor); + } + + return -(wholeMonthDiff + adjust); + } + + while (ordinalizeTokens.length) { + i = ordinalizeTokens.pop(); + formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i); + } + while (paddedTokens.length) { + i = paddedTokens.pop(); + formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); + } + formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); + + + function meridiemFixWrap(locale, hour, meridiem) { + var isPm; + + if (meridiem == null) { + // nothing to do + return hour; + } + if (locale.meridiemHour != null) { + return locale.meridiemHour(hour, meridiem); + } else if (locale.isPM != null) { + // Fallback + isPm = locale.isPM(meridiem); + if (isPm && hour < 12) { + hour += 12; + } + if (!isPm && hour === 12) { + hour = 0; + } + return hour; + } else { + // thie is not supposed to happen + return hour; + } + } + + /************************************ + Constructors + ************************************/ + + function Locale() { + } + + // Moment prototype object + function Moment(config, skipOverflow) { + if (skipOverflow !== false) { + checkOverflow(config); + } + copyConfig(this, config); + this._d = new Date(+config._d); + // Prevent infinite loop in case updateOffset creates new moment + // objects. + if (updateInProgress === false) { + updateInProgress = true; + moment.updateOffset(this); + updateInProgress = false; + } + } + + // Duration Constructor + function Duration(duration) { + var normalizedInput = normalizeObjectUnits(duration), + years = normalizedInput.year || 0, + quarters = normalizedInput.quarter || 0, + months = normalizedInput.month || 0, + weeks = normalizedInput.week || 0, + days = normalizedInput.day || 0, + hours = normalizedInput.hour || 0, + minutes = normalizedInput.minute || 0, + seconds = normalizedInput.second || 0, + milliseconds = normalizedInput.millisecond || 0; + + // representation for dateAddRemove + this._milliseconds = +milliseconds + + seconds * 1e3 + // 1000 + minutes * 6e4 + // 1000 * 60 + hours * 36e5; // 1000 * 60 * 60 + // Because of dateAddRemove treats 24 hours as different from a + // day when working around DST, we need to store them separately + this._days = +days + + weeks * 7; + // It is impossible translate months into days without knowing + // which months you are are talking about, so we have to store + // it separately. + this._months = +months + + quarters * 3 + + years * 12; + + this._data = {}; + + this._locale = moment.localeData(); + + this._bubble(); + } + + /************************************ + Helpers + ************************************/ + + + function extend(a, b) { + for (var i in b) { + if (hasOwnProp(b, i)) { + a[i] = b[i]; + } + } + + if (hasOwnProp(b, 'toString')) { + a.toString = b.toString; + } + + if (hasOwnProp(b, 'valueOf')) { + a.valueOf = b.valueOf; + } + + return a; + } + + function copyConfig(to, from) { + var i, prop, val; + + if (typeof from._isAMomentObject !== 'undefined') { + to._isAMomentObject = from._isAMomentObject; + } + if (typeof from._i !== 'undefined') { + to._i = from._i; + } + if (typeof from._f !== 'undefined') { + to._f = from._f; + } + if (typeof from._l !== 'undefined') { + to._l = from._l; + } + if (typeof from._strict !== 'undefined') { + to._strict = from._strict; + } + if (typeof from._tzm !== 'undefined') { + to._tzm = from._tzm; + } + if (typeof from._isUTC !== 'undefined') { + to._isUTC = from._isUTC; + } + if (typeof from._offset !== 'undefined') { + to._offset = from._offset; + } + if (typeof from._pf !== 'undefined') { + to._pf = from._pf; + } + if (typeof from._locale !== 'undefined') { + to._locale = from._locale; + } + + if (momentProperties.length > 0) { + for (i in momentProperties) { + prop = momentProperties[i]; + val = from[prop]; + if (typeof val !== 'undefined') { + to[prop] = val; + } + } + } + + return to; + } + + function absRound(number) { + if (number < 0) { + return Math.ceil(number); + } else { + return Math.floor(number); + } + } + + // left zero fill a number + // see http://jsperf.com/left-zero-filling for performance comparison + function leftZeroFill(number, targetLength, forceSign) { + var output = '' + Math.abs(number), + sign = number >= 0; + + while (output.length < targetLength) { + output = '0' + output; + } + return (sign ? (forceSign ? '+' : '') : '-') + output; + } + + function positiveMomentsDifference(base, other) { + var res = {milliseconds: 0, months: 0}; + + res.months = other.month() - base.month() + + (other.year() - base.year()) * 12; + if (base.clone().add(res.months, 'M').isAfter(other)) { + --res.months; + } + + res.milliseconds = +other - +(base.clone().add(res.months, 'M')); + + return res; + } + + function momentsDifference(base, other) { + var res; + other = makeAs(other, base); + if (base.isBefore(other)) { + res = positiveMomentsDifference(base, other); + } else { + res = positiveMomentsDifference(other, base); + res.milliseconds = -res.milliseconds; + res.months = -res.months; + } + + return res; + } + + // TODO: remove 'name' arg after deprecation is removed + function createAdder(direction, name) { + return function (val, period) { + var dur, tmp; + //invert the arguments, but complain about it + if (period !== null && !isNaN(+period)) { + deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period).'); + tmp = val; val = period; period = tmp; + } + + val = typeof val === 'string' ? +val : val; + dur = moment.duration(val, period); + addOrSubtractDurationFromMoment(this, dur, direction); + return this; + }; + } + + function addOrSubtractDurationFromMoment(mom, duration, isAdding, updateOffset) { + var milliseconds = duration._milliseconds, + days = duration._days, + months = duration._months; + updateOffset = updateOffset == null ? true : updateOffset; + + if (milliseconds) { + mom._d.setTime(+mom._d + milliseconds * isAdding); + } + if (days) { + rawSetter(mom, 'Date', rawGetter(mom, 'Date') + days * isAdding); + } + if (months) { + rawMonthSetter(mom, rawGetter(mom, 'Month') + months * isAdding); + } + if (updateOffset) { + moment.updateOffset(mom, days || months); + } + } + + // check if is an array + function isArray(input) { + return Object.prototype.toString.call(input) === '[object Array]'; + } + + function isDate(input) { + return Object.prototype.toString.call(input) === '[object Date]' || + input instanceof Date; + } + + // compare two arrays, return the number of differences + function compareArrays(array1, array2, dontConvert) { + var len = Math.min(array1.length, array2.length), + lengthDiff = Math.abs(array1.length - array2.length), + diffs = 0, + i; + for (i = 0; i < len; i++) { + if ((dontConvert && array1[i] !== array2[i]) || + (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { + diffs++; + } + } + return diffs + lengthDiff; + } + + function normalizeUnits(units) { + if (units) { + var lowered = units.toLowerCase().replace(/(.)s$/, '$1'); + units = unitAliases[units] || camelFunctions[lowered] || lowered; + } + return units; + } + + function normalizeObjectUnits(inputObject) { + var normalizedInput = {}, + normalizedProp, + prop; + + for (prop in inputObject) { + if (hasOwnProp(inputObject, prop)) { + normalizedProp = normalizeUnits(prop); + if (normalizedProp) { + normalizedInput[normalizedProp] = inputObject[prop]; + } + } + } + + return normalizedInput; + } + + function makeList(field) { + var count, setter; + + if (field.indexOf('week') === 0) { + count = 7; + setter = 'day'; + } + else if (field.indexOf('month') === 0) { + count = 12; + setter = 'month'; + } + else { + return; + } + + moment[field] = function (format, index) { + var i, getter, + method = moment._locale[field], + results = []; + + if (typeof format === 'number') { + index = format; + format = undefined; + } + + getter = function (i) { + var m = moment().utc().set(setter, i); + return method.call(moment._locale, m, format || ''); + }; + + if (index != null) { + return getter(index); + } + else { + for (i = 0; i < count; i++) { + results.push(getter(i)); + } + return results; + } + }; + } + + function toInt(argumentForCoercion) { + var coercedNumber = +argumentForCoercion, + value = 0; + + if (coercedNumber !== 0 && isFinite(coercedNumber)) { + if (coercedNumber >= 0) { + value = Math.floor(coercedNumber); + } else { + value = Math.ceil(coercedNumber); + } + } + + return value; + } + + function daysInMonth(year, month) { + return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); + } + + function weeksInYear(year, dow, doy) { + return weekOfYear(moment([year, 11, 31 + dow - doy]), dow, doy).week; + } + + function daysInYear(year) { + return isLeapYear(year) ? 366 : 365; + } + + function isLeapYear(year) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; + } + + function checkOverflow(m) { + var overflow; + if (m._a && m._pf.overflow === -2) { + overflow = + m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH : + m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE : + m._a[HOUR] < 0 || m._a[HOUR] > 24 || + (m._a[HOUR] === 24 && (m._a[MINUTE] !== 0 || + m._a[SECOND] !== 0 || + m._a[MILLISECOND] !== 0)) ? HOUR : + m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE : + m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND : + m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND : + -1; + + if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { + overflow = DATE; + } + + m._pf.overflow = overflow; + } + } + + function isValid(m) { + if (m._isValid == null) { + m._isValid = !isNaN(m._d.getTime()) && + m._pf.overflow < 0 && + !m._pf.empty && + !m._pf.invalidMonth && + !m._pf.nullInput && + !m._pf.invalidFormat && + !m._pf.userInvalidated; + + if (m._strict) { + m._isValid = m._isValid && + m._pf.charsLeftOver === 0 && + m._pf.unusedTokens.length === 0 && + m._pf.bigHour === undefined; + } + } + return m._isValid; + } + + function normalizeLocale(key) { + return key ? key.toLowerCase().replace('_', '-') : key; + } + + // pick the locale from the array + // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each + // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root + function chooseLocale(names) { + var i = 0, j, next, locale, split; + + while (i < names.length) { + split = normalizeLocale(names[i]).split('-'); + j = split.length; + next = normalizeLocale(names[i + 1]); + next = next ? next.split('-') : null; + while (j > 0) { + locale = loadLocale(split.slice(0, j).join('-')); + if (locale) { + return locale; + } + if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) { + //the next array item is better than a shallower substring of this one + break; + } + j--; + } + i++; + } + return null; + } + + function loadLocale(name) { + var oldLocale = null; + if (!locales[name] && hasModule) { + try { + oldLocale = moment.locale(); + require('./locale/' + name); + // because defineLocale currently also sets the global locale, we want to undo that for lazy loaded locales + moment.locale(oldLocale); + } catch (e) { } + } + return locales[name]; + } + + // Return a moment from input, that is local/utc/utcOffset equivalent to + // model. + function makeAs(input, model) { + var res, diff; + if (model._isUTC) { + res = model.clone(); + diff = (moment.isMoment(input) || isDate(input) ? + +input : +moment(input)) - (+res); + // Use low-level api, because this fn is low-level api. + res._d.setTime(+res._d + diff); + moment.updateOffset(res, false); + return res; + } else { + return moment(input).local(); + } + } + + /************************************ + Locale + ************************************/ + + + extend(Locale.prototype, { + + set : function (config) { + var prop, i; + for (i in config) { + prop = config[i]; + if (typeof prop === 'function') { + this[i] = prop; + } else { + this['_' + i] = prop; + } + } + // Lenient ordinal parsing accepts just a number in addition to + // number + (possibly) stuff coming from _ordinalParseLenient. + this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + /\d{1,2}/.source); + }, + + _months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), + months : function (m) { + return this._months[m.month()]; + }, + + _monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), + monthsShort : function (m) { + return this._monthsShort[m.month()]; + }, + + monthsParse : function (monthName, format, strict) { + var i, mom, regex; + + if (!this._monthsParse) { + this._monthsParse = []; + this._longMonthsParse = []; + this._shortMonthsParse = []; + } + + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + mom = moment.utc([2000, i]); + if (strict && !this._longMonthsParse[i]) { + this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i'); + this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i'); + } + if (!strict && !this._monthsParse[i]) { + regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); + this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) { + return i; + } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) { + return i; + } else if (!strict && this._monthsParse[i].test(monthName)) { + return i; + } + } + }, + + _weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), + weekdays : function (m) { + return this._weekdays[m.day()]; + }, + + _weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), + weekdaysShort : function (m) { + return this._weekdaysShort[m.day()]; + }, + + _weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), + weekdaysMin : function (m) { + return this._weekdaysMin[m.day()]; + }, + + weekdaysParse : function (weekdayName) { + var i, mom, regex; + + if (!this._weekdaysParse) { + this._weekdaysParse = []; + } + + for (i = 0; i < 7; i++) { + // make the regex if we don't have it already + if (!this._weekdaysParse[i]) { + mom = moment([2000, 1]).day(i); + regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); + this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (this._weekdaysParse[i].test(weekdayName)) { + return i; + } + } + }, + + _longDateFormat : { + LTS : 'h:mm:ss A', + LT : 'h:mm A', + L : 'MM/DD/YYYY', + LL : 'MMMM D, YYYY', + LLL : 'MMMM D, YYYY LT', + LLLL : 'dddd, MMMM D, YYYY LT' + }, + longDateFormat : function (key) { + var output = this._longDateFormat[key]; + if (!output && this._longDateFormat[key.toUpperCase()]) { + output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { + return val.slice(1); + }); + this._longDateFormat[key] = output; + } + return output; + }, + + isPM : function (input) { + // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays + // Using charAt should be more compatible. + return ((input + '').toLowerCase().charAt(0) === 'p'); + }, + + _meridiemParse : /[ap]\.?m?\.?/i, + meridiem : function (hours, minutes, isLower) { + if (hours > 11) { + return isLower ? 'pm' : 'PM'; + } else { + return isLower ? 'am' : 'AM'; + } + }, + + + _calendar : { + sameDay : '[Today at] LT', + nextDay : '[Tomorrow at] LT', + nextWeek : 'dddd [at] LT', + lastDay : '[Yesterday at] LT', + lastWeek : '[Last] dddd [at] LT', + sameElse : 'L' + }, + calendar : function (key, mom, now) { + var output = this._calendar[key]; + return typeof output === 'function' ? output.apply(mom, [now]) : output; + }, + + _relativeTime : { + future : 'in %s', + past : '%s ago', + s : 'a few seconds', + m : 'a minute', + mm : '%d minutes', + h : 'an hour', + hh : '%d hours', + d : 'a day', + dd : '%d days', + M : 'a month', + MM : '%d months', + y : 'a year', + yy : '%d years' + }, + + relativeTime : function (number, withoutSuffix, string, isFuture) { + var output = this._relativeTime[string]; + return (typeof output === 'function') ? + output(number, withoutSuffix, string, isFuture) : + output.replace(/%d/i, number); + }, + + pastFuture : function (diff, output) { + var format = this._relativeTime[diff > 0 ? 'future' : 'past']; + return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); + }, + + ordinal : function (number) { + return this._ordinal.replace('%d', number); + }, + _ordinal : '%d', + _ordinalParse : /\d{1,2}/, + + preparse : function (string) { + return string; + }, + + postformat : function (string) { + return string; + }, + + week : function (mom) { + return weekOfYear(mom, this._week.dow, this._week.doy).week; + }, + + _week : { + dow : 0, // Sunday is the first day of the week. + doy : 6 // The week that contains Jan 1st is the first week of the year. + }, + + firstDayOfWeek : function () { + return this._week.dow; + }, + + firstDayOfYear : function () { + return this._week.doy; + }, + + _invalidDate: 'Invalid date', + invalidDate: function () { + return this._invalidDate; + } + }); + + /************************************ + Formatting + ************************************/ + + + function removeFormattingTokens(input) { + if (input.match(/\[[\s\S]/)) { + return input.replace(/^\[|\]$/g, ''); + } + return input.replace(/\\/g, ''); + } + + function makeFormatFunction(format) { + var array = format.match(formattingTokens), i, length; + + for (i = 0, length = array.length; i < length; i++) { + if (formatTokenFunctions[array[i]]) { + array[i] = formatTokenFunctions[array[i]]; + } else { + array[i] = removeFormattingTokens(array[i]); + } + } + + return function (mom) { + var output = ''; + for (i = 0; i < length; i++) { + output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; + } + return output; + }; + } + + // format date using native date object + function formatMoment(m, format) { + if (!m.isValid()) { + return m.localeData().invalidDate(); + } + + format = expandFormat(format, m.localeData()); + + if (!formatFunctions[format]) { + formatFunctions[format] = makeFormatFunction(format); + } + + return formatFunctions[format](m); + } + + function expandFormat(format, locale) { + var i = 5; + + function replaceLongDateFormatTokens(input) { + return locale.longDateFormat(input) || input; + } + + localFormattingTokens.lastIndex = 0; + while (i >= 0 && localFormattingTokens.test(format)) { + format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); + localFormattingTokens.lastIndex = 0; + i -= 1; + } + + return format; + } + + + /************************************ + Parsing + ************************************/ + + + // get the regex to find the next token + function getParseRegexForToken(token, config) { + var a, strict = config._strict; + switch (token) { + case 'Q': + return parseTokenOneDigit; + case 'DDDD': + return parseTokenThreeDigits; + case 'YYYY': + case 'GGGG': + case 'gggg': + return strict ? parseTokenFourDigits : parseTokenOneToFourDigits; + case 'Y': + case 'G': + case 'g': + return parseTokenSignedNumber; + case 'YYYYYY': + case 'YYYYY': + case 'GGGGG': + case 'ggggg': + return strict ? parseTokenSixDigits : parseTokenOneToSixDigits; + case 'S': + if (strict) { + return parseTokenOneDigit; + } + /* falls through */ + case 'SS': + if (strict) { + return parseTokenTwoDigits; + } + /* falls through */ + case 'SSS': + if (strict) { + return parseTokenThreeDigits; + } + /* falls through */ + case 'DDD': + return parseTokenOneToThreeDigits; + case 'MMM': + case 'MMMM': + case 'dd': + case 'ddd': + case 'dddd': + return parseTokenWord; + case 'a': + case 'A': + return config._locale._meridiemParse; + case 'x': + return parseTokenOffsetMs; + case 'X': + return parseTokenTimestampMs; + case 'Z': + case 'ZZ': + return parseTokenTimezone; + case 'T': + return parseTokenT; + case 'SSSS': + return parseTokenDigits; + case 'MM': + case 'DD': + case 'YY': + case 'GG': + case 'gg': + case 'HH': + case 'hh': + case 'mm': + case 'ss': + case 'ww': + case 'WW': + return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits; + case 'M': + case 'D': + case 'd': + case 'H': + case 'h': + case 'm': + case 's': + case 'w': + case 'W': + case 'e': + case 'E': + return parseTokenOneOrTwoDigits; + case 'Do': + return strict ? config._locale._ordinalParse : config._locale._ordinalParseLenient; + default : + a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), 'i')); + return a; + } + } + + function utcOffsetFromString(string) { + string = string || ''; + var possibleTzMatches = (string.match(parseTokenTimezone) || []), + tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [], + parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0], + minutes = +(parts[1] * 60) + toInt(parts[2]); + + return parts[0] === '+' ? minutes : -minutes; + } + + // function to convert string input to date + function addTimeToArrayFromToken(token, input, config) { + var a, datePartArray = config._a; + + switch (token) { + // QUARTER + case 'Q': + if (input != null) { + datePartArray[MONTH] = (toInt(input) - 1) * 3; + } + break; + // MONTH + case 'M' : // fall through to MM + case 'MM' : + if (input != null) { + datePartArray[MONTH] = toInt(input) - 1; + } + break; + case 'MMM' : // fall through to MMMM + case 'MMMM' : + a = config._locale.monthsParse(input, token, config._strict); + // if we didn't find a month name, mark the date as invalid. + if (a != null) { + datePartArray[MONTH] = a; + } else { + config._pf.invalidMonth = input; + } + break; + // DAY OF MONTH + case 'D' : // fall through to DD + case 'DD' : + if (input != null) { + datePartArray[DATE] = toInt(input); + } + break; + case 'Do' : + if (input != null) { + datePartArray[DATE] = toInt(parseInt( + input.match(/\d{1,2}/)[0], 10)); + } + break; + // DAY OF YEAR + case 'DDD' : // fall through to DDDD + case 'DDDD' : + if (input != null) { + config._dayOfYear = toInt(input); + } + + break; + // YEAR + case 'YY' : + datePartArray[YEAR] = moment.parseTwoDigitYear(input); + break; + case 'YYYY' : + case 'YYYYY' : + case 'YYYYYY' : + datePartArray[YEAR] = toInt(input); + break; + // AM / PM + case 'a' : // fall through to A + case 'A' : + config._meridiem = input; + // config._isPm = config._locale.isPM(input); + break; + // HOUR + case 'h' : // fall through to hh + case 'hh' : + config._pf.bigHour = true; + /* falls through */ + case 'H' : // fall through to HH + case 'HH' : + datePartArray[HOUR] = toInt(input); + break; + // MINUTE + case 'm' : // fall through to mm + case 'mm' : + datePartArray[MINUTE] = toInt(input); + break; + // SECOND + case 's' : // fall through to ss + case 'ss' : + datePartArray[SECOND] = toInt(input); + break; + // MILLISECOND + case 'S' : + case 'SS' : + case 'SSS' : + case 'SSSS' : + datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000); + break; + // UNIX OFFSET (MILLISECONDS) + case 'x': + config._d = new Date(toInt(input)); + break; + // UNIX TIMESTAMP WITH MS + case 'X': + config._d = new Date(parseFloat(input) * 1000); + break; + // TIMEZONE + case 'Z' : // fall through to ZZ + case 'ZZ' : + config._useUTC = true; + config._tzm = utcOffsetFromString(input); + break; + // WEEKDAY - human + case 'dd': + case 'ddd': + case 'dddd': + a = config._locale.weekdaysParse(input); + // if we didn't get a weekday name, mark the date as invalid + if (a != null) { + config._w = config._w || {}; + config._w['d'] = a; + } else { + config._pf.invalidWeekday = input; + } + break; + // WEEK, WEEK DAY - numeric + case 'w': + case 'ww': + case 'W': + case 'WW': + case 'd': + case 'e': + case 'E': + token = token.substr(0, 1); + /* falls through */ + case 'gggg': + case 'GGGG': + case 'GGGGG': + token = token.substr(0, 2); + if (input) { + config._w = config._w || {}; + config._w[token] = toInt(input); + } + break; + case 'gg': + case 'GG': + config._w = config._w || {}; + config._w[token] = moment.parseTwoDigitYear(input); + } + } + + function dayOfYearFromWeekInfo(config) { + var w, weekYear, week, weekday, dow, doy, temp; + + w = config._w; + if (w.GG != null || w.W != null || w.E != null) { + dow = 1; + doy = 4; + + // TODO: We need to take the current isoWeekYear, but that depends on + // how we interpret now (local, utc, fixed offset). So create + // a now version of current config (take local/utc/offset flags, and + // create now). + weekYear = dfl(w.GG, config._a[YEAR], weekOfYear(moment(), 1, 4).year); + week = dfl(w.W, 1); + weekday = dfl(w.E, 1); + } else { + dow = config._locale._week.dow; + doy = config._locale._week.doy; + + weekYear = dfl(w.gg, config._a[YEAR], weekOfYear(moment(), dow, doy).year); + week = dfl(w.w, 1); + + if (w.d != null) { + // weekday -- low day numbers are considered next week + weekday = w.d; + if (weekday < dow) { + ++week; + } + } else if (w.e != null) { + // local weekday -- counting starts from begining of week + weekday = w.e + dow; + } else { + // default to begining of week + weekday = dow; + } + } + temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow); + + config._a[YEAR] = temp.year; + config._dayOfYear = temp.dayOfYear; + } + + // convert an array to a date. + // the array should mirror the parameters below + // note: all values past the year are optional and will default to the lowest possible value. + // [year, month, day , hour, minute, second, millisecond] + function dateFromConfig(config) { + var i, date, input = [], currentDate, yearToUse; + + if (config._d) { + return; + } + + currentDate = currentDateArray(config); + + //compute day of the year from weeks and weekdays + if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { + dayOfYearFromWeekInfo(config); + } + + //if the day of the year is set, figure out what it is + if (config._dayOfYear) { + yearToUse = dfl(config._a[YEAR], currentDate[YEAR]); + + if (config._dayOfYear > daysInYear(yearToUse)) { + config._pf._overflowDayOfYear = true; + } + + date = makeUTCDate(yearToUse, 0, config._dayOfYear); + config._a[MONTH] = date.getUTCMonth(); + config._a[DATE] = date.getUTCDate(); + } + + // Default to current date. + // * if no year, month, day of month are given, default to today + // * if day of month is given, default month and year + // * if month is given, default only year + // * if year is given, don't default anything + for (i = 0; i < 3 && config._a[i] == null; ++i) { + config._a[i] = input[i] = currentDate[i]; + } + + // Zero out whatever was not defaulted, including time + for (; i < 7; i++) { + config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; + } + + // Check for 24:00:00.000 + if (config._a[HOUR] === 24 && + config._a[MINUTE] === 0 && + config._a[SECOND] === 0 && + config._a[MILLISECOND] === 0) { + config._nextDay = true; + config._a[HOUR] = 0; + } + + config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input); + // Apply timezone offset from input. The actual utcOffset can be changed + // with parseZone. + if (config._tzm != null) { + config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); + } + + if (config._nextDay) { + config._a[HOUR] = 24; + } + } + + function dateFromObject(config) { + var normalizedInput; + + if (config._d) { + return; + } + + normalizedInput = normalizeObjectUnits(config._i); + config._a = [ + normalizedInput.year, + normalizedInput.month, + normalizedInput.day || normalizedInput.date, + normalizedInput.hour, + normalizedInput.minute, + normalizedInput.second, + normalizedInput.millisecond + ]; + + dateFromConfig(config); + } + + function currentDateArray(config) { + var now = new Date(); + if (config._useUTC) { + return [ + now.getUTCFullYear(), + now.getUTCMonth(), + now.getUTCDate() + ]; + } else { + return [now.getFullYear(), now.getMonth(), now.getDate()]; + } + } + + // date from string and format string + function makeDateFromStringAndFormat(config) { + if (config._f === moment.ISO_8601) { + parseISO(config); + return; + } + + config._a = []; + config._pf.empty = true; + + // This array is used to make a Date, either with `new Date` or `Date.UTC` + var string = '' + config._i, + i, parsedInput, tokens, token, skipped, + stringLength = string.length, + totalParsedInputLength = 0; + + tokens = expandFormat(config._f, config._locale).match(formattingTokens) || []; + + for (i = 0; i < tokens.length; i++) { + token = tokens[i]; + parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; + if (parsedInput) { + skipped = string.substr(0, string.indexOf(parsedInput)); + if (skipped.length > 0) { + config._pf.unusedInput.push(skipped); + } + string = string.slice(string.indexOf(parsedInput) + parsedInput.length); + totalParsedInputLength += parsedInput.length; + } + // don't parse if it's not a known token + if (formatTokenFunctions[token]) { + if (parsedInput) { + config._pf.empty = false; + } + else { + config._pf.unusedTokens.push(token); + } + addTimeToArrayFromToken(token, parsedInput, config); + } + else if (config._strict && !parsedInput) { + config._pf.unusedTokens.push(token); + } + } + + // add remaining unparsed input length to the string + config._pf.charsLeftOver = stringLength - totalParsedInputLength; + if (string.length > 0) { + config._pf.unusedInput.push(string); + } + + // clear _12h flag if hour is <= 12 + if (config._pf.bigHour === true && config._a[HOUR] <= 12) { + config._pf.bigHour = undefined; + } + // handle meridiem + config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], + config._meridiem); + dateFromConfig(config); + checkOverflow(config); + } + + function unescapeFormat(s) { + return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { + return p1 || p2 || p3 || p4; + }); + } + + // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript + function regexpEscape(s) { + return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + } + + // date from string and array of format strings + function makeDateFromStringAndArray(config) { + var tempConfig, + bestMoment, + + scoreToBeat, + i, + currentScore; + + if (config._f.length === 0) { + config._pf.invalidFormat = true; + config._d = new Date(NaN); + return; + } + + for (i = 0; i < config._f.length; i++) { + currentScore = 0; + tempConfig = copyConfig({}, config); + if (config._useUTC != null) { + tempConfig._useUTC = config._useUTC; + } + tempConfig._pf = defaultParsingFlags(); + tempConfig._f = config._f[i]; + makeDateFromStringAndFormat(tempConfig); + + if (!isValid(tempConfig)) { + continue; + } + + // if there is any input that was not parsed add a penalty for that format + currentScore += tempConfig._pf.charsLeftOver; + + //or tokens + currentScore += tempConfig._pf.unusedTokens.length * 10; + + tempConfig._pf.score = currentScore; + + if (scoreToBeat == null || currentScore < scoreToBeat) { + scoreToBeat = currentScore; + bestMoment = tempConfig; + } + } + + extend(config, bestMoment || tempConfig); + } + + // date from iso format + function parseISO(config) { + var i, l, + string = config._i, + match = isoRegex.exec(string); + + if (match) { + config._pf.iso = true; + for (i = 0, l = isoDates.length; i < l; i++) { + if (isoDates[i][1].exec(string)) { + // match[5] should be 'T' or undefined + config._f = isoDates[i][0] + (match[6] || ' '); + break; + } + } + for (i = 0, l = isoTimes.length; i < l; i++) { + if (isoTimes[i][1].exec(string)) { + config._f += isoTimes[i][0]; + break; + } + } + if (string.match(parseTokenTimezone)) { + config._f += 'Z'; + } + makeDateFromStringAndFormat(config); + } else { + config._isValid = false; + } + } + + // date from iso format or fallback + function makeDateFromString(config) { + parseISO(config); + if (config._isValid === false) { + delete config._isValid; + moment.createFromInputFallback(config); + } + } + + function map(arr, fn) { + var res = [], i; + for (i = 0; i < arr.length; ++i) { + res.push(fn(arr[i], i)); + } + return res; + } + + function makeDateFromInput(config) { + var input = config._i, matched; + if (input === undefined) { + config._d = new Date(); + } else if (isDate(input)) { + config._d = new Date(+input); + } else if ((matched = aspNetJsonRegex.exec(input)) !== null) { + config._d = new Date(+matched[1]); + } else if (typeof input === 'string') { + makeDateFromString(config); + } else if (isArray(input)) { + config._a = map(input.slice(0), function (obj) { + return parseInt(obj, 10); + }); + dateFromConfig(config); + } else if (typeof(input) === 'object') { + dateFromObject(config); + } else if (typeof(input) === 'number') { + // from milliseconds + config._d = new Date(input); + } else { + moment.createFromInputFallback(config); + } + } + + function makeDate(y, m, d, h, M, s, ms) { + //can't just apply() to create a date: + //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply + var date = new Date(y, m, d, h, M, s, ms); + + //the date constructor doesn't accept years < 1970 + if (y < 1970) { + date.setFullYear(y); + } + return date; + } + + function makeUTCDate(y) { + var date = new Date(Date.UTC.apply(null, arguments)); + if (y < 1970) { + date.setUTCFullYear(y); + } + return date; + } + + function parseWeekday(input, locale) { + if (typeof input === 'string') { + if (!isNaN(input)) { + input = parseInt(input, 10); + } + else { + input = locale.weekdaysParse(input); + if (typeof input !== 'number') { + return null; + } + } + } + return input; + } + + /************************************ + Relative Time + ************************************/ + + + // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize + function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { + return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); + } + + function relativeTime(posNegDuration, withoutSuffix, locale) { + var duration = moment.duration(posNegDuration).abs(), + seconds = round(duration.as('s')), + minutes = round(duration.as('m')), + hours = round(duration.as('h')), + days = round(duration.as('d')), + months = round(duration.as('M')), + years = round(duration.as('y')), + + args = seconds < relativeTimeThresholds.s && ['s', seconds] || + minutes === 1 && ['m'] || + minutes < relativeTimeThresholds.m && ['mm', minutes] || + hours === 1 && ['h'] || + hours < relativeTimeThresholds.h && ['hh', hours] || + days === 1 && ['d'] || + days < relativeTimeThresholds.d && ['dd', days] || + months === 1 && ['M'] || + months < relativeTimeThresholds.M && ['MM', months] || + years === 1 && ['y'] || ['yy', years]; + + args[2] = withoutSuffix; + args[3] = +posNegDuration > 0; + args[4] = locale; + return substituteTimeAgo.apply({}, args); + } + + + /************************************ + Week of Year + ************************************/ + + + // firstDayOfWeek 0 = sun, 6 = sat + // the day of the week that starts the week + // (usually sunday or monday) + // firstDayOfWeekOfYear 0 = sun, 6 = sat + // the first week is the week that contains the first + // of this day of the week + // (eg. ISO weeks use thursday (4)) + function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { + var end = firstDayOfWeekOfYear - firstDayOfWeek, + daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), + adjustedMoment; + + + if (daysToDayOfWeek > end) { + daysToDayOfWeek -= 7; + } + + if (daysToDayOfWeek < end - 7) { + daysToDayOfWeek += 7; + } + + adjustedMoment = moment(mom).add(daysToDayOfWeek, 'd'); + return { + week: Math.ceil(adjustedMoment.dayOfYear() / 7), + year: adjustedMoment.year() + }; + } + + //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday + function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { + var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear; + + d = d === 0 ? 7 : d; + weekday = weekday != null ? weekday : firstDayOfWeek; + daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0); + dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1; + + return { + year: dayOfYear > 0 ? year : year - 1, + dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear + }; + } + + /************************************ + Top Level Functions + ************************************/ + + function makeMoment(config) { + var input = config._i, + format = config._f, + res; + + config._locale = config._locale || moment.localeData(config._l); + + if (input === null || (format === undefined && input === '')) { + return moment.invalid({nullInput: true}); + } + + if (typeof input === 'string') { + config._i = input = config._locale.preparse(input); + } + + if (moment.isMoment(input)) { + return new Moment(input, true); + } else if (format) { + if (isArray(format)) { + makeDateFromStringAndArray(config); + } else { + makeDateFromStringAndFormat(config); + } + } else { + makeDateFromInput(config); + } + + res = new Moment(config); + if (res._nextDay) { + // Adding is smart enough around DST + res.add(1, 'd'); + res._nextDay = undefined; + } + + return res; + } + + moment = function (input, format, locale, strict) { + var c; + + if (typeof(locale) === 'boolean') { + strict = locale; + locale = undefined; + } + // object construction must be done this way. + // https://github.com/moment/moment/issues/1423 + c = {}; + c._isAMomentObject = true; + c._i = input; + c._f = format; + c._l = locale; + c._strict = strict; + c._isUTC = false; + c._pf = defaultParsingFlags(); + + return makeMoment(c); + }; + + moment.suppressDeprecationWarnings = false; + + moment.createFromInputFallback = deprecate( + 'moment construction falls back to js Date. This is ' + + 'discouraged and will be removed in upcoming major ' + + 'release. Please refer to ' + + 'https://github.com/moment/moment/issues/1407 for more info.', + function (config) { + config._d = new Date(config._i + (config._useUTC ? ' UTC' : '')); + } + ); + + // Pick a moment m from moments so that m[fn](other) is true for all + // other. This relies on the function fn to be transitive. + // + // moments should either be an array of moment objects or an array, whose + // first element is an array of moment objects. + function pickBy(fn, moments) { + var res, i; + if (moments.length === 1 && isArray(moments[0])) { + moments = moments[0]; + } + if (!moments.length) { + return moment(); + } + res = moments[0]; + for (i = 1; i < moments.length; ++i) { + if (moments[i][fn](res)) { + res = moments[i]; + } + } + return res; + } + + moment.min = function () { + var args = [].slice.call(arguments, 0); + + return pickBy('isBefore', args); + }; + + moment.max = function () { + var args = [].slice.call(arguments, 0); + + return pickBy('isAfter', args); + }; + + // creating with utc + moment.utc = function (input, format, locale, strict) { + var c; + + if (typeof(locale) === 'boolean') { + strict = locale; + locale = undefined; + } + // object construction must be done this way. + // https://github.com/moment/moment/issues/1423 + c = {}; + c._isAMomentObject = true; + c._useUTC = true; + c._isUTC = true; + c._l = locale; + c._i = input; + c._f = format; + c._strict = strict; + c._pf = defaultParsingFlags(); + + return makeMoment(c).utc(); + }; + + // creating with unix timestamp (in seconds) + moment.unix = function (input) { + return moment(input * 1000); + }; + + // duration + moment.duration = function (input, key) { + var duration = input, + // matching against regexp is expensive, do it on demand + match = null, + sign, + ret, + parseIso, + diffRes; + + if (moment.isDuration(input)) { + duration = { + ms: input._milliseconds, + d: input._days, + M: input._months + }; + } else if (typeof input === 'number') { + duration = {}; + if (key) { + duration[key] = input; + } else { + duration.milliseconds = input; + } + } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) { + sign = (match[1] === '-') ? -1 : 1; + duration = { + y: 0, + d: toInt(match[DATE]) * sign, + h: toInt(match[HOUR]) * sign, + m: toInt(match[MINUTE]) * sign, + s: toInt(match[SECOND]) * sign, + ms: toInt(match[MILLISECOND]) * sign + }; + } else if (!!(match = isoDurationRegex.exec(input))) { + sign = (match[1] === '-') ? -1 : 1; + parseIso = function (inp) { + // We'd normally use ~~inp for this, but unfortunately it also + // converts floats to ints. + // inp may be undefined, so careful calling replace on it. + var res = inp && parseFloat(inp.replace(',', '.')); + // apply sign while we're at it + return (isNaN(res) ? 0 : res) * sign; + }; + duration = { + y: parseIso(match[2]), + M: parseIso(match[3]), + d: parseIso(match[4]), + h: parseIso(match[5]), + m: parseIso(match[6]), + s: parseIso(match[7]), + w: parseIso(match[8]) + }; + } else if (duration == null) {// checks for null or undefined + duration = {}; + } else if (typeof duration === 'object' && + ('from' in duration || 'to' in duration)) { + diffRes = momentsDifference(moment(duration.from), moment(duration.to)); + + duration = {}; + duration.ms = diffRes.milliseconds; + duration.M = diffRes.months; + } + + ret = new Duration(duration); + + if (moment.isDuration(input) && hasOwnProp(input, '_locale')) { + ret._locale = input._locale; + } + + return ret; + }; + + // version number + moment.version = VERSION; + + // default format + moment.defaultFormat = isoFormat; + + // constant that refers to the ISO standard + moment.ISO_8601 = function () {}; + + // Plugins that add properties should also add the key here (null value), + // so we can properly clone ourselves. + moment.momentProperties = momentProperties; + + // This function will be called whenever a moment is mutated. + // It is intended to keep the offset in sync with the timezone. + moment.updateOffset = function () {}; + + // This function allows you to set a threshold for relative time strings + moment.relativeTimeThreshold = function (threshold, limit) { + if (relativeTimeThresholds[threshold] === undefined) { + return false; + } + if (limit === undefined) { + return relativeTimeThresholds[threshold]; + } + relativeTimeThresholds[threshold] = limit; + return true; + }; + + moment.lang = deprecate( + 'moment.lang is deprecated. Use moment.locale instead.', + function (key, value) { + return moment.locale(key, value); + } + ); + + // This function will load locale and then set the global locale. If + // no arguments are passed in, it will simply return the current global + // locale key. + moment.locale = function (key, values) { + var data; + if (key) { + if (typeof(values) !== 'undefined') { + data = moment.defineLocale(key, values); + } + else { + data = moment.localeData(key); + } + + if (data) { + moment.duration._locale = moment._locale = data; + } + } + + return moment._locale._abbr; + }; + + moment.defineLocale = function (name, values) { + if (values !== null) { + values.abbr = name; + if (!locales[name]) { + locales[name] = new Locale(); + } + locales[name].set(values); + + // backwards compat for now: also set the locale + moment.locale(name); + + return locales[name]; + } else { + // useful for testing + delete locales[name]; + return null; + } + }; + + moment.langData = deprecate( + 'moment.langData is deprecated. Use moment.localeData instead.', + function (key) { + return moment.localeData(key); + } + ); + + // returns locale data + moment.localeData = function (key) { + var locale; + + if (key && key._locale && key._locale._abbr) { + key = key._locale._abbr; + } + + if (!key) { + return moment._locale; + } + + if (!isArray(key)) { + //short-circuit everything else + locale = loadLocale(key); + if (locale) { + return locale; + } + key = [key]; + } + + return chooseLocale(key); + }; + + // compare moment object + moment.isMoment = function (obj) { + return obj instanceof Moment || + (obj != null && hasOwnProp(obj, '_isAMomentObject')); + }; + + // for typechecking Duration objects + moment.isDuration = function (obj) { + return obj instanceof Duration; + }; + + for (i = lists.length - 1; i >= 0; --i) { + makeList(lists[i]); + } + + moment.normalizeUnits = function (units) { + return normalizeUnits(units); + }; + + moment.invalid = function (flags) { + var m = moment.utc(NaN); + if (flags != null) { + extend(m._pf, flags); + } + else { + m._pf.userInvalidated = true; + } + + return m; + }; + + moment.parseZone = function () { + return moment.apply(null, arguments).parseZone(); + }; + + moment.parseTwoDigitYear = function (input) { + return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); + }; + + moment.isDate = isDate; + + /************************************ + Moment Prototype + ************************************/ + + + extend(moment.fn = Moment.prototype, { + + clone : function () { + return moment(this); + }, + + valueOf : function () { + return +this._d - ((this._offset || 0) * 60000); + }, + + unix : function () { + return Math.floor(+this / 1000); + }, + + toString : function () { + return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); + }, + + toDate : function () { + return this._offset ? new Date(+this) : this._d; + }, + + toISOString : function () { + var m = moment(this).utc(); + if (0 < m.year() && m.year() <= 9999) { + if ('function' === typeof Date.prototype.toISOString) { + // native implementation is ~50x faster, use it when we can + return this.toDate().toISOString(); + } else { + return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } + } else { + return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } + }, + + toArray : function () { + var m = this; + return [ + m.year(), + m.month(), + m.date(), + m.hours(), + m.minutes(), + m.seconds(), + m.milliseconds() + ]; + }, + + isValid : function () { + return isValid(this); + }, + + isDSTShifted : function () { + if (this._a) { + return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0; + } + + return false; + }, + + parsingFlags : function () { + return extend({}, this._pf); + }, + + invalidAt: function () { + return this._pf.overflow; + }, + + utc : function (keepLocalTime) { + return this.utcOffset(0, keepLocalTime); + }, + + local : function (keepLocalTime) { + if (this._isUTC) { + this.utcOffset(0, keepLocalTime); + this._isUTC = false; + + if (keepLocalTime) { + this.subtract(this._dateUtcOffset(), 'm'); + } + } + return this; + }, + + format : function (inputString) { + var output = formatMoment(this, inputString || moment.defaultFormat); + return this.localeData().postformat(output); + }, + + add : createAdder(1, 'add'), + + subtract : createAdder(-1, 'subtract'), + + diff : function (input, units, asFloat) { + var that = makeAs(input, this), + zoneDiff = (that.utcOffset() - this.utcOffset()) * 6e4, + anchor, diff, output, daysAdjust; + + units = normalizeUnits(units); + + if (units === 'year' || units === 'month' || units === 'quarter') { + output = monthDiff(this, that); + if (units === 'quarter') { + output = output / 3; + } else if (units === 'year') { + output = output / 12; + } + } else { + diff = this - that; + output = units === 'second' ? diff / 1e3 : // 1000 + units === 'minute' ? diff / 6e4 : // 1000 * 60 + units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 + units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst + units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst + diff; + } + return asFloat ? output : absRound(output); + }, + + from : function (time, withoutSuffix) { + return moment.duration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix); + }, + + fromNow : function (withoutSuffix) { + return this.from(moment(), withoutSuffix); + }, + + calendar : function (time) { + // We want to compare the start of today, vs this. + // Getting start-of-today depends on whether we're locat/utc/offset + // or not. + var now = time || moment(), + sod = makeAs(now, this).startOf('day'), + diff = this.diff(sod, 'days', true), + format = diff < -6 ? 'sameElse' : + diff < -1 ? 'lastWeek' : + diff < 0 ? 'lastDay' : + diff < 1 ? 'sameDay' : + diff < 2 ? 'nextDay' : + diff < 7 ? 'nextWeek' : 'sameElse'; + return this.format(this.localeData().calendar(format, this, moment(now))); + }, + + isLeapYear : function () { + return isLeapYear(this.year()); + }, + + isDST : function () { + return (this.utcOffset() > this.clone().month(0).utcOffset() || + this.utcOffset() > this.clone().month(5).utcOffset()); + }, + + day : function (input) { + var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); + if (input != null) { + input = parseWeekday(input, this.localeData()); + return this.add(input - day, 'd'); + } else { + return day; + } + }, + + month : makeAccessor('Month', true), + + startOf : function (units) { + units = normalizeUnits(units); + // the following switch intentionally omits break keywords + // to utilize falling through the cases. + switch (units) { + case 'year': + this.month(0); + /* falls through */ + case 'quarter': + case 'month': + this.date(1); + /* falls through */ + case 'week': + case 'isoWeek': + case 'day': + this.hours(0); + /* falls through */ + case 'hour': + this.minutes(0); + /* falls through */ + case 'minute': + this.seconds(0); + /* falls through */ + case 'second': + this.milliseconds(0); + /* falls through */ + } + + // weeks are a special case + if (units === 'week') { + this.weekday(0); + } else if (units === 'isoWeek') { + this.isoWeekday(1); + } + + // quarters are also special + if (units === 'quarter') { + this.month(Math.floor(this.month() / 3) * 3); + } + + return this; + }, + + endOf: function (units) { + units = normalizeUnits(units); + if (units === undefined || units === 'millisecond') { + return this; + } + return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms'); + }, + + isAfter: function (input, units) { + var inputMs; + units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); + if (units === 'millisecond') { + input = moment.isMoment(input) ? input : moment(input); + return +this > +input; + } else { + inputMs = moment.isMoment(input) ? +input : +moment(input); + return inputMs < +this.clone().startOf(units); + } + }, + + isBefore: function (input, units) { + var inputMs; + units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); + if (units === 'millisecond') { + input = moment.isMoment(input) ? input : moment(input); + return +this < +input; + } else { + inputMs = moment.isMoment(input) ? +input : +moment(input); + return +this.clone().endOf(units) < inputMs; + } + }, + + isBetween: function (from, to, units) { + return this.isAfter(from, units) && this.isBefore(to, units); + }, + + isSame: function (input, units) { + var inputMs; + units = normalizeUnits(units || 'millisecond'); + if (units === 'millisecond') { + input = moment.isMoment(input) ? input : moment(input); + return +this === +input; + } else { + inputMs = +moment(input); + return +(this.clone().startOf(units)) <= inputMs && inputMs <= +(this.clone().endOf(units)); + } + }, + + min: deprecate( + 'moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548', + function (other) { + other = moment.apply(null, arguments); + return other < this ? this : other; + } + ), + + max: deprecate( + 'moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548', + function (other) { + other = moment.apply(null, arguments); + return other > this ? this : other; + } + ), + + zone : deprecate( + 'moment().zone is deprecated, use moment().utcOffset instead. ' + + 'https://github.com/moment/moment/issues/1779', + function (input, keepLocalTime) { + if (input != null) { + if (typeof input !== 'string') { + input = -input; + } + + this.utcOffset(input, keepLocalTime); + + return this; + } else { + return -this.utcOffset(); + } + } + ), + + // keepLocalTime = true means only change the timezone, without + // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]--> + // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset + // +0200, so we adjust the time as needed, to be valid. + // + // Keeping the time actually adds/subtracts (one hour) + // from the actual represented time. That is why we call updateOffset + // a second time. In case it wants us to change the offset again + // _changeInProgress == true case, then we have to adjust, because + // there is no such time in the given timezone. + utcOffset : function (input, keepLocalTime) { + var offset = this._offset || 0, + localAdjust; + if (input != null) { + if (typeof input === 'string') { + input = utcOffsetFromString(input); + } + if (Math.abs(input) < 16) { + input = input * 60; + } + if (!this._isUTC && keepLocalTime) { + localAdjust = this._dateUtcOffset(); + } + this._offset = input; + this._isUTC = true; + if (localAdjust != null) { + this.add(localAdjust, 'm'); + } + if (offset !== input) { + if (!keepLocalTime || this._changeInProgress) { + addOrSubtractDurationFromMoment(this, + moment.duration(input - offset, 'm'), 1, false); + } else if (!this._changeInProgress) { + this._changeInProgress = true; + moment.updateOffset(this, true); + this._changeInProgress = null; + } + } + + return this; + } else { + return this._isUTC ? offset : this._dateUtcOffset(); + } + }, + + isLocal : function () { + return !this._isUTC; + }, + + isUtcOffset : function () { + return this._isUTC; + }, + + isUtc : function () { + return this._isUTC && this._offset === 0; + }, + + zoneAbbr : function () { + return this._isUTC ? 'UTC' : ''; + }, + + zoneName : function () { + return this._isUTC ? 'Coordinated Universal Time' : ''; + }, + + parseZone : function () { + if (this._tzm) { + this.utcOffset(this._tzm); + } else if (typeof this._i === 'string') { + this.utcOffset(utcOffsetFromString(this._i)); + } + return this; + }, + + hasAlignedHourOffset : function (input) { + if (!input) { + input = 0; + } + else { + input = moment(input).utcOffset(); + } + + return (this.utcOffset() - input) % 60 === 0; + }, + + daysInMonth : function () { + return daysInMonth(this.year(), this.month()); + }, + + dayOfYear : function (input) { + var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; + return input == null ? dayOfYear : this.add((input - dayOfYear), 'd'); + }, + + quarter : function (input) { + return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3); + }, + + weekYear : function (input) { + var year = weekOfYear(this, this.localeData()._week.dow, this.localeData()._week.doy).year; + return input == null ? year : this.add((input - year), 'y'); + }, + + isoWeekYear : function (input) { + var year = weekOfYear(this, 1, 4).year; + return input == null ? year : this.add((input - year), 'y'); + }, + + week : function (input) { + var week = this.localeData().week(this); + return input == null ? week : this.add((input - week) * 7, 'd'); + }, + + isoWeek : function (input) { + var week = weekOfYear(this, 1, 4).week; + return input == null ? week : this.add((input - week) * 7, 'd'); + }, + + weekday : function (input) { + var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; + return input == null ? weekday : this.add(input - weekday, 'd'); + }, + + isoWeekday : function (input) { + // behaves the same as moment#day except + // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) + // as a setter, sunday should belong to the previous week. + return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); + }, + + isoWeeksInYear : function () { + return weeksInYear(this.year(), 1, 4); + }, + + weeksInYear : function () { + var weekInfo = this.localeData()._week; + return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); + }, + + get : function (units) { + units = normalizeUnits(units); + return this[units](); + }, + + set : function (units, value) { + var unit; + if (typeof units === 'object') { + for (unit in units) { + this.set(unit, units[unit]); + } + } + else { + units = normalizeUnits(units); + if (typeof this[units] === 'function') { + this[units](value); + } + } + return this; + }, + + // If passed a locale key, it will set the locale for this + // instance. Otherwise, it will return the locale configuration + // variables for this instance. + locale : function (key) { + var newLocaleData; + + if (key === undefined) { + return this._locale._abbr; + } else { + newLocaleData = moment.localeData(key); + if (newLocaleData != null) { + this._locale = newLocaleData; + } + return this; + } + }, + + lang : deprecate( + 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', + function (key) { + if (key === undefined) { + return this.localeData(); + } else { + return this.locale(key); + } + } + ), + + localeData : function () { + return this._locale; + }, + + _dateUtcOffset : function () { + // On Firefox.24 Date#getTimezoneOffset returns a floating point. + // https://github.com/moment/moment/pull/1871 + return -Math.round(this._d.getTimezoneOffset() / 15) * 15; + } + + }); + + function rawMonthSetter(mom, value) { + var dayOfMonth; + + // TODO: Move this out of here! + if (typeof value === 'string') { + value = mom.localeData().monthsParse(value); + // TODO: Another silent failure? + if (typeof value !== 'number') { + return mom; + } + } + + dayOfMonth = Math.min(mom.date(), + daysInMonth(mom.year(), value)); + mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); + return mom; + } + + function rawGetter(mom, unit) { + return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit](); + } + + function rawSetter(mom, unit, value) { + if (unit === 'Month') { + return rawMonthSetter(mom, value); + } else { + return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); + } + } + + function makeAccessor(unit, keepTime) { + return function (value) { + if (value != null) { + rawSetter(this, unit, value); + moment.updateOffset(this, keepTime); + return this; + } else { + return rawGetter(this, unit); + } + }; + } + + moment.fn.millisecond = moment.fn.milliseconds = makeAccessor('Milliseconds', false); + moment.fn.second = moment.fn.seconds = makeAccessor('Seconds', false); + moment.fn.minute = moment.fn.minutes = makeAccessor('Minutes', false); + // Setting the hour should keep the time, because the user explicitly + // specified which hour he wants. So trying to maintain the same hour (in + // a new timezone) makes sense. Adding/subtracting hours does not follow + // this rule. + moment.fn.hour = moment.fn.hours = makeAccessor('Hours', true); + // moment.fn.month is defined separately + moment.fn.date = makeAccessor('Date', true); + moment.fn.dates = deprecate('dates accessor is deprecated. Use date instead.', makeAccessor('Date', true)); + moment.fn.year = makeAccessor('FullYear', true); + moment.fn.years = deprecate('years accessor is deprecated. Use year instead.', makeAccessor('FullYear', true)); + + // add plural methods + moment.fn.days = moment.fn.day; + moment.fn.months = moment.fn.month; + moment.fn.weeks = moment.fn.week; + moment.fn.isoWeeks = moment.fn.isoWeek; + moment.fn.quarters = moment.fn.quarter; + + // add aliased format methods + moment.fn.toJSON = moment.fn.toISOString; + + // alias isUtc for dev-friendliness + moment.fn.isUTC = moment.fn.isUtc; + + /************************************ + Duration Prototype + ************************************/ + + + function daysToYears (days) { + // 400 years have 146097 days (taking into account leap year rules) + return days * 400 / 146097; + } + + function yearsToDays (years) { + // years * 365 + absRound(years / 4) - + // absRound(years / 100) + absRound(years / 400); + return years * 146097 / 400; + } + + extend(moment.duration.fn = Duration.prototype, { + + _bubble : function () { + var milliseconds = this._milliseconds, + days = this._days, + months = this._months, + data = this._data, + seconds, minutes, hours, years = 0; + + // The following code bubbles up values, see the tests for + // examples of what that means. + data.milliseconds = milliseconds % 1000; + + seconds = absRound(milliseconds / 1000); + data.seconds = seconds % 60; + + minutes = absRound(seconds / 60); + data.minutes = minutes % 60; + + hours = absRound(minutes / 60); + data.hours = hours % 24; + + days += absRound(hours / 24); + + // Accurately convert days to years, assume start from year 0. + years = absRound(daysToYears(days)); + days -= absRound(yearsToDays(years)); + + // 30 days to a month + // TODO (iskren): Use anchor date (like 1st Jan) to compute this. + months += absRound(days / 30); + days %= 30; + + // 12 months -> 1 year + years += absRound(months / 12); + months %= 12; + + data.days = days; + data.months = months; + data.years = years; + }, + + abs : function () { + this._milliseconds = Math.abs(this._milliseconds); + this._days = Math.abs(this._days); + this._months = Math.abs(this._months); + + this._data.milliseconds = Math.abs(this._data.milliseconds); + this._data.seconds = Math.abs(this._data.seconds); + this._data.minutes = Math.abs(this._data.minutes); + this._data.hours = Math.abs(this._data.hours); + this._data.months = Math.abs(this._data.months); + this._data.years = Math.abs(this._data.years); + + return this; + }, + + weeks : function () { + return absRound(this.days() / 7); + }, + + valueOf : function () { + return this._milliseconds + + this._days * 864e5 + + (this._months % 12) * 2592e6 + + toInt(this._months / 12) * 31536e6; + }, + + humanize : function (withSuffix) { + var output = relativeTime(this, !withSuffix, this.localeData()); + + if (withSuffix) { + output = this.localeData().pastFuture(+this, output); + } + + return this.localeData().postformat(output); + }, + + add : function (input, val) { + // supports only 2.0-style add(1, 's') or add(moment) + var dur = moment.duration(input, val); + + this._milliseconds += dur._milliseconds; + this._days += dur._days; + this._months += dur._months; + + this._bubble(); + + return this; + }, + + subtract : function (input, val) { + var dur = moment.duration(input, val); + + this._milliseconds -= dur._milliseconds; + this._days -= dur._days; + this._months -= dur._months; + + this._bubble(); + + return this; + }, + + get : function (units) { + units = normalizeUnits(units); + return this[units.toLowerCase() + 's'](); + }, + + as : function (units) { + var days, months; + units = normalizeUnits(units); + + if (units === 'month' || units === 'year') { + days = this._days + this._milliseconds / 864e5; + months = this._months + daysToYears(days) * 12; + return units === 'month' ? months : months / 12; + } else { + // handle milliseconds separately because of floating point math errors (issue #1867) + days = this._days + Math.round(yearsToDays(this._months / 12)); + switch (units) { + case 'week': return days / 7 + this._milliseconds / 6048e5; + case 'day': return days + this._milliseconds / 864e5; + case 'hour': return days * 24 + this._milliseconds / 36e5; + case 'minute': return days * 24 * 60 + this._milliseconds / 6e4; + case 'second': return days * 24 * 60 * 60 + this._milliseconds / 1000; + // Math.floor prevents floating point math errors here + case 'millisecond': return Math.floor(days * 24 * 60 * 60 * 1000) + this._milliseconds; + default: throw new Error('Unknown unit ' + units); + } + } + }, + + lang : moment.fn.lang, + locale : moment.fn.locale, + + toIsoString : deprecate( + 'toIsoString() is deprecated. Please use toISOString() instead ' + + '(notice the capitals)', + function () { + return this.toISOString(); + } + ), + + toISOString : function () { + // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js + var years = Math.abs(this.years()), + months = Math.abs(this.months()), + days = Math.abs(this.days()), + hours = Math.abs(this.hours()), + minutes = Math.abs(this.minutes()), + seconds = Math.abs(this.seconds() + this.milliseconds() / 1000); + + if (!this.asSeconds()) { + // this is the same as C#'s (Noda) and python (isodate)... + // but not other JS (goog.date) + return 'P0D'; + } + + return (this.asSeconds() < 0 ? '-' : '') + + 'P' + + (years ? years + 'Y' : '') + + (months ? months + 'M' : '') + + (days ? days + 'D' : '') + + ((hours || minutes || seconds) ? 'T' : '') + + (hours ? hours + 'H' : '') + + (minutes ? minutes + 'M' : '') + + (seconds ? seconds + 'S' : ''); + }, + + localeData : function () { + return this._locale; + }, + + toJSON : function () { + return this.toISOString(); + } + }); + + moment.duration.fn.toString = moment.duration.fn.toISOString; + + function makeDurationGetter(name) { + moment.duration.fn[name] = function () { + return this._data[name]; + }; + } + + for (i in unitMillisecondFactors) { + if (hasOwnProp(unitMillisecondFactors, i)) { + makeDurationGetter(i.toLowerCase()); + } + } + + moment.duration.fn.asMilliseconds = function () { + return this.as('ms'); + }; + moment.duration.fn.asSeconds = function () { + return this.as('s'); + }; + moment.duration.fn.asMinutes = function () { + return this.as('m'); + }; + moment.duration.fn.asHours = function () { + return this.as('h'); + }; + moment.duration.fn.asDays = function () { + return this.as('d'); + }; + moment.duration.fn.asWeeks = function () { + return this.as('weeks'); + }; + moment.duration.fn.asMonths = function () { + return this.as('M'); + }; + moment.duration.fn.asYears = function () { + return this.as('y'); + }; + + /************************************ + Default Locale + ************************************/ + + + // Set default locale, other locale will inherit from English. + moment.locale('en', { + ordinalParse: /\d{1,2}(th|st|nd|rd)/, + ordinal : function (number) { + var b = number % 10, + output = (toInt(number % 100 / 10) === 1) ? 'th' : + (b === 1) ? 'st' : + (b === 2) ? 'nd' : + (b === 3) ? 'rd' : 'th'; + return number + output; + } + }); + + /* EMBED_LOCALES */ + + /************************************ + Exposing Moment + ************************************/ + + function makeGlobal(shouldDeprecate) { + /*global ender:false */ + if (typeof ender !== 'undefined') { + return; + } + oldGlobalMoment = globalScope.moment; + if (shouldDeprecate) { + globalScope.moment = deprecate( + 'Accessing Moment through the global scope is ' + + 'deprecated, and will be removed in an upcoming ' + + 'release.', + moment); + } else { + globalScope.moment = moment; + } + } + + // CommonJS module is defined + if (hasModule) { + module.exports = moment; + } else if (typeof define === 'function' && define.amd) { + define(function (require, exports, module) { + if (module.config && module.config() && module.config().noGlobal === true) { + // release the global variable + globalScope.moment = oldGlobalMoment; + } + + return moment; + }); + makeGlobal(true); + } else { + makeGlobal(); + } +}).call(this); \ No newline at end of file diff --git a/public/js/lib/moment/nextTuesday.js b/public/js/lib/moment/nextTuesday.js index 135be1ac41..15cd8068a6 100644 --- a/public/js/lib/moment/nextTuesday.js +++ b/public/js/lib/moment/nextTuesday.js @@ -1,3 +1,16 @@ /** * Created by jason on 2/11/15. */ + +function nextSession () { + var next = 'Our next session will be '; + var today = moment().day(moment().day()); + if (today > moment().day(2)) { + next += moment().day(9).format('dddd, MMMM Do YYYY') + ' at 9PM EST!'; + } else { + next += moment().day('Tuesday').format('dddd, MMMM Do YYYY') + ' at 9PM EST!'; + } + return next; + + +} diff --git a/views/layout-wide.jade b/views/layout-wide.jade index 33873b2bf2..a46d82bcee 100644 --- a/views/layout-wide.jade +++ b/views/layout-wide.jade @@ -4,6 +4,8 @@ html(ng-app='profileValidation', lang='en') script(src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js") script(src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.11/angular.min.js") script(src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.0/ui-bootstrap-tpls.min.js") + script(src="/js/lib/moment/moment.js") + script(src="/js/lib/moment/nextTuesday.js") link(rel='shortcut icon', href='//s3.amazonaws.com/freecodecamp/favicon.ico') link(rel='stylesheet', href='//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css') link(rel='stylesheet', href='//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css') diff --git a/views/resources/live-pair-programming.jade b/views/resources/live-pair-programming.jade index b18baf2216..cd268dc7a0 100644 --- a/views/resources/live-pair-programming.jade +++ b/views/resources/live-pair-programming.jade @@ -1,8 +1,12 @@ extends ../layout-wide block content + .text-center h1 Live Pair Programming - h2 Our next session will be February 3rd, 2015 at 9 p.m. EST! + + + h2#next-session + h2 Watch the live stream below or on our   a(href="http://twitch.tv/freecodecamp", target='_blank') Twitch.tv channel | . @@ -46,3 +50,5 @@ block content br br br + script. + $('#next-session').text(nextSession()); From 995ca3d3765f4b0c17b0079d98972a36efaffe2b Mon Sep 17 00:00:00 2001 From: Nathan Leniz Date: Fri, 13 Feb 2015 00:24:57 -0500 Subject: [PATCH 27/68] Refactor moment scripts to only be included in live-pair-programming view instead of being required in layout-wide --- views/layout-wide.jade | 2 -- views/resources/live-pair-programming.jade | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/views/layout-wide.jade b/views/layout-wide.jade index a46d82bcee..33873b2bf2 100644 --- a/views/layout-wide.jade +++ b/views/layout-wide.jade @@ -4,8 +4,6 @@ html(ng-app='profileValidation', lang='en') script(src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js") script(src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.11/angular.min.js") script(src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.0/ui-bootstrap-tpls.min.js") - script(src="/js/lib/moment/moment.js") - script(src="/js/lib/moment/nextTuesday.js") link(rel='shortcut icon', href='//s3.amazonaws.com/freecodecamp/favicon.ico') link(rel='stylesheet', href='//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css') link(rel='stylesheet', href='//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css') diff --git a/views/resources/live-pair-programming.jade b/views/resources/live-pair-programming.jade index cd268dc7a0..46ba914596 100644 --- a/views/resources/live-pair-programming.jade +++ b/views/resources/live-pair-programming.jade @@ -50,5 +50,7 @@ block content br br br + script(src="/js/lib/moment/moment.js") + script(src="/js/lib/moment/nextTuesday.js") script. $('#next-session').text(nextSession()); From 43da6d16ff3e2be254d3c38520232b091615db51 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Thu, 12 Feb 2015 22:54:45 -0800 Subject: [PATCH 28/68] fix trello integration and make minor changes to courseware.json --- controllers/resources.js | 2 +- seed_data/coursewares.json | 37 +++++++++++++++++++------------------ 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/controllers/resources.js b/controllers/resources.js index 56234fe8e2..ec1c063f20 100644 --- a/controllers/resources.js +++ b/controllers/resources.js @@ -123,7 +123,7 @@ module.exports = { var daysRunning = Math.ceil(timeDiff / (1000 * 3600 * 24)); client.get('https://trello.com/1/boards/BA3xVpz9/cards?key=' + secrets.trello.key, function(trello, res2) { client.get('https://www.googleapis.com/blogger/v3/blogs/2421288658305323950/posts?key=' + secrets.blogger.key, function(blogger, res3) { - var nonprofitProjects = trello.length || 15; + var nonprofitProjects = (JSON.parse(trello)).length || 27; var blog = JSON.parse(blogger); User.count({'points': {'$gt': 2}}, function (err, c3) { if (err) { diff --git a/seed_data/coursewares.json b/seed_data/coursewares.json index cfb32c6e38..f675d0e52c 100644 --- a/seed_data/coursewares.json +++ b/seed_data/coursewares.json @@ -9,13 +9,14 @@ "You can edit code in the text editor we've embedded into this web page.", "Do you see the code in the text editor that says <h1>hello</h1>? That's an HTML element.", "Most HTML elements have an opening tag and a closing tag. Opening tags look like this: <h1>. Closing tags look like this: </h1>. Note that the only difference between opening and closing tags is that closing tags have a slash after their opening angle bracket.", - "To advance to the next exercise, change the h1 tag's text to say \"hello world\" instead of \"hello\"." + "Once you've completed the challenge, the \"Go to my next challenge\" button will become enabled. Click it - or press control and enter at the same time - to advance to the next challenge.", + "To enable the \"Go to my next challenge\" button on this exercise, change the h1 tag's text to say \"Hello World\" instead of \"Hello\"." ], "tests": [ "expect((/hello(\\s)+world/gi).test($('h1').text())).to.be.true;" ], "challengeSeed": [ - "

hello

" + "

Hello

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

Hello

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

hello world

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

hello world

", "

hello html

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

hello html

", "

hello paragraph

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

hello paragraph

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

hello paragraph

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

cat photo app

", "

hello paragraph

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

cat photo app

", "

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

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

cat photo app

", "

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

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

cat photo app

", "

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

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

cat photo app

", "

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

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

cat photo app

", "

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

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

cat photo app

", "

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

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

cat photo app

", "

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

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

cat photo app

", "

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

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

cat photo app

", "

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

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

cat photo app

", "

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

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

cat photo app

", "

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

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

cat photo app

", "

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

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

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

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

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

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

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

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

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

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

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

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

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

hello world

" ], - "challengeType": 0, - "completionMessage": "" + "challengeType": 0 } ] diff --git a/views/coursewares/show.jade b/views/coursewares/showHTML.jade similarity index 100% rename from views/coursewares/show.jade rename to views/coursewares/showHTML.jade diff --git a/views/coursewares/showJS.jade b/views/coursewares/showJS.jade index 30df71c717..71c8e037e3 100644 --- a/views/coursewares/showJS.jade +++ b/views/coursewares/showJS.jade @@ -73,11 +73,4 @@ block content i.fa.fa-twitter   = phrase - else - a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress - //#all-bonfires-dialog.modal(tabindex='-1') - // .modal-dialog.animated.fadeInUp.fast-animation - // .modal-content - // .modal-header.challenge-list-header Bonfires - // a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') × - // .modal-body - // include ../partials/bonfires + a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress \ No newline at end of file diff --git a/views/coursewares/showVideo.jade b/views/coursewares/showVideo.jade index 4d207bf6e5..95b6e8590d 100644 --- a/views/coursewares/showVideo.jade +++ b/views/coursewares/showVideo.jade @@ -1,41 +1,49 @@ - extends ../layout-wide block content .row - .col-sm-12.col-md-12.col-xs-12 - .panel.panel-primary - .panel-heading.text-center - h1 #{name} + .col-xs-12.col-sm-12.col-md-4.bonfire-top + h1.text-center= name + .well + h4 + ol + for step in details + li!= step + .col-xs-12.col-sm-12.col-md-8 + .embed-responsive.embed-responsive-16by9 + iframe.embed-responsive-item(src='//player.vimeo.com/video/#{video}') + br + - if (cc) + a.btn.btn-primary.btn-lg.btn-block#next-courseware-button Go to my next challenge (ctrl + enter) script. - var challengeName = !{JSON.stringify(name)}; + var userLoggedIn = true; + - else + a.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress + script. + var userLoggedIn = false; + br + script(type="text/javascript"). + var tests = !{JSON.stringify(tests)}; var passedCoursewareHash = !{JSON.stringify(coursewareHash)}; - - .panel.panel-body - .embed-responsive.embed-responsive-16by9 - iframe.embed-responsive-item(src='//player.vimeo.com/video/#{video}') - .col-xs-12.col-sm-10.col-sm-offset-1.col-md-8.col-md-offset-2 - h3 Steps: - h4 - ol - for step in details - li!= step - .btn.btn-primary.btn-big.btn-block#completed-courseware I've completed this challenge - .ten-pixel-break - .btn.btn-success.btn-big.btn-block.all-challenges Show me all the challenges - #complete-courseware-dialog.modal(tabindex='-1') - .modal-dialog.animated.zoomIn.fast-animation - .modal-content - .modal-header.challenge-list-header= compliment - a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') × - .modal-body - .text-center - .animated.zoomInDown.delay-half - span.completion-icon.ion-checkmark-circled.text-primary - - if (cc) - a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block#next-courseware-button(name='_csrf', value=_csrf, aria-hidden='true') Take me to my next challenge - - if (points && points > 2) - a.animated.fadeIn.btn.btn-lg.btn-block.btn-twitter(href="https://twitter.com/intent/tweet?text=I%20just%20#{verb}%20%40FreeCodeCamp%20Challenge%20%23#{number}:%20#{name}&url=http%3A%2F%2Ffreecodecamp.com/challenges/#{number}&hashtags=LearnToCode, JavaScript" target="_blank") - i.fa.fa-twitter   - = phrase - - else - a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress + var challengeName = !{JSON.stringify(name)}; + var started = Math.floor(Date.now() / 1000); + #complete-courseware-dialog.modal(tabindex='-1') + .modal-dialog.animated.zoomIn.fast-animation + .modal-content + .modal-header.challenge-list-header= compliment + a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') × + .modal-body(ng-controller="pairedWithController") + .text-center + .animated.zoomInDown.delay-half + span.completion-icon.ion-checkmark-circled.text-primary + - if (cc) + a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block.next-courseware-button(name='_csrf', value=_csrf, ng-disabled='completedWithForm.$invalid && existingUser.length > 0') Go to my next challenge (ctrl + enter) + - if (points && points > 2) + a.animated.fadeIn.btn.btn-lg.btn-block.btn-twitter(href="https://twitter.com/intent/tweet?text=I%20just%20#{verb}%20%40FreeCodeCamp%20Bonfire:%20#{name}&url=http%3A%2F%2Ffreecodecamp.com/bonfires/#{dashedName}&hashtags=LearnToCode, JavaScript" target="_blank") + i.fa.fa-twitter   + = phrase + - else + a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress + h1 #{name} + script. + var challengeName = !{JSON.stringify(name)}; + var passedCoursewareHash = !{JSON.stringify(coursewareHash)}; \ No newline at end of file From 5846a619554fce271b624c9327a228a2462a2d2d Mon Sep 17 00:00:00 2001 From: Alex Dixon Date: Fri, 13 Feb 2015 21:40:02 -0800 Subject: [PATCH 42/68] Typos --- seed_data/challenges.json | 82 +++++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 33 deletions(-) diff --git a/seed_data/challenges.json b/seed_data/challenges.json index 6830fc0442..c18749f41a 100644 --- a/seed_data/challenges.json +++ b/seed_data/challenges.json @@ -30,7 +30,7 @@ "Now enter the chat room by going to https://gitter.im/FreeCodeCamp/FreeCodeCamp and clicking the \"sign in with GitHub\" button.", "Introduce yourself to our chat room by typing: \"hello world!\".", "Tell your fellow campers how you found Free Code Camp. Also tell us why you want to learn to code.", - "Keep the chat room open while you work through the other challenges. That way you ask for help If you get stuck on a challenge. You can also socialize when you feel like taking a break.", + "Keep the chat room open while you work through the other challenges. That way you ask for help if you get stuck on a challenge. You can also socialize when you feel like taking a break.", "Now that you've completed this challenge, you can go directly your most-recently visited chat room by clicking the \"Chat\" button in the navigation bar above." ] }, @@ -67,7 +67,7 @@ "video": "114578441", "challengeNumber": 4, "steps": [ - "Next, let's learn about Responsive web design and continue learning about HTML and CSS.", + "Next, let's learn about responsive web design and continue learning about HTML and CSS.", "A responsive website will automatically adapt to changes in your browser's width. This means that you can make one version of a website that will look good on desktop, tablet and phone.", "Later, we'll use Twitter's Bootstrap CSS framework to build responsive websites.", "You can check it out here: http://getbootstrap.com/.", @@ -79,7 +79,8 @@ "time": 60, "video": "114578438", "challengeNumber": 5, - "steps": ["Ready for some more HTML and CSS fundamentals?", + "steps": [ + "Ready for some more HTML and CSS fundamentals?", "Go to https://dash.generalassemb.ly/projects/eshas-restaurant-1 and complete the third project."] }, { @@ -94,7 +95,7 @@ "Right-click an area of the page that doesn't have any HTML elements on it, then choose 'view page source'.", "Select all the text, then copy it.", "Go to http://codepen.io/pen/", - "Paste the HTML you copied from Newsweek.com into the HTML field of Codepen.", + "Paste the HTML you copied from Newsweek.com into the HTML field of CodePen.", "You now have your own customizable version of the Newsweek.com website. See if you can change some of the text and images." ] }, @@ -103,7 +104,8 @@ "time": 60, "video": "114578436", "challengeNumber": 7, - "steps": ["Now let's learn some more CSS, and a small amount of a JavaScript-based tool called jQuery.", + "steps": [ + "Now let's learn some more CSS, and a small amount of a JavaScript-based tool called jQuery.", "Go to https://dash.generalassemb.ly/projects/cotbots-1 and complete the fourth project."] }, { @@ -155,7 +157,7 @@ "video": "114591801", "challengeNumber": 12, "steps": [ - "Finally, let's use jQuery to manipulate the way websites look, by changing the CSS of elements.", + "Finally, let's use jQuery to manipulate the way websites look by changing the CSS of elements.", "Go to http://try.jquery.com/levels/5/challenges/1 and complete the fifth section." ] }, @@ -166,7 +168,7 @@ "challengeNumber": 13, "steps": [ "Now that we've built a foundation in jQuery, let's go back to Dash and do its last challenge.", - "If you aren't familiar with Mad Libs, they basically involve inserting random nouns, adjectives and verbs in to stories. The stories that result are often hilarious.", + "If you aren't familiar with Mad Libs, they basically involve inserting random nouns, adjectives and verbs into stories. The stories that result are often hilarious.", "Go to https://dash.generalassemb.ly/projects/mad-libs-1 and complete the fifth project." ] }, @@ -204,12 +206,12 @@ "Right-click an area of the page that doesn't have any HTML elements on it, then choose 'view page source'.", "Select all the text, then copy it.", "Go to http://codepen.io/pen/", - "Paste the HTML you copied from GetBootStrap.com into the HTML field of Codepen.", + "Paste the HTML you copied from GetBootStrap.com into the HTML field of CodePen.", "Go to http://bootswatch.com/", "Decide which theme you want to use.", - "Click the down arrow next to the download button and choose 'bootstrap.css'", + "Click the down arrow next to the download button and choose 'bootstrap.css'.", "Select all the text, then copy it.", - "Go back to CodePen and paste the CSS you copied from Bootswatch.com into the CSS field of Codepen.", + "Go back to CodePen and paste the CSS you copied from Bootswatch.com into the CSS field of CodePen.", "Your Bootswatch CSS should now be applied to the HTML from the GetBootStrap page.", "This page is currently using a two-column layout, with the main content on the left and additional navigation on the right. See if you can make it a one-column layout." ] @@ -249,7 +251,8 @@ "steps": [ "Now let's tackle week 2 of Stanford's Intro to Computer Science course.", "This will introduce us to loops, a fundamental feature of every programming language.", - "Go to https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z100/a7a70ce6e4724c58862ee6007284face/ and complete Week 2."] + "Go to https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z100/a7a70ce6e4724c58862ee6007284face/ and complete Week 2." + ] }, { "name": "Learn Computer Hardware", @@ -270,7 +273,8 @@ "steps": [ "Now that you've learned about computer hardware, it's time to learn about the software that runs on top of it.", "Particularly important, you will learn about networks and TCP/IP - the protocol that powers the internet.", - "Go to https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z187/z144/ and complete Week 4."] + "Go to https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z187/z144/ and complete Week 4." + ] }, { "name": "Learn Boolean Logic", @@ -280,7 +284,8 @@ "steps": [ "Now we'll do some more table exercises and learn boolean logic.", "We'll also learn the difference between digital data and analog data.", - "Go to https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z208/z188/ and complete Week 5."] + "Go to https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z208/z188/ and complete Week 5." + ] }, { "name": "Learn Computer Security", @@ -291,7 +296,8 @@ "We're almost done with Stanford's Introduction to Computer Science course!", "We'll learn about one of the most important inventions of the 20th century - spreadsheets.", "We'll also learn about Computer Security and some of the more common vulnerabilities software systems have.", - "Go to https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z229/z213/ and complete Week 6, the final week of the course."] + "Go to https://class.stanford.edu/courses/Engineering/CS101/Summer2014/courseware/z229/z213/ and complete Week 6, the final week of the course." + ] }, { "name": "Build an Adventure Game", @@ -379,19 +385,19 @@ "video": "114612882", "challengeNumber": 31, "steps": [ - "In this final CodeCademy section, we'll learn even more about JavaScript objects.", + "In this final Codecademy section, we'll learn even more about JavaScript objects.", "Go to http://www.codecademy.com/courses/objects-ii/0/1 and complete this section.", "Be sure to also complete the final section: http://www.codecademy.com/courses/close-the-super-makert/0/1." ] }, { - "name": "Get Help The Hacker Way", + "name": "Get Help the Hacker Way", "time": 30, "video": "111500801", "challengeNumber": 32, "steps": [ "Watch the video to learn the RSAP (Read, Search, Ask, Post) methodology for getting help.", - "Try an intelligent Google query that involves JavaScript and filters for this year (since JavaScript changes)", + "Try an intelligent Google query that involves JavaScript and filters for this year (since JavaScript changes).", "Go to http://stackoverflow.com/ and view the recent questions.", "Go to http://webchat.freenode.net/ and create an IRC account.", "Join the #JavaScript chat room and introduce yourself as a Free Code Camp student.", @@ -427,11 +433,11 @@ "Private message your pair and ask for the email address he or she used to register Screen Hero.", "Add them as a new contact in Screen Hero, then click the monitor-looking button to attempt to share your screen with them.", "Once the Screen Hero session starts, your screen's margins will glow orange. You are now sharing your screen.", - "Your pair will have his or her own cursor, and will be able to type text on his or her and keyboard.", + "Your pair will have his or her own cursor, and will be able to type text on his or her keyboard.", "Now it's time to tackle CoderByte.", - "Create a CoderByte account at http://coderbyte.com/sl/", - "Now go to http://coderbyte.com/CodingArea/Challenges/#easyChals and start working through Coderbyte's easy algorithm scripting challenges using JavaScript.", - "When you are finished pair programming, end the session in Screen Hero session.", + "Create a CoderByte account at http://coderbyte.com/sl/.", + "Now go to http://coderbyte.com/CodingArea/Challenges/#easyChals and start working through CoderByte's easy algorithm scripting challenges using JavaScript.", + "When you are finished pair programming, end the session in Screen Hero.", "Congratulations! You have completed your first pair programming session.", "You should pair program with different campers until you've completed all the Easy, Medium and Hard CoderByte challenges. This is a big time investment, but the JavaScript practice you'll get, along with the scripting and algorithm experience, are well worth it!", "You can complete CoderByte problems while you continue to work through Free Code Camp's challenges.", @@ -468,7 +474,7 @@ "video": "114684206", "challengeNumber": 37, "steps": [ - "One of the reasons Node.js is so fast is that it is \"evented\" - it processes events in an asynchronous manner.", + "One of the reasons Node.js is so fast is that it is \"evented.\" It processes events in an asynchronous manner.", "As a result, Node.js relies on asynchronous callbacks.", "We'll learn more about how events and callbacks work in this exciting Code School lesson.", "Go to http://campus.codeschool.com/courses/real-time-web-with-node-js/level/2/video/1 and complete the section." @@ -494,7 +500,8 @@ "One of the most exciting features of Node.js is NPM - Node Package Manager", "With NPM, you quickly install any of thousands of Node.js modules into your app, and it will automatically handle the other modules that each module dependends upon downstream.", "In this lesson, we'll learn how to include these modules in our Node.js app by requiring them as variables.", - "Go to http://campus.codeschool.com/courses/real-time-web-with-node-js/level/4/video/1 and complete the section."] + "Go to http://campus.codeschool.com/courses/real-time-web-with-node-js/level/4/video/1 and complete the section." + ] }, { "name": "Start an Express.js Server", @@ -503,14 +510,17 @@ "challengeNumber": 40, "steps": [ "We'll complete Code School's Express.js course shortly after completing this course, but this challenge will give you a quick tour of the Express.js framework.", - "Go to http://campus.codeschool.com/courses/real-time-web-with-node-js/level/5/video/1 and complete the section."] + "Go to http://campus.codeschool.com/courses/real-time-web-with-node-js/level/5/video/1 and complete the section." + ] }, { - "name": "Use Socket.IO", + "name": "Use Socket.io", "time": 45, "video": "114684530", "challengeNumber": 41, - "steps": ["Go to http://campus.codeschool.com/courses/real-time-web-with-node-js/level/6/video/1 and complete the section."] + "steps": [ + "Go to http://campus.codeschool.com/courses/real-time-web-with-node-js/level/6/video/1 and complete the section." + ] }, { "name": "Use Redis to Persist Data", @@ -520,7 +530,8 @@ "steps": [ "Redis is a key-value store, which is a type of non-relational database. It's one of the fastest and easiest ways to persist data.", "Even though we'll ultimately use MongoDB and other technologies to persist data, Redis is quite easy to learn and is still worth learning.", - "Go to http://campus.codeschool.com/courses/real-time-web-with-node-js/level/7/video/1 and complete the section."] + "Go to http://campus.codeschool.com/courses/real-time-web-with-node-js/level/7/video/1 and complete the section." + ] }, { "name": "Dive Deeper into Express.js", @@ -529,7 +540,8 @@ "challengeNumber": 43, "steps": [ "Code School has one of the first comprehensive courses on Express.js. Note that this course requires a Code School subscription, but that you can get a free two-day membership to Code School by going to https://www.codeschool.com/hall_passes/213f3fedb6b9/claim_shared. If you've already used your Code School two-day membership, go to the Free Code Camp main chat room and ask how you can get some extra time to work through this course. Alternatively, you could subscribe to Code School for one month, then take your time in completing these challenges.", - "Go to http://campus.codeschool.com/courses/building-blocks-of-express-js/level/1/video/1 and complete the section."] + "Go to http://campus.codeschool.com/courses/building-blocks-of-express-js/level/1/video/1 and complete the section." + ] }, { @@ -549,7 +561,7 @@ "video": "114684537", "challengeNumber": 45, "steps": [ - "Have you've ever noticed a question mark in your browser's address bar, followed by a series of string? Those are parameters. Parameters are an efficient way to pass information to the server between page loads.", + "Have you ever noticed a question mark in your browser's address bar, followed by a series of strings? Those are parameters. Parameters are an efficient way to pass information to the server between page loads.", "We'll learn about parameters, along with a powerful Express.js feature called Dynamic Routing, in this exciting Code School lesson.", "Go to http://campus.codeschool.com/courses/building-blocks-of-express-js/level/3/video/1 and complete the section." ] @@ -594,7 +606,8 @@ "steps": [ "Code School has a short, free Angular.js course. This will give us a quick tour of Angular.js's mechanics and features.", "In this course, we'll build a virtual shop entirely in Angular.js.", - "Go to http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/1/section/1/video/1 and complete the section."] + "Go to http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/1/section/1/video/1 and complete the section." + ] }, { "name": "Apply Angular.js Directives", @@ -615,7 +628,8 @@ "steps": [ "One area where Angular.js really shines is its powerful web forms.", "Learn how to create reactive Angular.js forms, including real-time form validation.", - "Go to http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/3/section/1/video/1 and complete the section."] + "Go to http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/3/section/1/video/1 and complete the section." + ] }, { "name": "Customize Angular.js Directives", @@ -624,7 +638,8 @@ "challengeNumber": 52, "steps": [ "Now we'll learn how to modify existing Angular.js directives, and even build directives of your own.", - "Go to http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/4/section/1/video/1 and complete the section."] + "Go to http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/4/section/1/video/1 and complete the section." + ] }, { "name": "Create Angular.js Services", @@ -634,6 +649,7 @@ "steps": [ "Services are functions that you can use and reuse throughout your Angular.js app to get things done.", "We'll learn how to use services in this final Code School Angular.js challenge.", - "Go to http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/5/section/1/video/1 and complete the section."] + "Go to http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/5/section/1/video/1 and complete the section." + ] } ] From 255d2654ea215e4f63e10c6fa6e48ca16bd5938d Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Sat, 14 Feb 2015 12:52:04 -0800 Subject: [PATCH 43/68] fix an indentation issue in showHTML --- views/coursewares/showVideo.jade | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/views/coursewares/showVideo.jade b/views/coursewares/showVideo.jade index 95b6e8590d..88099ddc42 100644 --- a/views/coursewares/showVideo.jade +++ b/views/coursewares/showVideo.jade @@ -21,11 +21,11 @@ block content script. var userLoggedIn = false; br - script(type="text/javascript"). - var tests = !{JSON.stringify(tests)}; - var passedCoursewareHash = !{JSON.stringify(coursewareHash)}; - var challengeName = !{JSON.stringify(name)}; - var started = Math.floor(Date.now() / 1000); + script(type="text/javascript"). + var tests = !{JSON.stringify(tests)}; + var passedCoursewareHash = !{JSON.stringify(coursewareHash)}; + var challengeName = !{JSON.stringify(name)}; + var started = Math.floor(Date.now() / 1000); #complete-courseware-dialog.modal(tabindex='-1') .modal-dialog.animated.zoomIn.fast-animation .modal-content From 31aafd300c2f08e9c4842d4e5b0214e9509af6fd Mon Sep 17 00:00:00 2001 From: Nathan Leniz Date: Sat, 14 Feb 2015 15:54:51 -0500 Subject: [PATCH 44/68] Removing a very buggy challenge --- seed_data/bonfires.json | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/seed_data/bonfires.json b/seed_data/bonfires.json index b41aaffca7..2dcd441810 100644 --- a/seed_data/bonfires.json +++ b/seed_data/bonfires.json @@ -220,20 +220,6 @@ "assert.deepEqual(bouncer([false, null, 0]), [], 'should return empty array if all elements are falsey');" ] }, - { - "_id":"a8e512fbe388ac2f9198f0fa", - "name":"Where art thou", - "difficulty":"1.55", - "description":[ - "Maketh a function that looks through a list (first argument) and returns an array of all objects that have equivalent property values (second argument)." - ], - "challengeEntryPoint":"where([{ first: 'Romeo', last: 'Montague' }, { first: 'Mercutio', last: null }, { first: 'Tybalt', last: 'Capulet' }], { last: 'Capulet' });", - "challengeSeed":"function where(collection, source) {\n var arr = [];\r\n // What's in a name?\r\n return arr;\r\n}", - "tests":[ - "assert.deepEqual(where([{ first: 'Romeo', last: 'Montague' }, { first: 'Mercutio', last: null }, { first: 'Tybalt', last: 'Capulet' }], { last: 'Capulet' }), [{ first: 'Tybalt', last: 'Capulet' }], 'should return an array of objects');", - "assert.deepEqual(where([{ 'a': 1 }, { 'a': 1 }, { 'a': 1, 'b': 2 }], { 'a': 1 }), [{ 'a': 1 }, { 'a': 1 }, { 'a': 1 }], 'should return with multiples');" - ] - }, { "_id":"a39963a4c10bc8b4d4f06d7e", "name":"Seek and Destroy", From fb971ab080198652a78de9a13e33956506160fae Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Sat, 14 Feb 2015 14:09:26 -0800 Subject: [PATCH 45/68] start adding test output to coursewares --- .../coursewaresHCJQFramework_v0.1.1.js | 9 ++++++++- public/js/lib/coursewares/iFrameScripts.js | 19 ++++++++++++------- seed_data/coursewares.json | 10 +++++----- views/coursewares/showHTML.jade | 12 +++++------- 4 files changed, 30 insertions(+), 20 deletions(-) diff --git a/public/js/lib/coursewares/coursewaresHCJQFramework_v0.1.1.js b/public/js/lib/coursewares/coursewaresHCJQFramework_v0.1.1.js index 026f36c04e..189f796c6a 100644 --- a/public/js/lib/coursewares/coursewaresHCJQFramework_v0.1.1.js +++ b/public/js/lib/coursewares/coursewaresHCJQFramework_v0.1.1.js @@ -62,7 +62,7 @@ function updatePreview() { var previewFrame = document.getElementById('preview'); var preview = previewFrame.contentDocument || previewFrame.contentWindow.document; preview.open(); - preview.write(libraryIncludes + editor.getValue() + otherTestsForNow); + preview.write(libraryIncludes + editor.getValue()); preview.close(); } setTimeout(updatePreview, 300); @@ -81,6 +81,13 @@ eventer(messageEvent,function(e) { } },false); +var postError = function(data) { + console.log(Object.keys(data)); + var testDoc = document.createElement("div"); + $(testDoc) + .html("
" + data + "
") + .prependTo($('#testSuite')) +}; var challengeSeed = challengeSeed || null; var tests = tests || []; var allSeeds = ''; diff --git a/public/js/lib/coursewares/iFrameScripts.js b/public/js/lib/coursewares/iFrameScripts.js index 325b34af69..5c3d38998f 100644 --- a/public/js/lib/coursewares/iFrameScripts.js +++ b/public/js/lib/coursewares/iFrameScripts.js @@ -1,14 +1,19 @@ (function() { var allTestsGood = true; var expect = chai.expect; + var tests = parent.tests; - try { - eval(parent.allTests); - } catch (err) { - allTestsGood = false; - } finally { - if (allTestsGood) { - parent.postMessage('CompleteAwesomeSauce', parent.nodeEnv); + for (var i = 0; i < tests.length; i++) { + + try { + eval(tests[i]); + } catch (err) { + parent.postError(err); + allTestsGood = false; + } finally { + if (allTestsGood) { + parent.postMessage('CompleteAwesomeSauce', parent.nodeEnv); + } } } })(); \ No newline at end of file diff --git a/seed_data/coursewares.json b/seed_data/coursewares.json index 0c752ff36b..e7c4a99289 100644 --- a/seed_data/coursewares.json +++ b/seed_data/coursewares.json @@ -256,7 +256,7 @@ " color: blue;", " }", "", - "

hello world

", + "

hello world

", "

cat photo app

", "

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

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