diff --git a/README.md b/README.md index 9b0c87d631..0611cd1816 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Our campers (students) start by working through our free, self-paced, browser-ba 80% of our campers are over 25, and nearly a fifth of our campers are women. -This code is running live at [FreeCodeCamp.com](http://www.FreeCodeCamp.com). We also have [Gitter](https://gitter.im/FreeCodeCamp/FreeCodeCamp), a [blog](http://blog.freecodecamp.com), and even a [Twitch.tv channel](http://twitch.tv/freecodecamp). +This code is running live at [FreeCodeCamp.com](http://www.FreeCodeCamp.com). We also have [Gitter](https://gitter.im/FreeCodeCamp/FreeCodeCamp), a [blog](http://medium.freecodecamp.com), and even a [Twitch.tv channel](http://twitch.tv/freecodecamp). [Join our community here](http://www.freecodecamp.com/signin). @@ -54,22 +54,26 @@ The easiest way to get started is to clone the repository: # Get the latest snapshot git clone --depth=1 https://github.com/freecodecamp/freecodecamp.git freecodecamp +# Change directory cd freecodecamp # Install NPM dependencies npm install +# Install Gulp globally +npm install -g gulp + +# Install Bower globally +npm install -g bower + # Install Bower dependencies bower install # Create a .env file and populate it with the necessary API keys and secrets: touch .env - -# Install Gulp globally -npm install -g gulp ``` -Edit your `.env` file with the following API keys accordingly (if you only use email login, only the `MONGOHQ_URL`, `SESSION_SECRET`, `MANDRILL_USER` and `MANDRILL_PASSWORD` fields are necessary. Keep in mind if you want to use more services you'll have to get your own API keys for those services. +Edit your `.env` file with the following API keys accordingly. If you only use email login, only the `MONGOHQ_URL`, `SESSION_SECRET`, `MANDRILL_USER` and `MANDRILL_PASSWORD` fields are necessary. Keep in mind if you want to use more services you'll have to get your own API keys for those services. If you only use a subset or no OAuth2 authentication methods, you may want to remove them from ```server/passport-providers.js``` - otherwise the server will complain about missing clientIDs at launch. ``` MONGOHQ_URL='mongodb://localhost:27017/freecodecamp' @@ -107,20 +111,20 @@ DEBUG=true ``` ```bash -# Start the mongo server +# Start the mongo server in a seperate terminal mongod -# Create your mongo database. -# Type "mongo" in your terminal to access the mongo shell -use freecodecamp -# Exit the mongo shell with control + d - -# Seed your database with the challenges -node seed/ +# Initialize Free Code Camp +# This will seed the database for the first time. +# This command should only be run once. +npm run first-time # start the application gulp ``` +Now navigate to your browser and open http://localhost:3001 +If the app loads, congratulations - you're all set. Otherwise, let us know by opening a GitHub issue and with your error. + License ------- diff --git a/client/commonFramework.js b/client/commonFramework.js index a28a1e743d..2505fe08f4 100644 --- a/client/commonFramework.js +++ b/client/commonFramework.js @@ -374,8 +374,9 @@ var editor = (function(CodeMirror, emmetCodeMirror, common) { } var editor = CodeMirror.fromTextArea(document.getElementById('codeEditor'), { + lint: true, lineNumbers: true, - mode: 'text', + mode: 'javascript', theme: 'monokai', runnable: true, matchBrackets: true, @@ -529,6 +530,20 @@ function safeHTMLRun(test) { // add feuxQuery s = 'var document = \"\"; var $ = function() {return(new function() {this.add=function() {return(this);};this.addBack=function() {return(this);};this.addClass=function() {return(this);};this.after=function() {return(this);};this.ajaxComplete=function() {return(this);};this.ajaxError=function() {return(this);};this.ajaxSend=function() {return(this);};this.ajaxStart=function() {return(this);};this.ajaxStop=function() {return(this);};this.ajaxSuccess=function() {return(this);};this.andSelf=function() {return(this);};this.animate=function() {return(this);};this.append=function() {return(this);};this.appendTo=function() {return(this);};this.attr=function() {return(this);};this.before=function() {return(this);};this.bind=function() {return(this);};this.blur=function() {return(this);};this.callbacksadd=function() {return(this);};this.callbacksdisable=function() {return(this);};this.callbacksdisabled=function() {return(this);};this.callbacksempty=function() {return(this);};this.callbacksfire=function() {return(this);};this.callbacksfired=function() {return(this);};this.callbacksfireWith=function() {return(this);};this.callbackshas=function() {return(this);};this.callbackslock=function() {return(this);};this.callbackslocked=function() {return(this);};this.callbacksremove=function() {return(this);};this.change=function() {return(this);};this.children=function() {return(this);};this.clearQueue=function() {return(this);};this.click=function() {return(this);};this.clone=function() {return(this);};this.closest=function() {return(this);};this.contents=function() {return(this);};this.context=function() {return(this);};this.css=function() {return(this);};this.data=function() {return(this);};this.dblclick=function() {return(this);};this.delay=function() {return(this);};this.delegate=function() {return(this);};this.dequeue=function() {return(this);};this.detach=function() {return(this);};this.die=function() {return(this);};this.each=function() {return(this);};this.empty=function() {return(this);};this.end=function() {return(this);};this.eq=function() {return(this);};this.error=function() {return(this);};this.fadeIn=function() {return(this);};this.fadeOut=function() {return(this);};this.fadeTo=function() {return(this);};this.fadeToggle=function() {return(this);};this.filter=function() {return(this);};this.find=function() {return(this);};this.finish=function() {return(this);};this.first=function() {return(this);};this.focus=function() {return(this);};this.focusin=function() {return(this);};this.focusout=function() {return(this);};this.get=function() {return(this);};this.has=function() {return(this);};this.hasClass=function() {return(this);};this.height=function() {return(this);};this.hide=function() {return(this);};this.hover=function() {return(this);};this.html=function() {return(this);};this.index=function() {return(this);};this.innerHeight=function() {return(this);};this.innerWidth=function() {return(this);};this.insertAfter=function() {return(this);};this.insertBefore=function() {return(this);};this.is=function() {return(this);};this.jQuery=function() {return(this);};this.jquery=function() {return(this);};this.keydown=function() {return(this);};this.keypress=function() {return(this);};this.keyup=function() {return(this);};this.last=function() {return(this);};this.length=function() {return(this);};this.live=function() {return(this);};this.load=function() {return(this);};this.load=function() {return(this);};this.map=function() {return(this);};this.mousedown=function() {return(this);};this.mouseenter=function() {return(this);};this.mouseleave=function() {return(this);};this.mousemove=function() {return(this);};this.mouseout=function() {return(this);};this.mouseover=function() {return(this);};this.mouseup=function() {return(this);};this.next=function() {return(this);};this.nextAll=function() {return(this);};this.nextUntil=function() {return(this);};this.not=function() {return(this);};this.off=function() {return(this);};this.offset=function() {return(this);};this.offsetParent=function() {return(this);};this.on=function() {return(this);};this.one=function() {return(this);};this.outerHeight=function() {return(this);};this.outerWidth=function() {return(this);};this.parent=function() {return(this);};this.parents=function() {return(this);};this.parentsUntil=function() {return(this);};this.position=function() {return(this);};this.prepend=function() {return(this);};this.prependTo=function() {return(this);};this.prev=function() {return(this);};this.prevAll=function() {return(this);};this.prevUntil=function() {return(this);};this.promise=function() {return(this);};this.prop=function() {return(this);};this.pushStack=function() {return(this);};this.queue=function() {return(this);};this.ready=function() {return(this);};this.remove=function() {return(this);};this.removeAttr=function() {return(this);};this.removeClass=function() {return(this);};this.removeData=function() {return(this);};this.removeProp=function() {return(this);};this.replaceAll=function() {return(this);};this.replaceWith=function() {return(this);};this.resize=function() {return(this);};this.scroll=function() {return(this);};this.scrollLeft=function() {return(this);};this.scrollTop=function() {return(this);};this.select=function() {return(this);};this.selector=function() {return(this);};this.serialize=function() {return(this);};this.serializeArray=function() {return(this);};this.show=function() {return(this);};this.siblings=function() {return(this);};this.size=function() {return(this);};this.slice=function() {return(this);};this.slideDown=function() {return(this);};this.slideToggle=function() {return(this);};this.slideUp=function() {return(this);};this.stop=function() {return(this);};this.submit=function() {return(this);};this.text=function() {return(this);};this.toArray=function() {return(this);};this.toggle=function() {return(this);};this.toggle=function() {return(this);};this.toggleClass=function() {return(this);};this.trigger=function() {return(this);};this.triggerHandler=function() {return(this);};this.unbind=function() {return(this);};this.undelegate=function() {return(this);};this.unload=function() {return(this);};this.unwrap=function() {return(this);};this.val=function() {return(this);};this.width=function() {return(this);};this.wrap=function() {return(this);};this.wrapAll=function() {return(this);};this.wrapInner=function() {return(this);}});};$.ajax=function() {return($);};$.ajaxPrefilter=function() {return($);};$.ajaxSetup=function() {return($);};$.ajaxTransport=function() {return($);};$.boxModel=function() {return($);};$.browser=function() {return($);};$.Callbacks=function() {return($);};$.contains=function() {return($);};$.cssHooks=function() {return($);};$.cssNumber=function() {return($);};$.data=function() {return($);};$.Deferred=function() {return($);};$.dequeue=function() {return($);};$.each=function() {return($);};$.error=function() {return($);};$.extend=function() {return($);};$.fnextend=function() {return($);};$.fxinterval=function() {return($);};$.fxoff=function() {return($);};$.get=function() {return($);};$.getJSON=function() {return($);};$.getScript=function() {return($);};$.globalEval=function() {return($);};$.grep=function() {return($);};$.hasData=function() {return($);};$.holdReady=function() {return($);};$.inArray=function() {return($);};$.isArray=function() {return($);};$.isEmptyObject=function() {return($);};$.isFunction=function() {return($);};$.isNumeric=function() {return($);};$.isPlainObject=function() {return($);};$.isWindow=function() {return($);};$.isXMLDoc=function() {return($);};$.makeArray=function() {return($);};$.map=function() {return($);};$.merge=function() {return($);};$.noConflict=function() {return($);};$.noop=function() {return($);};$.now=function() {return($);};$.param=function() {return($);};$.parseHTML=function() {return($);};$.parseJSON=function() {return($);};$.parseXML=function() {return($);};$.post=function() {return($);};$.proxy=function() {return($);};$.queue=function() {return($);};$.removeData=function() {return($);};$.sub=function() {return($);};$.support=function() {return($);};$.trim=function() {return($);};$.type=function() {return($);};$.unique=function() {return($);};$.when=function() {return($);};$.always=function() {return($);};$.done=function() {return($);};$.fail=function() {return($);};$.isRejected=function() {return($);};$.isResolved=function() {return($);};$.notify=function() {return($);};$.notifyWith=function() {return($);};$.pipe=function() {return($);};$.progress=function() {return($);};$.promise=function() {return($);};$.reject=function() {return($);};$.rejectWith=function() {return($);};$.resolve=function() {return($);};$.resolveWith=function() {return($);};$.state=function() {return($);};$.then=function() {return($);};$.currentTarget=function() {return($);};$.data=function() {return($);};$.delegateTarget=function() {return($);};$.isDefaultPrevented=function() {return($);};$.isImmediatePropagationStopped=function() {return($);};$.isPropagationStopped=function() {return($);};$.metaKey=function() {return($);};$.namespace=function() {return($);};$.pageX=function() {return($);};$.pageY=function() {return($);};$.preventDefault=function() {return($);};$.relatedTarget=function() {return($);};$.result=function() {return($);};$.stopImmediatePropagation=function() {return($);};$.stopPropagation=function() {return($);};$.target=function() {return($);};$.timeStamp=function() {return($);};$.type=function() {return($);};$.which=function() {return($);};' + s; + // add spoofigator + + s = " var navigator = " + + "function(){" + + " this.geolocation=function(){" + + " this.getCurrentPosition=function(){" + + " this.coords = {latitude: \"\", longitude: \"\"};" + + " return(this);" + + " };" + + " return(this);" + + " };" + + " return(this);" + + "};" + s; + sandBox.submit(scopejQuery(s), function(cls, message) { if (cls) { console.log(message.error); diff --git a/common/app/components/Footer/links.json b/common/app/components/Footer/links.json index 92199b127f..8089a868e4 100644 --- a/common/app/components/Footer/links.json +++ b/common/app/components/Footer/links.json @@ -2,7 +2,7 @@ { "className": "ion-speakerphone", "content": " Blog ", - "href": "http://blog.freecodecamp.com", + "href": "http://medium.freecodecamp.com", "target": "_blank" }, { diff --git a/common/models/challenge.json b/common/models/challenge.json index 84cf3a4c6b..81d6af6eef 100644 --- a/common/models/challenge.json +++ b/common/models/challenge.json @@ -82,6 +82,10 @@ }, "descriptionPt": { "type": "array" + }, + "solutions": { + "type": "array", + "default": [] } }, "validations": [], diff --git a/package.json b/package.json index 06d6a933ce..1c6f77559a 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,8 @@ "url": "https://github.com/freecodecamp/freecodecamp.git" }, "scripts": { + "first-time": "npm run create-rev && echo '\n\nseeding database\n\n' && node seed && node seed/nonprofits", + "create-rev": "test ! -e server/rev-manifest.json && echo '\n\ncreating manifest\n\n' && touch server/rev-manifest.json && echo '{}' >> server/rev-manifest.json", "build": "gulp build", "start": "babel-node server/server.js", "prestart-production": "bower cache clean && bower install && gulp build", @@ -49,6 +51,13 @@ "forever": "~0.14.1", "frameguard": "^0.2.2", "github-api": "~0.7.0", + "gulp": "~3.8.8", + "gulp-eslint": "~0.9.0", + "gulp-inject": "~1.0.2", + "gulp-jsonlint": "^1.1.0", + "gulp-nodemon": "^2.0.3", + "gulp-notify": "^2.2.0", + "gulp-plumber": "^1.0.1", "gulp-less": "^3.0.3", "gulp-minify-css": "~0.5.1", "gulp-reduce-file": "0.0.1", @@ -114,13 +123,6 @@ "browserify": "^10.2.4", "chai": "~1.10.0", "envify": "^3.4.0", - "gulp": "~3.8.8", - "gulp-eslint": "~0.9.0", - "gulp-inject": "~1.0.2", - "gulp-jsonlint": "^1.1.0", - "gulp-nodemon": "^2.0.3", - "gulp-notify": "^2.2.0", - "gulp-plumber": "^1.0.1", "istanbul": "^0.3.15", "loopback-explorer": "^1.7.2", "loopback-testing": "^1.1.0", diff --git a/seed/challenges/advanced-bonfires.json b/seed/challenges/advanced-bonfires.json index 8ff025e2fe..04ab7c18b2 100644 --- a/seed/challenges/advanced-bonfires.json +++ b/seed/challenges/advanced-bonfires.json @@ -57,6 +57,9 @@ "MDNlinks": [ "RegExp" ], + "solutions": [ + "var re = /^(?:(?:\\+?1\\s*(?:[.-]\\s*)?)?(?:\\(\\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\\s*\\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\\s*(?:[.-]\\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\\s*(?:[.-]\\s*)?([0-9]{4})$/;\n\nfunction telephoneCheck(str) {\n return !!str.match(re);\n}\n\ntelephoneCheck(\"555-555-5555\");" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -88,13 +91,15 @@ "tests": [ "assert.sameMembers(sym([1, 2, 3], [5, 2, 1, 4]), [3, 5, 4], 'message: sym([1, 2, 3], [5, 2, 1, 4]) should return [3, 5, 4].');", "assert.sameMembers(sym([1, 2, 5], [2, 3, 5], [3, 4, 5]), [1, 4, 5], 'message: sym([1, 2, 5], [2, 3, 5], [3, 4, 5]) should return [1, 4, 5]');", - "assert.sameMembers(sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]), [1, 4, 5], 'message: sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]) should return [1, 4, 5].');", - "assert.sameMembers(sym([1, 1]), [1], 'message: sym([1, 1]) should return [1].');" - ], + "assert.sameMembers(sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]), [1, 4, 5], 'message: sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]) should return [1, 4, 5].');" + ], "MDNlinks": [ "Array.reduce()", "Symmetric Difference" ], + "solutions": [ + "function sym(args) {\n var index = -1;\n var length = arguments.length;\n var result;\n while (++index < length) {\n var array = arguments[index];\n result = result ? diff(result, array).concat(diff(array, result)) : array;\n }\n return result ? uniq(result) : [];\n}\n\nfunction uniq(arr) {\n var h = Object.create(null);\n var u = [];\n arr.forEach(function(v) {\n if (v in h) return;\n h[v] = true;\n u.push(v);\n });\n return u;\n}\n\nfunction diff(a, b) {\n var h = Object.create(null);\n b.forEach(function(v) {\n h[v] = true; \n });\n return a.filter(function(v) { return !(v in h);});\n}\nsym([1, 2, 3], [5, 2, 1, 4]);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -151,6 +156,9 @@ "MDNlinks": [ "Global Object" ], + "solutions": [ + "var VALUES = [1, 5, 10, 25, 100, 500, 1000, 2000, 10000];\n\nfunction drawer(price, cash, cid) {\n cash = ~~(cash * 100);\n price = ~~(price * 100);\n var diff = cash-price;\n cid.forEach(function(c) {\n c[1] = ~~(c[1] * 100);\n });\n var totalCid = cid.reduce(function(a, c) {\n return a + c[1];\n }, 0);\n if (diff > totalCid) {\n return \"Insufficient Funds\";\n }\n if (diff === totalCid) {\n return \"Closed\";\n }\n \n var change = []; \n var index = cid.length;\n while (diff > 0 && --index > -1) {\n var t = 0;\n var value = VALUES[index];\n while (diff >= value && cid[index][1] > 0) {\n t += value;\n cid[index][1] -= value;\n diff -= value;\n }\n if (t) {\n change.push([cid[index][0], t/100]);\n }\n console.log(JSON.stringify(change));\n }\n // Here is your change, ma'am.\n return change;\n}\n\n// Example cash-in-drawer array:\n// [['PENNY', 1.01],\n// ['NICKEL', 2.05],\n// ['DIME', 3.10],\n// ['QUARTER', 4.25],\n// ['ONE', 90.00],\n// ['FIVE', 55.00],\n// ['TEN', 20.00],\n// ['TWENTY', 60.00],\n// ['ONE HUNDRED', 100.00]]\n\ndrawer(19.50, 20.00, [['PENNY', 1.01], ['NICKEL', 2.05], ['DIME', 3.10], ['QUARTER', 4.25], ['ONE', 90.00], ['FIVE', 55.00], ['TEN', 20.00], ['TWENTY', 60.00], ['ONE HUNDRED', 100.00]]);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -205,6 +213,9 @@ "MDNlinks": [ "Global Array Object" ], + "solutions": [ + "function inventory(arr1, arr2) {\n arr2.forEach(function(item) {\n createOrUpdate(arr1, item);\n });\n // All inventory must be accounted for or you're fired!\n return arr1;\n}\n\nfunction createOrUpdate(arr1, item) {\n var index = -1;\n while (++index < arr1.length) {\n if (arr1[index][1] === item[1]) {\n arr1[index][0] += item[0];\n return;\n }\n if (arr1[index][1] > item[1]) {\n break;\n }\n }\n arr1.splice(index, 0, item);\n}\n\n// Example inventory lists\nvar curInv = [\n [21, 'Bowling Ball'],\n [2, 'Dirty Sock'],\n [1, 'Hair Pin'],\n [5, 'Microphone']\n];\n\nvar newInv = [\n [2, 'Hair Pin'],\n [3, 'Half-Eaten Apple'],\n [67, 'Bowling Ball'],\n [7, 'Toothpaste']\n];\n\ninventory(curInv, newInv);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -246,6 +257,9 @@ "Permutations", "RegExp" ], + "solutions": [ + "function permAlone(str) {\n return permutor(str).filter(function(perm) {\n return !perm.match(/(.)\\1/g);\n }).length;\n}\n\nfunction permutor(str) {\n // http://staff.roguecc.edu/JMiller/JavaScript/permute.html\n //permArr: Global array which holds the list of permutations\n //usedChars: Global utility array which holds a list of \"currently-in-use\" characters\n var permArr = [], usedChars = [];\n function permute(input) {\n //convert input into a char array (one element for each character)\n var i, ch, chars = input.split(\"\");\n for (i = 0; i < chars.length; i++) {\n //get and remove character at index \"i\" from char array\n ch = chars.splice(i, 1);\n //add removed character to the end of used characters\n usedChars.push(ch);\n //when there are no more characters left in char array to add, add used chars to list of permutations\n if (chars.length === 0) permArr[permArr.length] = usedChars.join(\"\");\n //send characters (minus the removed one from above) from char array to be permuted\n permute(chars.join(\"\"));\n //add removed character back into char array in original position\n chars.splice(i, 0, ch);\n //remove the last character used off the end of used characters array\n usedChars.pop();\n }\n }\n permute(str);\n return permArr;\n}\n\npermAlone('aab');\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -291,6 +305,9 @@ "String.substr()", "parseInt()" ], + "solutions": [ + "function friendly(str) {\n var dates = str.map(function(s) {return s.split('-').map(Number);});\n var start = dates[0];\n var end = dates[1];\n if (str[0] === str[1]) {\n return [readable(start)];\n }\n if (start[0] !== end[0]) {\n if (start[0] + 1 === end[0] && start[1] > end[1]) {\n start[0] = undefined;\n end[0] = undefined;\n }\n return dates.map(readable);\n }\n start[0] = undefined;\n end[0] = undefined;\n if (start[1] !== end[1]) {\n return dates.map(readable);\n }\n end[1] = undefined;\n return dates.map(readable);\n}\n\nfunction readable(arr) {\n var ordD = arr[2] + nth(arr[2]);\n if (!arr[1]) {\n return ordD;\n }\n return MONTH[arr[1]] + \" \" + ordD + (!arr[0] ? \"\" : \", \" + arr[0]);\n}\n\nvar MONTH = {1: \"January\",\n 2: \"February\",\n 3: \"March\",\n 4: \"April\",\n 5: \"May\",\n 6: \"June\",\n 7: \"July\",\n 8: \"August\",\n 9: \"September\",\n 10: \"October\",\n 11: \"November\",\n 12: \"December\"};\n\nfunction nth(d) {\n if(d>3 && d<21) return 'th';\n switch (d % 10) {\n case 1: return \"st\";\n case 2: return \"nd\";\n case 3: return \"rd\";\n default: return \"th\";\n }\n} \n\nfriendly(['2015-07-01', '2015-07-04']);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", diff --git a/seed/challenges/basic-bonfires.json b/seed/challenges/basic-bonfires.json index e2e2fa0e3f..8ac6cbcae7 100644 --- a/seed/challenges/basic-bonfires.json +++ b/seed/challenges/basic-bonfires.json @@ -28,6 +28,9 @@ "", "meetBonfire(\"You can do this!\");" ], + "solutions": [ + "function meetBonfire(argument) {\n // Good luck!\n console.log(\"you can read this function's argument in the developer tools\", argument);\n\n return true;\n}\n\n\n\nmeetBonfire(\"You can do this!\");\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -69,6 +72,9 @@ "Array.reverse()", "Array.join()" ], + "solutions": [ + "function reverseString(str) {\n return str.split('').reverse().join(\"\");\n}\n\nreverseString('hello');\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -109,6 +115,9 @@ "MDNlinks": [ "Arithmetic Operators" ], + "solutions": [ + "function factorialize(num) {\n return num === 1 ? 1 : num * factorialize(num-1);\n}\n\nfactorialize(5);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -159,6 +168,9 @@ "String.replace()", "String.toLowerCase()" ], + "solutions": [ + "function palindrome(str) {\n var a = str.toLowerCase().replace(/[^a-z]/g, '');\n console.log(a.split('').reverse().join(''));\n return a == a.split('').reverse().join('');\n}\n\n\n\npalindrome(\"eye\");\npalindrome(\"A man, a plan, a canal. Panama\");\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -199,6 +211,9 @@ "String.split()", "String.length" ], + "solutions": [ + "function findLongestWord(str) {\n return str.split(' ').sort(function(a, b) { return b.length - a.length;})[0].length;\n}\n\nfindLongestWord('The quick brown fox jumped over the lazy dog');\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -236,6 +251,9 @@ "MDNlinks": [ "String.charAt()" ], + "solutions": [ + "function titleCase(str) {\n return str.split(' ').map(function(word) {\n return word.charAt(0).toUpperCase() + word.substring(1).toLowerCase();\n }).join(' ');\n}\n\ntitleCase(\"I'm a little tea pot\");\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -274,6 +292,9 @@ "MDNlinks": [ "Comparison Operators" ], + "solutions": [ + "function largestOfFour(arr) {\n return arr.map(function(subArr) {\n return Math.max.apply(null, subArr);\n });\n}\n\nlargestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -306,7 +327,7 @@ "tests": [ "assert(end(\"Bastian\", \"n\") === true, 'message: end(\"Bastian\", \"n\") should return true.');", "assert(end(\"Connor\", \"n\") === false, 'message: end(\"Connor\", \"n\") should return false.');", - "assert(end(\"Walking on water and developing software from a specification are easy if both are frozen.\", \"specification\") === false, 'message: end(\"Walking on water and developing software from a specification are easy if both are frozen.\", \"specification\") should return false.');", + "assert(end(\"Walking on water and developing software from a specification are easy if both are frozen\", \"specification\") === false, '\"Walking on water and developing software from a specification are easy if both are frozen\", \"specification\") should return false.');", "assert(end(\"He has to give me a new name\", \"name\") === true, 'message: end(\"He has to give me a new name\", \"name\") should return true.');", "assert(end(\"He has to give me a new name\", \"me\") === true, 'message: end(\"He has to give me a new name\", \"me\") should return true.');", "assert(end(\"If you want to save our world, you must hurry. We dont know how much longer we can withstand the nothing\", \"mountain\") === false, 'message: end(\"If you want to save our world, you must hurry. We dont know how much longer we can withstand the nothing\", \"mountain\") should return false.');" @@ -314,6 +335,9 @@ "MDNlinks": [ "String.substr()" ], + "solutions": [ + "function end(str, target) {\n // \"Never give up and good luck will find you.\"\n // -- Falcor\n return str.substring(str.length-target.length) === target;\n}\n\nend('Bastian', 'n');\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -350,6 +374,9 @@ "MDNlinks": [ "Global String Object" ], + "solutions": [ + "function repeat(str, num) {\n if (num < 0) return '';\n return num === 1 ? str : str + repeat(str, num-1);\n}\n\nrepeat('abc', 3);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -390,6 +417,9 @@ "MDNlinks": [ "String.slice()" ], + "solutions": [ + "function truncate(str, num) {\n if (str.length > num) {\n return str.substring(0, num-3) + '...';\n }\n return str;\n}\n\ntruncate('A-tisket a-tasket A green and yellow basket', 11);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -427,6 +457,9 @@ "MDNlinks": [ "Array.push()" ], + "solutions": [ + "function chunk(arr, size) {\n var out = [];\n for (var i = 0; i < arr.length; i+=size) {\n out.push(arr.slice(i,i+size));\n }\n return out;\n}\n\nchunk(['a', 'b', 'c', 'd'], 2);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -466,6 +499,9 @@ "Array.slice()", "Array.splice()" ], + "solutions": [ + "function slasher(arr, howMany) {\n // it doesn't always pay to be first\n return arr.slice(howMany);\n}\n\nslasher([1, 2, 3], 2);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -509,6 +545,9 @@ "MDNlinks": [ "Array.indexOf()" ], + "solutions": [ + "function mutation(arr) {\n var hash = Object.create(null);\n arr[0].toLowerCase().split('').forEach(function(c) {\n hash[c] = true;\n });\n return !arr[1].toLowerCase().split('').filter(function(c) {\n return !hash[c];\n }).length;\n}\n\nmutation(['hello', 'hey']);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -547,6 +586,9 @@ "Boolean Objects", "Array.filter()" ], + "solutions": [ + "function bouncer(arr) {\n // Don't show a false ID to this bouncer.\n return arr.filter(function(e) {return e;});\n}\n\nbouncer([7, 'ate', '', false, 9]);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -586,6 +628,9 @@ "Arguments object", "Array.filter()" ], + "solutions": [ + "function destroyer(arr) {\n var hash = Object.create(null);\n [].slice.call(arguments, 1).forEach(function(e) {\n hash[e] = true;\n });\n // Remove all the values\n return arr.filter(function(e) { return !(e in hash);});\n}\n\ndestroyer([1, 2, 3, 1, 2, 3], 2, 3);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -603,8 +648,9 @@ "id": "a24c1a4622e3c05097f71d67", "title": "Where do I belong", "description": [ - "Return the lowest index at which a value (second argument) should be inserted into a sorted array (first argument).", - "For example, where([1,2,3,4], 1.5) should return 1 because it is greater than 1 (0th index), but less than 2 (1st index).", + "Return the lowest index at which a value (second argument) should be inserted into an array (first argument) once it has been sorted.", + "For example, where([1,2,3,4], 1.5) should return 1 because it is greater than 1 (index 0), but less than 2 (index 1).", + "Likewise, where([20,3,5], 19) should return 2 because it is less than 20 (index 2) and greater than 5 (index 1).", "Remember to use Read-Search-Ask if you get stuck. Write your own code." ], "challengeSeed": [ @@ -618,12 +664,15 @@ "MDNlinks": [ "Array.sort()" ], + "solutions": [ + "function where(arr, num) {\n // Find my place in this sorted array.\n return num;\n}\n\nwhere([40, 60], 50);\n" + ], "tests": [ "assert(where([10, 20, 30, 40, 50], 35) === 3, 'message: where([10, 20, 30, 40, 50], 35) should return 3.');", "assert(where([10, 20, 30, 40, 50], 30) === 2, 'message: where([10, 20, 30, 40, 50], 30) should return 2.');", "assert(where([40, 60], 50) === 1, 'message: where([40, 60,], 50) should return 1.');", - "assert(where([5, 3, 20, 3], 3) === 0, 'message: where([5, 3, 20, 3], 3) should return 0.');", - "assert(where([2, 20, 10], 1) === 0, 'message: where([2, 20, 10], 1) should return 0.');", + "assert(where([5, 3, 20, 3], 5) === 2, 'message: where([5, 3, 20, 3], 5) should return 2.');", + "assert(where([2, 20, 10], 19) === 2, 'message: where([2, 20, 10], 19) should return 2.');", "assert(where([2, 5, 10], 15) === 3, 'message: where([2, 5, 10], 15) should return 3.');" ], "type": "bonfire", diff --git a/seed/challenges/basic-javascript.json b/seed/challenges/basic-javascript.json index 9ff39ae512..5c9da5407a 100644 --- a/seed/challenges/basic-javascript.json +++ b/seed/challenges/basic-javascript.json @@ -938,7 +938,7 @@ "description": [ "Random numbers are useful for creating random behavior.", "JavaScript has a Math.random() function that generates a random decimal number.", - "Change myFunction to return a random number instead of returning 0." + "Change myFunction to return a random number instead of returning 0.", "Note that you can return a function, just like you would return a variable or value." ], "tests": [ @@ -972,7 +972,7 @@ "Note that because we're rounding down, it's impossible to actually get 20.", "Putting everything together, this is what our code looks like:", "Math.floor(Math.random() * 20);", - "See how Math.floor takes (Math.random() * 20) as its argument? That's right - you can pass a function to another function as an argument." + "See how Math.floor takes (Math.random() * 20) as its argument? That's right - you can pass a function to another function as an argument.", "Let's use this technique to generate and return a random whole number between 0 and 9." ], "tests": [ @@ -1003,7 +1003,7 @@ "title": "Generate Random Whole Numbers within a Range", "description": [ "Instead of generating a random number between zero and a given number like we did before, we can generate a random number that falls within a range of two specific numbers.", - "To do this, we'll define a minimum number min and a maximum number max." + "To do this, we'll define a minimum number min and a maximum number max.", "Here's the formula we'll use. Take a moment to read and try to understand what this code is doing.", "Math.floor(Math.random() * (max - min + 1)) + min", "Define two variables: myMin and myMax, and set them both equal to numbers.", @@ -1035,7 +1035,7 @@ "", "", "", - "", + "", "// Only change code above this line.", "", "", @@ -1186,7 +1186,7 @@ "description": [ "You can invert any match by using the uppercase version of the regular expression selector.", "For example, \\s will match any whitespace, and \\S will match anything that isn't whitespace.", - "Use /\\S/g to count the number of non-whitespace characters in testString.", + "Use /\\S/g to count the number of non-whitespace characters in testString." ], "tests": [ "assert(editor.getValue().match(/\\/\\\\S\\/g/g), 'message: Use the /\\S/g regular expression to find non-space characters in testString.');", @@ -1860,4 +1860,4 @@ "challengeType": 0 } ] -} \ No newline at end of file +} diff --git a/seed/challenges/basic-ziplines.json b/seed/challenges/basic-ziplines.json index 4565f364a8..0cd948d614 100644 --- a/seed/challenges/basic-ziplines.json +++ b/seed/challenges/basic-ziplines.json @@ -35,7 +35,7 @@ [ "http://i.imgur.com/Wzt6Y9Y.gif", "A gif showing the process of saving and forking a pen.", - "Save your pen with the \"Save\" button. Then click the \"Fork\" button. This will create a fork (copy) of your pen that you can experimient with.", + "Save your pen with the \"Save\" button. Then click the \"Fork\" button. This will create a fork (copy) of your pen that you can experiment with.", "" ] ], @@ -68,7 +68,7 @@ "User Story: As a user, I can click different buttons that will take me to the portfolio creator's different social media pages.", "User Story: As a user, I can see thumbnail images of different projects the portfolio creator has built (if you haven't built any websites before, use placeholders.)", "Bonus User Story: As a user, I navigate to different sections of the webpage by clicking buttons in the navigation.", - "Don't worry if you don't have anything to showcase on your portfolio yet - you will build several several apps on the next few CodePen challenges, and can come back and update your portfolio later.", + "Don't worry if you don't have anything to showcase on your portfolio yet - you will build several apps on the next few CodePen challenges, and can come back and update your portfolio later.", "There are many great portfolio templates out there, but for this challenge, you'll need to build a portfolio page yourself. Using Bootstrap will make this much easier for you.", "Note that CodePen.io overrides the Window.open() function, so if you want to open windows using jquery, you will need to target invisible anchor elements like this one: <a target='_blank'>.", "Remember to use Read-Search-Ask if you get stuck.", diff --git a/seed/challenges/bootstrap.json b/seed/challenges/bootstrap.json index e921750ae7..239ecf1903 100644 --- a/seed/challenges/bootstrap.json +++ b/seed/challenges/bootstrap.json @@ -93,14 +93,15 @@ "id": "bad87fee1348bd9acde08812", "title": "Make Images Mobile Responsive", "description": [ - "First, add a new image below the existing one. Set it's src attribute to http://bit.ly/fcc-running-cats.", + "First, add a new image below the existing one. Set its src attribute to http://bit.ly/fcc-running-cats.", "It would be great if this image could be exactly the width of our phone's screen.", "Fortunately, with Bootstrap, all we need to do is add the img-responsive class to your image. Do this, and the image should perfectly fit the width of your page." ], "tests": [ - "assert($(\"img\").length > 1, 'You should have a total of two images.')", - "assert($(\"img\").hasClass(\"img-responsive\"), 'Your new image should have the class img-responsive')", - "assert(new RegExp(\"http://bit.ly/fcc-running-cats\", \"gi\").test($(\"img.img-responsive\").attr(\"src\")), 'Add a second image with the src of http://bit.ly/fcc-running-cats')" + "assert($(\"img\").length === 2, 'You should have a total of two images.')", + "assert($(\"img:eq(1)\").hasClass(\"img-responsive\"), 'Your new image should be below your old one and have the class img-responsive.')", + "assert($(\"img:eq(1)\").attr(\"src\") === \"http://bit.ly/fcc-running-cats\", 'Your new image should have a src of http://bit.ly/fcc-running-cats.')", + "assert(editor.match(//g).length === 2 && editor.match(/img element has a closing angle bracket.')" ], "challengeSeed": [ "", @@ -178,8 +179,7 @@ "title": "Center Text with Bootstrap", "description": [ "Now that we're using Bootstrap, we can center our heading element to make it look better. All we need to do is add the class text-center to our h2 element.", - "Remember that you can add several classes to the same element by separating each of them with a space, like this:", - "<h2 class=\"red-text text-center\">your text</h2>" + "Remember that you can add several classes to the same element by separating each of them with a space, like this: <h2 class=\"red-text text-center\">your text</h2>." ], "tests": [ "assert($(\"h2\").hasClass(\"text-center\"), 'Your h2 element should be centered by applying the class text-center')" @@ -345,7 +345,7 @@ "id": "bad87fee1348cd8acef08812", "title": "Create a Block Element Bootstrap Button", "description": [ - "Normally, your button elements are only as wide as the text that they contain. By making them block elements, your button will stretch to fill your page's entire horizontal space.", + "Normally, your button elements are only as wide as the text that they contain. By making them block elements, your button will stretch to fill your page's entire horizontal space and any elements following it will flow onto a \"new line\" below the block.", "This image illustrates the difference between inline elements and block-level elements:", "\"An", "Note that these buttons still need the btn class.", @@ -892,8 +892,7 @@ "\"An", "By using the span element, you can put several elements together, and even style different parts of the same element differently.", "Nest the word \"love\" in your \"Things cats love\" element below within a span element. Then give that span the class text-danger to make the text red.", - "Here's how you would do this with the \"Top 3 things cats hate\" element:", - "<p>Top 3 things cats <span class = \"text-danger\">hate</span></p>" + "Here's how you would do this with the \"Top 3 things cats hate\" element: <p>Top 3 things cats <span class = \"text-danger\">hate</span></p>" ], "tests": [ "assert($(\"p span\") && $(\"p span\").length > 0, 'Your span element should be inside your p element.')", @@ -1909,7 +1908,7 @@ "title": "Add ID Attributes to Bootstrap Elements", "description": [ "Recall that in addition to class attributes, you can give each of your elements an id attribute.", - "Each id should be unique to a specific element.", + "Each id must be unique to a specific element and used only once per page.", "Let's give a unique id to each of our div elements of class well.", "Remember that you can give an element an id like this:", "<div class=\"well\" id=\"center-well\">", @@ -2008,7 +2007,7 @@ "title": "Give Each Element a Unique ID", "description": [ "We will also want to be able to use jQuery to target each button by its unique id.", - "Give each of your buttons a unique id, starting with target1 and ending with target6." + "Give each of your buttons a unique id like, starting with target1 and ending with target6." ], "tests": [ "assert($(\"#left-well\").children(\"#target1\") && $(\"#left-well\").children(\"#target1\").length > 0, 'One button element should have the id target1.')", @@ -2059,7 +2058,7 @@ "title": "Label Bootstrap Buttons", "description": [ "Just like we labeled our wells, we want to label our buttons.", - "Give each of your button elements text that corresponds to its id." + "Give each of your button elements text that corresponds to their id." ], "tests": [ "assert(new RegExp(\"#target1\",\"gi\").test($(\"#target1\").text()), 'Give your button element with the id target1 the text #target1.')", @@ -2116,7 +2115,7 @@ ], "tests": [ "assert(editor.match(/.*\\n+.+/g), 'Be sure to close your comment with -->.')" ], "challengeSeed": [ diff --git a/seed/challenges/html5-and-css.json b/seed/challenges/html5-and-css.json index 1ebf6e3858..58adc46b54 100644 --- a/seed/challenges/html5-and-css.json +++ b/seed/challenges/html5-and-css.json @@ -390,6 +390,7 @@ "assert(!$(\"h2\").attr(\"style\"), 'Remove the style attribute from your h2 element.')", "assert($(\"style\") && $(\"style\").length > 1, 'Create a style element.')", "assert($(\"h2\").css(\"color\") === \"rgb(0, 0, 255)\", 'Your h2 element should be blue.')", + "assert(editor.match(/h2\\s*\\{\\s*color:\\s*blue;\\s*\\}/g), 'Ensure that your stylesheet h2 declaration is valid with a semicolon and closing brace')", "assert(editor.match(/<\\/style>/g) && editor.match(/<\\/style>/g).length === (editor.match(//g) || []).length, 'Make sure all your style elements are valid and have a closing tag.')" ], "challengeSeed": [ @@ -449,6 +450,7 @@ "tests": [ "assert($(\"h2\").css(\"color\") === \"rgb(255, 0, 0)\", 'Your h2 element should be red.')", "assert($(\"h2\").hasClass(\"red-text\"), 'Your h2 element should have the class red-text.')", + "assert(editor.match(/\\.red-text\\s*\\{\\s*color:\\s*red;\\s*\\}/g), 'Your stylesheet should declare a red-text class and have its color set to red.')", "assert($(\"h2\").attr(\"style\") === undefined, 'Do not use inline style declarations like style=\"color: red\" in your h2 element.')" ], "challengeSeed": [ diff --git a/seed/challenges/intermediate-bonfires.json b/seed/challenges/intermediate-bonfires.json index d8b008208d..9ae783a1a5 100644 --- a/seed/challenges/intermediate-bonfires.json +++ b/seed/challenges/intermediate-bonfires.json @@ -30,6 +30,9 @@ "Math.min()", "Array.reduce()" ], + "solutions": [ + "function sumAll(arr) {\n var sum = 0;\n arr.sort(function(a,b) {return a-b;});\n for (var i = arr[0]; i <= arr[1]; i++) {\n sum += i; \n }\n return sum;\n}\n\nsumAll([1, 4]);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -76,6 +79,9 @@ "Array.indexOf()", "Array.concat()" ], + "solutions": [ + "function diff(arr1, arr2) {\n var newArr = [];\n var h1 = Object.create(null);\n arr1.forEach(function(e) {\n h1[e] = e;\n });\n \n var h2 = Object.create(null);\n arr2.forEach(function(e) {\n h2[e] = e;\n });\n \n Object.keys(h1).forEach(function(e) {\n if (!(e in h2)) newArr.push(h1[e]);\n });\n Object.keys(h2).forEach(function(e) {\n if (!(e in h1)) newArr.push(h2[e]);\n });\n // Same, same; but different.\n return newArr;\n}\n\ndiff([1, 2, 3, 5], [1, 2, 3, 4, 5]);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -93,11 +99,25 @@ "id": "a7f4d8f2483413a6ce226cac", "title": "Roman Numeral Converter", "tests": [ - "assert.deepEqual(convert(12), \"XII\", 'message: convert(12) should return \"XII\".');", "assert.deepEqual(convert(5), \"V\", 'message: convert(5) should return \"V\".');", "assert.deepEqual(convert(9), \"IX\", 'message: convert(9) should return \"IX\".');", + "assert.deepEqual(convert(12), \"XII\", 'message: convert(12) should return \"XII\".');", + "assert.deepEqual(convert(16), \"XVI\", 'message: convert(16) should return \"XVI\".');", "assert.deepEqual(convert(29), \"XXIX\", 'message: convert(29) should return \"XXIX\".');", - "assert.deepEqual(convert(16), \"XVI\", 'message: convert(16) should return \"XVI\".');" + "assert.deepEqual(convert(44), \"XLIV\", 'message: convert(44) should return \"XLIV\".');", + "assert.deepEqual(convert(45), \"XLV\", 'convert(45) should return \"XLV\"');", + "assert.deepEqual(convert(68), \"LXVIII\", 'convert(68) should return \"LXVIII\"');", + "assert.deepEqual(convert(83), \"LXXXIII\", 'convert(83) should return \"LXXXIII\"');", + "assert.deepEqual(convert(97), \"XCVII\", 'convert(97) should return \"XCVII\"');", + "assert.deepEqual(convert(99), \"XCIX\", 'convert(99) should return \"XCIX\"');", + "assert.deepEqual(convert(500), \"D\", 'convert(500) should return \"D\"');", + "assert.deepEqual(convert(501), \"DI\", 'convert(501) should return \"DI\"');", + "assert.deepEqual(convert(649), \"DCXLIX\", 'convert(649) should return \"DCXLIX\"');", + "assert.deepEqual(convert(798), \"DCCXCVIII\", 'convert(798) should return \"DCCXCVIII\"');", + "assert.deepEqual(convert(891), \"DCCCXCI\", 'convert(891) should return \"DCCCXCI\"');", + "assert.deepEqual(convert(1000), \"M\", 'convert(1000) should return \"M\"');", + "assert.deepEqual(convert(1004), \"MIV\", 'convert(1004) should return \"MIV\"');", + "assert.deepEqual(convert(1006), \"MVI\", 'convert(1006) should return \"MVI\"');" ], "description": [ "Convert the given number into a roman numeral.", @@ -117,6 +137,9 @@ "Array.indexOf()", "Array.join()" ], + "solutions": [ + "function convert(num) {\n var ref = [['M', 1000], ['CM', 900], ['D', 500], ['CD', 400], ['C', 100], ['XC', 90], ['L', 50], ['XL', 40], ['X', 10], ['IX', 9], ['V', 5], ['IV', 4], ['I', 1]];\n var res = [];\n ref.forEach(function(p) {\n while (num >= p[1]) {\n res.push(p[0]);\n num -= p[1];\n }\n });\n return res.join('');\n}\n\nconvert(36);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -148,7 +171,7 @@ "where([{ 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\" }], 'message: where() should return an array of objects.');", + "assert.deepEqual(where([{ first: \"Romeo\", last: \"Montague\" }, { first: \"Mercutio\", last: null }, { first: \"Tybalt\", last: \"Capulet\" }], { last: \"Capulet\" }), [{ first: \"Tybalt\", last: \"Capulet\" }], 'message: where([{ first: \"Romeo\", last: \"Montague\" }, { first: \"Mercutio\", last: null }, { first: \"Tybalt\", last: \"Capulet\" }], { last: \"Capulet\" }) should return [{ first: \"Tybalt\", last: \"Capulet\" }].');", "assert.deepEqual(where([{ \"a\": 1 }, { \"a\": 1 }, { \"a\": 1, \"b\": 2 }], { \"a\": 1 }), [{ \"a\": 1 }, { \"a\": 1 }, { \"a\": 1, \"b\": 2 }], 'message: where([{ \"a\": 1 }, { \"a\": 1 }, { \"a\": 1, \"b\": 2 }], { \"a\": 1 }) should return [{ \"a\": 1 }, { \"a\": 1 }, { \"a\": 1, \"b\": 2 }].');", "assert.deepEqual(where([{ \"a\": 1, \"b\": 2 }, { \"a\": 1 }, { \"a\": 1, \"b\": 2, \"c\": 2 }], { \"a\": 1, \"b\": 2 }), [{ \"a\": 1, \"b\": 2 }, { \"a\": 1, \"b\": 2, \"c\": 2 }], 'message: where([{ \"a\": 1, \"b\": 2 }, { \"a\": 1 }, { \"a\": 1, \"b\": 2, \"c\": 2 }], { \"a\": 1, \"b\": 2 }) should return [{ \"a\": 1, \"b\": 2 }, { \"a\": 1, \"b\": 2, \"c\": 2 }].');" ], @@ -157,6 +180,9 @@ "Object.hasOwnProperty()", "Object.keys()" ], + "solutions": [ + "function where(collection, source) {\n var arr = [];\n var keys = Object.keys(source);\n collection.forEach(function(e) {\n if(keys.every(function(key) {return e[key] === source[key];})) {\n arr.push(e); \n }\n });\n return arr;\n}\n\nwhere([{ first: 'Romeo', last: 'Montague' }, { first: 'Mercutio', last: null }, { first: 'Tybalt', last: 'Capulet' }], { last: 'Capulet' });\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -176,7 +202,7 @@ "tests": [ "assert.deepEqual(myReplace(\"Let us go to the store\", \"store\", \"mall\"), \"Let us go to the mall\", 'message: myReplace(\"Let us go to the store\", \"store\", \"mall\") should return \"Let us go to the mall\".');", "assert.deepEqual(myReplace(\"He is Sleeping on the couch\", \"Sleeping\", \"sitting\"), \"He is Sitting on the couch\", 'message: myReplace(\"He is Sleeping on the couch\", \"Sleeping\", \"sitting\") should return \"He is Sitting on the couch\".');", - "assert.deepEqual(myReplace(\"This has a spellngi error\", \"spellngi\", \"spelling\"), \"This has a spelling error\", 'message: myReplace(\"This has a spellngi error\", \"spellingi\", \"spelling\") should return \"This has a spelling error\".');", + "assert.deepEqual(myReplace(\"This has a spellngi error\", \"spellngi\", \"spelling\"), \"This has a spelling error\", 'message: myReplace(\"This has a spellngi error\", \"spellngi\", \"spelling\") should return \"This has a spelling error\".');", "assert.deepEqual(myReplace(\"His name is Tom\", \"Tom\", \"john\"), \"His name is John\", 'message: myReplace(\"His name is Tom\", \"Tom\", \"john\") should return \"His name is John\".');", "assert.deepEqual(myReplace(\"Let us get back to more Coding\", \"Coding\", \"bonfires\"), \"Let us get back to more Bonfires\", 'message: myReplace(\"Let us get back to more Coding\", \"Coding\", \"bonfires\") should return \"Let us get back to more Bonfires\".');" ], @@ -200,6 +226,9 @@ "String.replace()", "Array.join()" ], + "solutions": [ + "function replace(str, before, after) {\n if (before.charAt(0) === before.charAt(0).toUpperCase()) {\n after = after.charAt(0).toUpperCase() + after.substring(1);\n } else {\n after = after.charAt(0).toLowerCase() + after.substring(1);\n }\n return str.replace(before, after);\n}\n\nreplace(\"A quick brown fox jumped over the lazy dog\", \"jumped\", \"leaped\");\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -243,6 +272,9 @@ "String.substr()", "String.split()" ], + "solutions": [ + "function translate(str) {\n if (isVowel(str.charAt(0))) return str + \"way\";\n var front = [];\n str = str.split('');\n while (str.length && !isVowel(str[0])) {\n front.push(str.shift());\n }\n return [].concat(str, front).join('') + 'ay';\n}\n\nfunction isVowel(c) {\n return ['a', 'e', 'i', 'o', 'u'].indexOf(c.toLowerCase()) !== -1;\n}\n\ntranslate(\"consonant\");\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -283,6 +315,9 @@ "Array.push()", "String.split()" ], + "solutions": [ + "var lookup = Object.create(null);\nlookup.A = 'T';\nlookup.T = 'A';\nlookup.C = 'G';\nlookup.G = 'C';\n\nfunction pair(str) {\n return str.split('').map(function(p) {return [p, lookup[p]];});\n}\n\npair(\"GCG\");\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -321,6 +356,9 @@ "String.charCodeAt()", "String.fromCharCode()" ], + "solutions": [ + "function fearNotLetter(str) {\n var s = str.split('').map(function(c) {return c.charCodeAt(0);});\n for (var i = 1; i < s.length; i++) {\n if (s[i]-1 != s[i-1]) {\n return String.fromCharCode(s[i]-1);\n }\n }\n}\n\nfearNotLetter('abce');\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -363,6 +401,9 @@ "MDNlinks": [ "Boolean Objects" ], + "solutions": [ + "function boo(bool) {\n // What is the new fad diet for ghost developers? The Boolean.\n return typeof(bool) === \"boolean\";\n}\n\nboo(null);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -403,6 +444,9 @@ "Arguments object", "Array.reduce()" ], + "solutions": [ + "function unite(arr1, arr2, arr3) {\n return [].slice.call(arguments).reduce(function(a, b) {\n return [].concat(a, b.filter(function(e) {return a.indexOf(e) === -1;}));\n }, []);\n}\n\nunite([1, 2, 3], [5, 2, 1, 4], [2, 1]);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -444,6 +488,9 @@ "RegExp", "HTML Entities" ], + "solutions": [ + "var MAP = { '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": '''};\n\nfunction convert(str) {\n return str.replace(/[&<>\"']/g, function(c) {\n return MAP[c];\n });\n}\n\nconvert('Dolce & Gabbana');\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -483,6 +530,9 @@ "RegExp", "String.replace()" ], + "solutions": [ + "function spinalCase(str) {\n // \"It's such a fine line between stupid, and clever.\"\n // --David St. Hubbins\n str = str.replace(/([a-z](?=[A-Z]))/g, '$1 ');\n return str.toLowerCase().replace(/\\ |\\_/g, '-');\n}\n\nspinalCase('This Is Spinal Tap');\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -523,6 +573,9 @@ "MDNlinks": [ "Remainder" ], + "solutions": [ + "function sumFibs(num) {\n var a = 1; \n var b = 1;\n var s = 0;\n while (a <= num) {\n if (a % 2 !== 0) { \n s += a; \n }\n a = [b, b=b+a][0];\n }\n return s;\n}\n\nsumFibs(4);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -561,6 +614,9 @@ "For Loops", "Array.push()" ], + "solutions": [ + "function eratosthenesArray(n) {\n var primes = [];\n if (n > 2) {\n var half = n>>1;\n var sieve = Array(half);\n for (var i = 1, limit = Math.sqrt(n)>>1; i <= limit; i++) {\n if (!sieve[i]) {\n for (var step = 2*i+1, j = (step*step)>>1; j < half; j+=step) {\n sieve[j] = true;\n }\n }\n }\n primes.push(2);\n for (var p = 1; p < half; p++) {\n if (!sieve[p]) primes.push(2*p+1);\n }\n }\n return primes;\n}\n\nfunction sumPrimes(num) {\n return eratosthenesArray(num+1).reduce(function(a,b) {return a+b;}, 0);\n}\n\nsumPrimes(10);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -600,6 +656,9 @@ "MDNlinks": [ "Smallest Common Multiple" ], + "solutions": [ + "function gcd(a, b) {\n while (b !== 0) {\n a = [b, b = a % b][0];\n }\n return a;\n}\n\nfunction lcm(a, b) {\n return (a * b) / gcd(a, b);\n}\n\nfunction smallestCommons(arr) {\n arr.sort(function(a,b) {return a-b;});\n var rng = [];\n for (var i = arr[0]; i <= arr[1]; i++) {\n rng.push(i);\n }\n return rng.reduce(lcm);\n}\n\n\nsmallestCommons([1,5]);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -633,7 +692,10 @@ "assert.strictEqual(find([1, 3, 5, 9], function(num) { return num % 2 === 0; }), undefined, 'message: find([1, 3, 5, 9], function(num) { return num % 2 === 0; }) should return undefined.');" ], "MDNlinks": [ - "Array.some()" + "Array.filter()" + ], + "solutions": [ + "function find(arr, func) {\n var num;\n arr.some(function(e) {\n if (func(e)) {\n num = e;\n return true;\n }\n });\n return num;\n}\n\nfind([1, 2, 3, 4], function(num){ return num % 2 === 0; });\n" ], "type": "bonfire", "challengeType": 5, @@ -664,15 +726,18 @@ "drop([1, 2, 3], function(n) {return n < 3; });" ], "tests": [ - "assert.deepEqual(drop([1, 2, 3, 4], function(n) {return n>= 3;}), [3, 4], 'message: drop([1, 2, 3, 4], function(n) {return n>= 3;}) should return [3, 4].');", + "assert.deepEqual(drop([1, 2, 3, 4], function(n) {return n>= 3;}), [3, 4], 'message: drop([1, 2, 3, 4], function(n) {return n >= 3;}) should return [3, 4].');", "assert.deepEqual(drop([1, 2, 3], function(n) {return n > 0; }), [1, 2, 3], 'message: drop([1, 2, 3], function(n) {return n > 0; }) should return [1, 2, 3].');", "assert.deepEqual(drop([1, 2, 3, 4], function(n) {return n > 5;}), [], 'message: drop([1, 2, 3, 4], function(n) {return n > 5;}) should return [].');", - "assert.deepEqual(drop([1, 2, 3, 7, 4], function(n) {return n > 3}), [7, 4], 'message: drop([1, 2, 3, 7, 4], function(n) {return n>= 3}) should return [7, 4].');" + "assert.deepEqual(drop([1, 2, 3, 7, 4], function(n) {return n > 3}), [7, 4], 'message: drop([1, 2, 3, 7, 4], function(n) {return n > 3}) should return [7, 4].');" ], "MDNlinks": [ "Arguments object", "Array.shift()" ], + "solutions": [ + "(function drop(arr, func) {\n // Drop them elements.\n while (arr.length && !func(arr[0])) {\n arr.shift();\n }\n return arr;\n}\n\ndrop([1, 2, 3], function(n) {return n < 3; });\n)" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -710,6 +775,9 @@ "MDNlinks": [ "Array.isArray()" ], + "solutions": [ + "function steamroller(arr) {\n if (!Array.isArray(arr)) {\n return [arr];\n }\n var out = [];\n arr.forEach(function(e) {\n steamroller(e).forEach(function(v) {\n out.push(v);\n });\n });\n return out;\n}\n\nsteamroller([1, [2], [3, [[4]]]]);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -746,6 +814,9 @@ "String.charCodeAt()", "String.fromCharCode()" ], + "solutions": [ + "function binaryAgent(str) {\n return str.split(' ').map(function(s) { return parseInt(s, 2); }).map(function(b) { return String.fromCharCode(b);}).join('');\n}\n\nbinaryAgent('01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111');\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", @@ -763,14 +834,13 @@ "id": "a10d2431ad0c6a099a4b8b52", "title": "Everything Be True", "description": [ - "Check if the predicate (second argument) returns truthy (defined) for all elements of a collection (first argument).", - "For this, check to see if the property defined in the second argument is present on every element of the collection.", + "Check if the predicate (second argument) is truthy on all elements of a collection (first argument).", "Remember, you can access object properties through either dot notation or [] notation.", "Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code." ], "challengeSeed": [ "function every(collection, pre) {", - " // Does everyone have one of these?", + " // Is everyone being true?", " return pre;", "}", "", @@ -778,12 +848,17 @@ ], "tests": [ "assert.strictEqual(every([{\"user\": \"Tinky-Winky\", \"sex\": \"male\"}, {\"user\": \"Dipsy\", \"sex\": \"male\"}, {\"user\": \"Laa-Laa\", \"sex\": \"female\"}, {\"user\": \"Po\", \"sex\": \"female\"}], \"sex\"), true, 'message: every([{\"user\": \"Tinky-Winky\", \"sex\": \"male\"}, {\"user\": \"Dipsy\", \"sex\": \"male\"}, {\"user\": \"Laa-Laa\", \"sex\": \"female\"}, {\"user\": \"Po\", \"sex\": \"female\"}], \"sex\") should return true.');", - "assert.strictEqual(every([{\"user\": \"Tinky-Winky\", \"sex\": \"male\"}, {\"user\": \"Dipsy\", \"sex\": \"male\"}, {\"user\": \"Laa-Laa\", \"sex\": \"female\"}, {\"user\": \"Po\", \"sex\": \"female\"}], {\"sex\": \"female\"}), false, 'message: every([{\"user\": \"Tinky-Winky\", \"sex\": \"male\"}, {\"user\": \"Dipsy\", \"sex\": \"male\"}, {\"user\": \"Laa-Laa\", \"sex\": \"female\"}, {\"user\": \"Po\", \"sex\": \"female\"}], {\"sex\": \"female\"}) should return false.');", - "assert.strictEqual(every([{\"user\": \"Tinky-Winky\", \"sex\": \"female\"}, {\"user\": \"Dipsy\", \"sex\": \"male\"}, {\"user\": \"Laa-Laa\", \"sex\": \"female\"}, {\"user\": \"Po\", \"sex\": \"female\"}], {\"sex\": \"female\"}), false, 'message: every([{\"user\": \"Tinky-Winky\", \"sex\": \"female\"}, {\"user\": \"Dipsy\", \"sex\": \"male\"}, {\"user\": \"Laa-Laa\", \"sex\": \"female\"}, {\"user\": \"Po\", \"sex\": \"female\"}], {\"sex\": \"female\"}) should return false.');" + "assert.strictEqual(every([{\"user\": \"Tinky-Winky\", \"sex\": \"male\"}, {\"user\": \"Dipsy\"}, {\"user\": \"Laa-Laa\", \"sex\": \"female\"}, {\"user\": \"Po\", \"sex\": \"female\"}], \"sex\"), false, 'message: every([{\"user\": \"Tinky-Winky\", \"sex\": \"male\"}, {\"user\": \"Dipsy\"}, {\"user\": \"Laa-Laa\", \"sex\": \"female\"}, {\"user\": \"Po\", \"sex\": \"female\"}], \"sex\") should return false.');", + "assert.strictEqual(every([{\"user\": \"Tinky-Winky\", \"sex\": \"male\", \"age\": 2}, {\"user\": \"Dipsy\", \"sex\": \"male\", \"age\": 0}, {\"user\": \"Laa-Laa\", \"sex\": \"female\", \"age\": 5}, {\"user\": \"Po\", \"sex\": \"female\", \"age\": 4}], \"age\"), false, 'message: every([{\"user\": \"Tinky-Winky\", \"sex\": \"male\", \"age\": 0}, {\"user\": \"Dipsy\", \"sex\": \"male\", \"age\": 3}, {\"user\": \"Laa-Laa\", \"sex\": \"female\", \"age\": 5}, {\"user\": \"Po\", \"sex\": \"female\", \"age\": 4}], \"age\") should return false.');", + "assert.strictEqual(every([{\"name\": \"Pete\", \"onBoat\": true}, {\"name\": \"Repeat\", \"onBoat\": true}, {\"name\": \"FastFoward\", \"onBoat\": null}], \"onBoat\"), false, 'message: every([{\"name\": \"Pete\", \"onBoat\": true}, {\"name\": \"Repeat\", \"onBoat\": true}, {\"name\": \"FastFoward\", \"onBoat\": null}], \"onBoat\") should return false');", + "assert.strictEqual(every([{\"name\": \"Pete\", \"onBoat\": true}, {\"name\": \"Repeat\", \"onBoat\": true, \"alias\": \"Repete\"}, {\"name\": \"FastFoward\", \"onBoat\": true}], \"onBoat\"), true, 'message: every([{\"name\": \"Pete\", \"onBoat\": true}, {\"name\": \"Repeat\", \"onBoat\": true, \"alias\": \"Repete\"}, {\"name\": \"FastFoward\", \"onBoat\": true}], \"onBoat\") should return true');", + "assert.strictEqual(every([{\"single\": \"yes\"}], \"single\"), true, 'message: every([{\"single\": \"yes\"}], \"single\") should return true');", + "assert.strictEqual(every([{\"single\": \"\"}, {\"single\": \"double\"}], \"single\"), false, 'message: every([{\"single\": \"\"}, {\"single\": \"double\"}], \"single\") should return false');", + "assert.strictEqual(every([{\"single\": \"double\"}, {\"single\": undefined}], \"single\"), false, 'message: every([{\"single\": \"double\"}, {\"single\": undefined}], \"single\") should return false');", + "assert.strictEqual(every([{\"single\": \"double\"}, {\"single\": NaN}], \"single\"), false, 'message: every([{\"single\": \"double\"}, {\"single\": NaN}], \"single\") should return false');" ], - "MDNlinks": [ - "Object.hasOwnProperty()", - "Object.getOwnPropertyNames()" + "solutions": [ + "function every(collection, pre) {\n // Does everyone have one of these?\n return collection.every(function(e) { return e[pre]; });\n}\n\nevery([{'user': 'Tinky-Winky', 'sex': 'male'}, {'user': 'Dipsy', 'sex': 'male'}, {'user': 'Laa-Laa', 'sex': 'female'}, {'user': 'Po', 'sex': 'female'}], 'sex');\n" ], "type": "bonfire", "challengeType": 5, @@ -828,6 +903,10 @@ "Closures", "Arguments object" ], + "solutions": [ + "function add() {\n if (arguments.length == 1) {\n var a = arguments[0];\n if (!isNumber(a)) return;\n return function(b) {\n if (!isNumber(b)) return;\n return a+b;\n };\n }\n if (![].slice.call(arguments).every(isNumber)) return;\n return arguments[0] + arguments[1];\n}\n \nfunction isNumber(obj) {\n return toString.call(obj) == '[object Number]';\n}\n\nadd(2,3);\n", + "function add() {\n var a = arguments[0];\n if (toString.call(a) !== '[object Number]') return; \n if (arguments.length === 1) {\n return function(b) {\n if (toString.call(b) !== '[object Number]') return;\n return a + b;\n };\n }\n var b = arguments[1];\n if (toString.call(b) !== '[object Number]') return; \n return a + arguments[1];\n}\n\nadd(2,3);\n" + ], "type": "bonfire", "challengeType": 5, "nameCn": "", diff --git a/seed/challenges/intermediate-ziplines.json b/seed/challenges/intermediate-ziplines.json index fd3ea5b5e9..0d2afbcb5c 100644 --- a/seed/challenges/intermediate-ziplines.json +++ b/seed/challenges/intermediate-ziplines.json @@ -8,7 +8,7 @@ "title": "Show the Local Weather", "challengeSeed": ["126415127"], "description": [ - "Objective: Build a CodePen.io app that successfully reverse-engineers this: http://codepen.io/AdventureBear/full/yNBJRj.", + "Objective: Build a CodePen.io app that successfully reverse-engineers this: http://codepen.io/FreeCodeCamp/pen/avqvgJ.", "Rule #1: Don't look at the example project's code on CodePen. Figure it out for yourself.", "Rule #2: You may use whichever libraries or APIs you need.", "Rule #3: Reverse engineer the example project's functionality, and also feel free to personalize it.", @@ -17,6 +17,7 @@ "Bonus User Story: As a user, I can see an icon depending on the weather.", "Bonus User Story: As a user, I see a different background image (e.g. snowy mountain, hot desert) depending on the weather.", "Bonus User Story: As a user, I can push a button to toggle between Fahrenheit and Celsius.", + "We recommend using the Open Weather API. This will require creating a free API key. Normally you want to avoid exposing API keys on CodePen, but we haven't been able to find a keyless API for weather.", "Remember to use Read-Search-Ask if you get stuck.", "When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen. If you pair programmed, you should also include the Free Code Camp username of your pair.", "If you'd like immediate feedback on your project from fellow campers, click this button and paste in a link to your CodePen project.

Click here then add your link to your tweet's text" diff --git a/seed/challenges/jquery.json b/seed/challenges/jquery.json index 5dca551d39..ef51837c3c 100644 --- a/seed/challenges/jquery.json +++ b/seed/challenges/jquery.json @@ -16,8 +16,7 @@ "This is important because without your document ready function, your code may run before your HTML is rendered, which would cause bugs." ], "tests": [ - "assert(editor.match(/