Merge pull request #4115 from FreeCodeCamp/feature/add-challenge-testing

Add challenge testing
This commit is contained in:
Logan Tegman
2015-11-01 23:23:00 -08:00
16 changed files with 198 additions and 596 deletions

View File

@ -1,7 +1,6 @@
language: node_js language: node_js
node_js: node_js:
- 'node' - '4.2.1'
- '1.6.4'
sudo: false sudo: false

View File

@ -13,7 +13,11 @@
"prestart-production": "bower cache clean && bower install && gulp build", "prestart-production": "bower cache clean && bower install && gulp build",
"start-production": "node pm2Start", "start-production": "node pm2Start",
"lint": "eslint --ext=.js,.jsx .", "lint": "eslint --ext=.js,.jsx .",
"test": "gulp test-challenges" "lint-challenges": "jsonlint -q seed/challenges/*.json",
"lint-nonprofits": "jsonlint -q seed/nonprofits.json",
"test-challenges": "babel-node seed/test-challenges.js | tnyan",
"pretest": "npm run lint-challenges && npm run lint-nonprofits",
"test": "npm run test-challenges"
}, },
"license": "(BSD-3-Clause AND CC-BY-SA-4.0)", "license": "(BSD-3-Clause AND CC-BY-SA-4.0)",
"dependencies": { "dependencies": {
@ -124,11 +128,14 @@
"chai": "~1.10.0", "chai": "~1.10.0",
"envify": "^3.4.0", "envify": "^3.4.0",
"istanbul": "^0.3.15", "istanbul": "^0.3.15",
"jsonlint": "^1.6.2",
"loopback-explorer": "^1.7.2", "loopback-explorer": "^1.7.2",
"loopback-testing": "^1.1.0", "loopback-testing": "^1.1.0",
"mocha": "~2.0.1", "mocha": "~2.0.1",
"multiline": "~1.0.1", "multiline": "~1.0.1",
"supertest": "~0.15.0", "supertest": "~0.15.0",
"tap-nyan": "0.0.2",
"tape": "^4.2.2",
"vinyl-source-stream": "^1.1.0" "vinyl-source-stream": "^1.1.0"
} }
} }

View File

@ -1,44 +0,0 @@
require('dotenv').load();
var bonfires = require('./bonfires.json'),
app = require('../server/server'),
mongodb = require('mongodb'),
MongoClient = mongodb.MongoClient,
User = app.models.User,
UserIdentity = app.models.userIdentity,
oldUri='mongodb://localhost:27017/app30893198',
coursewares = require('./coursewares.json');
MongoClient.connect(oldUri, function(err, database) {
database.collection('users').find({}).batchSize(20).toArray(function(err, users) {
if (users !== null && users.length !== 0) {
var mappedUserArray = users.map(function(user) {
Object.keys(user.profile).forEach(function(prop) {
user[prop] = user.profile[prop];
});
Object.keys(user.portfolio).forEach(function(prop) {
user[prop] = user.portfolio[prop];
});
user.completedCoursewares = Object.keys(user.challengesHash)
.filter(function(key) {
return user.challengesHash[key] !== 0;
})
.map(function(key) {
return({
id: coursewares[key].id,
completedDate: user.challengesHash[key]
});
});
return user;
});
User.create(mappedUserArray, function(err) {
if (err) {
console.log(err);
}
console.log("a batch finished");
});
}
});
});

View File

@ -1,226 +0,0 @@
[
{
"oldNumber": "0",
"newId": "bd7124d8c441eddfaeb5bdef"
},
{
"oldNumber": "1",
"newId": "bd7125d8c441eddfaeb5bd0f"
},
{
"oldNumber": "2",
"newId": ""
},
{
"oldNumber": "3",
"newId": "bd7127d8c441eddfaeb5bdef"
},
{
"oldNumber": "4",
"newId": "bd7128d8c441eddfaeb5bdef"
},
{
"oldNumber": "5",
"newId": "bd8129d8c441eddfaeb5bdef"
},
{
"oldNumber": "6",
"newId": ""
},
{
"oldNumber": "7",
"newId": ""
},
{
"oldNumber": "8",
"newId": "bd7112d8c441eddfaeb5bdef"
},
{
"oldNumber": "9",
"newId": "bd7113d8c441eddfaeb5bdef"
},
{
"oldNumber": "10",
"newId": "bd7114d8c441eddfaeb5bdef"
},
{
"oldNumber": "11",
"newId": "bd7115d8c441eddfaeb5bdef"
},
{
"oldNumber": "12",
"newId": "bd7116d8c441eddfaeb5bdef"
},
{
"oldNumber": "13",
"newId": "bd7117d8c441eddfaeb5bdef"
},
{
"oldNumber": "14",
"newId": "bd7118d8c441eddfaeb5bdef"
},
{
"oldNumber": "15",
"newId": ""
},
{
"oldNumber": "16",
"newId": ""
},
{
"oldNumber": "17",
"newId": ""
},
{
"oldNumber": "18",
"newId": ""
},
{
"oldNumber": "19",
"newId": "bd7123d8c441eddfaeb5bdef"
},
{
"oldNumber": "20",
"newId": "bd8124d8c441eddfaeb5bdef"
},
{
"oldNumber": "21",
"newId": "bd8126d8c441eddfaeb5bdef"
},
{
"oldNumber": "22",
"newId": "bd8127d8c441eddfaeb5bdef"
},
{
"oldNumber": "23",
"newId": "bd8128d8c441eddfaeb5bdef"
},
{
"oldNumber": "24",
"newId": "bd7129d8c441eddfaeb5bdef"
},
{
"oldNumber": "25",
"newId": "bd7130d8c441eddfaeb5bdef"
},
{
"oldNumber": "26",
"newId": "bd7131d8c441eddfaeb5bdef"
},
{
"oldNumber": "27",
"newId": "bd7132d8c441eddfaeb5bdef"
},
{
"oldNumber": "28",
"newId": "bd7133d8c441eddfaeb5bdef"
},
{
"oldNumber": "29",
"newId": "bd7134d8c441eddfaeb5bdef"
},
{
"oldNumber": "30",
"newId": "bd7135d8c441eddfaeb5bdef"
},
{
"oldNumber": "31",
"newId": "bd7136d8c441eddfaeb5bdef"
},
{
"oldNumber": "32",
"newId": ""
},
{
"oldNumber": "33",
"newId": "bd7138d8c441eddfaeb5bdef"
},
{
"oldNumber": "34",
"newId": "bd7137d8c441eddfaeb5bdef"
},
{
"oldNumber": "35",
"newId": "bd7140d8c441eddfaeb5bdef"
},
{
"oldNumber": "36",
"newId": ""
},
{
"oldNumber": "37",
"newId": ""
},
{
"oldNumber": "38",
"newId": ""
},
{
"oldNumber": "39",
"newId": ""
},
{
"oldNumber": "40",
"newId": ""
},
{
"oldNumber": "41",
"newId": ""
},
{
"oldNumber": "42",
"newId": ""
},
{
"oldNumber": "43",
"newId": ""
},
{
"oldNumber": "44",
"newId": ""
},
{
"oldNumber": "45",
"newId": ""
},
{
"oldNumber": "46",
"newId": ""
},
{
"oldNumber": "47",
"newId": ""
},
{
"oldNumber": "48",
"newId": "bd7153d8c441eddfaeb5bd2f"
},
{
"oldNumber": "49",
"newId": "bd7154d8c441eddfaeb5bdef"
},
{
"oldNumber": "50",
"newId": "bd7155d8c441eddfaeb5bdef"
},
{
"oldNumber": "51",
"newId": "bd7156d8c441eddfaeb5bdef"
},
{
"oldNumber": "52",
"newId": "bd7157d8c441eddfaeb5bdef"
},
{
"oldNumber": "53",
"newId": "bd7158d8c441eddfaeb5bdef"
},
{
"oldNumber": "54",
"newId": ""
},
{
"oldNumber": "55",
"newId": ""
}
]

View File

@ -157,7 +157,6 @@
"Global Object" "Global Object"
], ],
"solutions": [ "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", "type": "bonfire",
"challengeType": 5, "challengeType": 5,

View File

@ -14,7 +14,12 @@
], ],
"type": "waypoint", "type": "waypoint",
"challengeType": 2, "challengeType": 2,
"tests": [], "tests": [
"assert(true, 'No test needed');"
],
"solutions": [
"/* no test needed */"
],
"nameCn": "", "nameCn": "",
"descriptionCn": [], "descriptionCn": [],
"nameFr": "", "nameFr": "",
@ -37,7 +42,12 @@
], ],
"type": "waypoint", "type": "waypoint",
"challengeType": 2, "challengeType": 2,
"tests": [], "tests": [
"assert(true, 'No test needed');"
],
"solutions": [
"/* no test needed */"
],
"nameCn": "", "nameCn": "",
"descriptionCn": [], "descriptionCn": [],
"nameFr": "", "nameFr": "",
@ -60,7 +70,12 @@
], ],
"type": "waypoint", "type": "waypoint",
"challengeType": 2, "challengeType": 2,
"tests": [], "tests": [
"assert(true, 'No test needed');"
],
"solutions": [
"/* no test needed */"
],
"nameCn": "", "nameCn": "",
"descriptionCn": [], "descriptionCn": [],
"nameFr": "", "nameFr": "",
@ -82,7 +97,12 @@
], ],
"type": "waypoint", "type": "waypoint",
"challengeType": 2, "challengeType": 2,
"tests": [], "tests": [
"assert(true, 'No test needed');"
],
"solutions": [
"/* no test needed */"
],
"nameCn": "", "nameCn": "",
"descriptionCn": [], "descriptionCn": [],
"nameFr": "", "nameFr": "",
@ -105,7 +125,12 @@
], ],
"type": "waypoint", "type": "waypoint",
"challengeType": 2, "challengeType": 2,
"tests": [], "tests": [
"assert(true, 'No test needed');"
],
"solutions": [
"/* no test needed */"
],
"nameCn": "", "nameCn": "",
"descriptionCn": [], "descriptionCn": [],
"nameFr": "", "nameFr": "",

View File

@ -116,7 +116,7 @@
"Arithmetic Operators" "Arithmetic Operators"
], ],
"solutions": [ "solutions": [
"function factorialize(num) {\n return num === 1 ? 1 : num * factorialize(num-1);\n}\n\nfactorialize(5);\n" "function factorialize(num) {\n return num < 1 ? 1 : num * factorialize(num-1);\n}\n\nfactorialize(5);\n"
], ],
"type": "bonfire", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -169,7 +169,6 @@
"String.toLowerCase()" "String.toLowerCase()"
], ],
"solutions": [ "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", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -417,7 +416,6 @@
"String.slice()" "String.slice()"
], ],
"solutions": [ "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", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -663,9 +661,7 @@
"MDNlinks": [ "MDNlinks": [
"Array.sort()" "Array.sort()"
], ],
"solutions": [ "solutions": [],
"function where(arr, num) {\n // Find my place in this sorted array.\n return num;\n}\n\nwhere([40, 60], 50);\n"
],
"tests": [ "tests": [
"assert(where([10, 20, 30, 40, 50], 35) === 3, 'message: <code>where([10, 20, 30, 40, 50], 35)</code> should return <code>3</code>.');", "assert(where([10, 20, 30, 40, 50], 35) === 3, 'message: <code>where([10, 20, 30, 40, 50], 35)</code> should return <code>3</code>.');",
"assert(where([10, 20, 30, 40, 50], 30) === 2, 'message: <code>where([10, 20, 30, 40, 50], 30)</code> should return <code>2</code>.');", "assert(where([10, 20, 30, 40, 50], 30) === 2, 'message: <code>where([10, 20, 30, 40, 50], 30)</code> should return <code>2</code>.');",

View File

@ -31,7 +31,7 @@
"Array.reduce()" "Array.reduce()"
], ],
"solutions": [ "solutions": [
"function sumAll(arr) {\n var sum = 0;\n arr.sort(function(a,b) {return a-b;});\n for (var i = arr[0]; i <= arr[1]; i++) {\n sum += i; \n }\n return sum;\n}\n\nsumAll([1, 4]);\n" "function sumAll(arr) {\n var sum = 0;\n arr.sort(function(a,b) {return a-b;});\n for (var i = arr[0]; i <= arr[1]; i++) {\n sum += i; \n }\n return sum;\n}"
], ],
"type": "bonfire", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -80,7 +80,7 @@
"Array.concat()" "Array.concat()"
], ],
"solutions": [ "solutions": [
"function diff(arr1, arr2) {\n var newArr = [];\n var h1 = Object.create(null);\n arr1.forEach(function(e) {\n h1[e] = e;\n });\n \n var h2 = Object.create(null);\n arr2.forEach(function(e) {\n h2[e] = e;\n });\n \n Object.keys(h1).forEach(function(e) {\n if (!(e in h2)) newArr.push(h1[e]);\n });\n Object.keys(h2).forEach(function(e) {\n if (!(e in h1)) newArr.push(h2[e]);\n });\n // Same, same; but different.\n return newArr;\n}\n\ndiff([1, 2, 3, 5], [1, 2, 3, 4, 5]);\n" "function diff(arr1, arr2) {\n var newArr = [];\n var h1 = Object.create(null);\n arr1.forEach(function(e) {\n h1[e] = e;\n });\n \n var h2 = Object.create(null);\n arr2.forEach(function(e) {\n h2[e] = e;\n });\n \n Object.keys(h1).forEach(function(e) {\n if (!(e in h2)) newArr.push(h1[e]);\n });\n Object.keys(h2).forEach(function(e) {\n if (!(e in h1)) newArr.push(h2[e]);\n });\n // Same, same; but different.\n return newArr;\n}"
], ],
"type": "bonfire", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -138,7 +138,7 @@
"Array.join()" "Array.join()"
], ],
"solutions": [ "solutions": [
"function convert(num) {\n var ref = [['M', 1000], ['CM', 900], ['D', 500], ['CD', 400], ['C', 100], ['XC', 90], ['L', 50], ['XL', 40], ['X', 10], ['IX', 9], ['V', 5], ['IV', 4], ['I', 1]];\n var res = [];\n ref.forEach(function(p) {\n while (num >= p[1]) {\n res.push(p[0]);\n num -= p[1];\n }\n });\n return res.join('');\n}\n\nconvert(36);\n" "function convert(num) {\n var ref = [['M', 1000], ['CM', 900], ['D', 500], ['CD', 400], ['C', 100], ['XC', 90], ['L', 50], ['XL', 40], ['X', 10], ['IX', 9], ['V', 5], ['IV', 4], ['I', 1]];\n var res = [];\n ref.forEach(function(p) {\n while (num >= p[1]) {\n res.push(p[0]);\n num -= p[1];\n }\n });\n return res.join('');\n}"
], ],
"type": "bonfire", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -181,7 +181,7 @@
"Object.keys()" "Object.keys()"
], ],
"solutions": [ "solutions": [
"function where(collection, source) {\n var arr = [];\n var keys = Object.keys(source);\n collection.forEach(function(e) {\n if(keys.every(function(key) {return e[key] === source[key];})) {\n arr.push(e); \n }\n });\n return arr;\n}\n\nwhere([{ first: 'Romeo', last: 'Montague' }, { first: 'Mercutio', last: null }, { first: 'Tybalt', last: 'Capulet' }], { last: 'Capulet' });\n" "function where(collection, source) {\n var arr = [];\n var keys = Object.keys(source);\n collection.forEach(function(e) {\n if(keys.every(function(key) {return e[key] === source[key];})) {\n arr.push(e); \n }\n });\n return arr;\n}"
], ],
"type": "bonfire", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -227,7 +227,7 @@
"Array.join()" "Array.join()"
], ],
"solutions": [ "solutions": [
"function replace(str, before, after) {\n if (before.charAt(0) === before.charAt(0).toUpperCase()) {\n after = after.charAt(0).toUpperCase() + after.substring(1);\n } else {\n after = after.charAt(0).toLowerCase() + after.substring(1);\n }\n return str.replace(before, after);\n}\n\nreplace(\"A quick brown fox jumped over the lazy dog\", \"jumped\", \"leaped\");\n" "function myReplace(str, before, after) {\n if (before.charAt(0) === before.charAt(0).toUpperCase()) {\n after = after.charAt(0).toUpperCase() + after.substring(1);\n } else {\n after = after.charAt(0).toLowerCase() + after.substring(1);\n }\n return str.replace(before, after);\n}"
], ],
"type": "bonfire", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -273,7 +273,7 @@
"String.split()" "String.split()"
], ],
"solutions": [ "solutions": [
"function translate(str) {\n if (isVowel(str.charAt(0))) return str + \"way\";\n var front = [];\n str = str.split('');\n while (str.length && !isVowel(str[0])) {\n front.push(str.shift());\n }\n return [].concat(str, front).join('') + 'ay';\n}\n\nfunction isVowel(c) {\n return ['a', 'e', 'i', 'o', 'u'].indexOf(c.toLowerCase()) !== -1;\n}\n\ntranslate(\"consonant\");\n" "function translate(str) {\n if (isVowel(str.charAt(0))) return str + \"way\";\n var front = [];\n str = str.split('');\n while (str.length && !isVowel(str[0])) {\n front.push(str.shift());\n }\n return [].concat(str, front).join('') + 'ay';\n}\n\nfunction isVowel(c) {\n return ['a', 'e', 'i', 'o', 'u'].indexOf(c.toLowerCase()) !== -1;\n}"
], ],
"type": "bonfire", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -316,7 +316,7 @@
"String.split()" "String.split()"
], ],
"solutions": [ "solutions": [
"var lookup = Object.create(null);\nlookup.A = 'T';\nlookup.T = 'A';\nlookup.C = 'G';\nlookup.G = 'C';\n\nfunction pair(str) {\n return str.split('').map(function(p) {return [p, lookup[p]];});\n}\n\npair(\"GCG\");\n" "var lookup = Object.create(null);\nlookup.A = 'T';\nlookup.T = 'A';\nlookup.C = 'G';\nlookup.G = 'C';\n\nfunction pair(str) {\n return str.split('').map(function(p) {return [p, lookup[p]];});\n}"
], ],
"type": "bonfire", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -357,7 +357,7 @@
"String.fromCharCode()" "String.fromCharCode()"
], ],
"solutions": [ "solutions": [
"function fearNotLetter(str) {\n var s = str.split('').map(function(c) {return c.charCodeAt(0);});\n for (var i = 1; i < s.length; i++) {\n if (s[i]-1 != s[i-1]) {\n return String.fromCharCode(s[i]-1);\n }\n }\n}\n\nfearNotLetter('abce');\n" "function fearNotLetter(str) {\n var s = str.split('').map(function(c) {return c.charCodeAt(0);});\n for (var i = 1; i < s.length; i++) {\n if (s[i]-1 != s[i-1]) {\n return String.fromCharCode(s[i]-1);\n }\n }\n}"
], ],
"type": "bonfire", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -402,7 +402,7 @@
"Boolean Objects" "Boolean Objects"
], ],
"solutions": [ "solutions": [
"function boo(bool) {\n // What is the new fad diet for ghost developers? The Boolean.\n return typeof(bool) === \"boolean\";\n}\n\nboo(null);\n" "function boo(bool) {\n // What is the new fad diet for ghost developers? The Boolean.\n return typeof(bool) === \"boolean\";\n}\n\nboo(null);"
], ],
"type": "bonfire", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -445,7 +445,7 @@
"Array.reduce()" "Array.reduce()"
], ],
"solutions": [ "solutions": [
"function unite(arr1, arr2, arr3) {\n return [].slice.call(arguments).reduce(function(a, b) {\n return [].concat(a, b.filter(function(e) {return a.indexOf(e) === -1;}));\n }, []);\n}\n\nunite([1, 2, 3], [5, 2, 1, 4], [2, 1]);\n" "function unite(arr1, arr2, arr3) {\n return [].slice.call(arguments).reduce(function(a, b) {\n return [].concat(a, b.filter(function(e) {return a.indexOf(e) === -1;}));\n }, []);\n}"
], ],
"type": "bonfire", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -489,7 +489,7 @@
"HTML Entities" "HTML Entities"
], ],
"solutions": [ "solutions": [
"var MAP = { '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&apos;'};\n\nfunction convert(str) {\n return str.replace(/[&<>\"']/g, function(c) {\n return MAP[c];\n });\n}\n\nconvert('Dolce & Gabbana');\n" "var MAP = { '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&apos;'};\n\nfunction convert(str) {\n return str.replace(/[&<>\"']/g, function(c) {\n return MAP[c];\n });\n}"
], ],
"type": "bonfire", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -531,7 +531,7 @@
"String.replace()" "String.replace()"
], ],
"solutions": [ "solutions": [
"function spinalCase(str) {\n // \"It's such a fine line between stupid, and clever.\"\n // --David St. Hubbins\n str = str.replace(/([a-z](?=[A-Z]))/g, '$1 ');\n return str.toLowerCase().replace(/\\ |\\_/g, '-');\n}\n\nspinalCase('This Is Spinal Tap');\n" "function spinalCase(str) {\n // \"It's such a fine line between stupid, and clever.\"\n // --David St. Hubbins\n str = str.replace(/([a-z](?=[A-Z]))/g, '$1 ');\n return str.toLowerCase().replace(/\\ |\\_/g, '-');\n}"
], ],
"type": "bonfire", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -574,7 +574,7 @@
"Remainder" "Remainder"
], ],
"solutions": [ "solutions": [
"function sumFibs(num) {\n var a = 1; \n var b = 1;\n var s = 0;\n while (a <= num) {\n if (a % 2 !== 0) { \n s += a; \n }\n a = [b, b=b+a][0];\n }\n return s;\n}\n\nsumFibs(4);\n" "function sumFibs(num) {\n var a = 1; \n var b = 1;\n var s = 0;\n while (a <= num) {\n if (a % 2 !== 0) { \n s += a; \n }\n a = [b, b=b+a][0];\n }\n return s;\n}"
], ],
"type": "bonfire", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -615,7 +615,7 @@
"Array.push()" "Array.push()"
], ],
"solutions": [ "solutions": [
"function eratosthenesArray(n) {\n var primes = [];\n if (n > 2) {\n var half = n>>1;\n var sieve = Array(half);\n for (var i = 1, limit = Math.sqrt(n)>>1; i <= limit; i++) {\n if (!sieve[i]) {\n for (var step = 2*i+1, j = (step*step)>>1; j < half; j+=step) {\n sieve[j] = true;\n }\n }\n }\n primes.push(2);\n for (var p = 1; p < half; p++) {\n if (!sieve[p]) primes.push(2*p+1);\n }\n }\n return primes;\n}\n\nfunction sumPrimes(num) {\n return eratosthenesArray(num+1).reduce(function(a,b) {return a+b;}, 0);\n}\n\nsumPrimes(10);\n" "function eratosthenesArray(n) {\n var primes = [];\n if (n > 2) {\n var half = n>>1;\n var sieve = Array(half);\n for (var i = 1, limit = Math.sqrt(n)>>1; i <= limit; i++) {\n if (!sieve[i]) {\n for (var step = 2*i+1, j = (step*step)>>1; j < half; j+=step) {\n sieve[j] = true;\n }\n }\n }\n primes.push(2);\n for (var p = 1; p < half; p++) {\n if (!sieve[p]) primes.push(2*p+1);\n }\n }\n return primes;\n}\n\nfunction sumPrimes(num) {\n return eratosthenesArray(num+1).reduce(function(a,b) {return a+b;}, 0);\n}\n\nsumPrimes(10);"
], ],
"type": "bonfire", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -657,7 +657,7 @@
"Smallest Common Multiple" "Smallest Common Multiple"
], ],
"solutions": [ "solutions": [
"function gcd(a, b) {\n while (b !== 0) {\n a = [b, b = a % b][0];\n }\n return a;\n}\n\nfunction lcm(a, b) {\n return (a * b) / gcd(a, b);\n}\n\nfunction smallestCommons(arr) {\n arr.sort(function(a,b) {return a-b;});\n var rng = [];\n for (var i = arr[0]; i <= arr[1]; i++) {\n rng.push(i);\n }\n return rng.reduce(lcm);\n}\n\n\nsmallestCommons([1,5]);\n" "function gcd(a, b) {\n while (b !== 0) {\n a = [b, b = a % b][0];\n }\n return a;\n}\n\nfunction lcm(a, b) {\n return (a * b) / gcd(a, b);\n}\n\nfunction smallestCommons(arr) {\n arr.sort(function(a,b) {return a-b;});\n var rng = [];\n for (var i = arr[0]; i <= arr[1]; i++) {\n rng.push(i);\n }\n return rng.reduce(lcm);\n}"
], ],
"type": "bonfire", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -695,7 +695,7 @@
"Array.filter()" "Array.filter()"
], ],
"solutions": [ "solutions": [
"function find(arr, func) {\n var num;\n arr.some(function(e) {\n if (func(e)) {\n num = e;\n return true;\n }\n });\n return num;\n}\n\nfind([1, 2, 3, 4], function(num){ return num % 2 === 0; });\n" "function find(arr, func) {\n var num;\n arr.some(function(e) {\n if (func(e)) {\n num = e;\n return true;\n }\n });\n return num;\n}"
], ],
"type": "bonfire", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -736,7 +736,7 @@
"Array.shift()" "Array.shift()"
], ],
"solutions": [ "solutions": [
"(function drop(arr, func) {\n // Drop them elements.\n while (arr.length && !func(arr[0])) {\n arr.shift();\n }\n return arr;\n}\n\ndrop([1, 2, 3], function(n) {return n < 3; });\n)" "function drop(arr, func) {\n // Drop them elements.\n while (arr.length && !func(arr[0])) {\n arr.shift();\n }\n return arr;\n}"
], ],
"type": "bonfire", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -776,7 +776,7 @@
"Array.isArray()" "Array.isArray()"
], ],
"solutions": [ "solutions": [
"function steamroller(arr) {\n if (!Array.isArray(arr)) {\n return [arr];\n }\n var out = [];\n arr.forEach(function(e) {\n steamroller(e).forEach(function(v) {\n out.push(v);\n });\n });\n return out;\n}\n\nsteamroller([1, [2], [3, [[4]]]]);\n" "function steamroller(arr) {\n if (!Array.isArray(arr)) {\n return [arr];\n }\n var out = [];\n arr.forEach(function(e) {\n steamroller(e).forEach(function(v) {\n out.push(v);\n });\n });\n return out;\n}"
], ],
"type": "bonfire", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -815,7 +815,7 @@
"String.fromCharCode()" "String.fromCharCode()"
], ],
"solutions": [ "solutions": [
"function binaryAgent(str) {\n return str.split(' ').map(function(s) { return parseInt(s, 2); }).map(function(b) { return String.fromCharCode(b);}).join('');\n}\n\nbinaryAgent('01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111');\n" "function binaryAgent(str) {\n return str.split(' ').map(function(s) { return parseInt(s, 2); }).map(function(b) { return String.fromCharCode(b);}).join('');\n}"
], ],
"type": "bonfire", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -858,7 +858,7 @@
"assert.strictEqual(every([{\"single\": \"double\"}, {\"single\": NaN}], \"single\"), false, 'message: <code>every([{\"single\": \"double\"}, {\"single\": NaN}], \"single\")</code> should return false');" "assert.strictEqual(every([{\"single\": \"double\"}, {\"single\": NaN}], \"single\"), false, 'message: <code>every([{\"single\": \"double\"}, {\"single\": NaN}], \"single\")</code> should return false');"
], ],
"solutions": [ "solutions": [
"function every(collection, pre) {\n // Does everyone have one of these?\n return collection.every(function(e) { return e[pre]; });\n}\n\nevery([{'user': 'Tinky-Winky', 'sex': 'male'}, {'user': 'Dipsy', 'sex': 'male'}, {'user': 'Laa-Laa', 'sex': 'female'}, {'user': 'Po', 'sex': 'female'}], 'sex');\n" "function every(collection, pre) {\n // Does everyone have one of these?\n return collection.every(function(e) { return e[pre]; });\n}"
], ],
"type": "bonfire", "type": "bonfire",
"challengeType": 5, "challengeType": 5,
@ -904,8 +904,7 @@
"Arguments object" "Arguments object"
], ],
"solutions": [ "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}"
"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", "type": "bonfire",
"challengeType": 5, "challengeType": 5,

19
seed/getChallenges.js Normal file
View File

@ -0,0 +1,19 @@
var fs = require('fs');
var path = require('path');
function getFilesFor(dir) {
return fs.readdirSync(path.join(__dirname, '/' + dir));
}
module.exports = function getChallenges() {
try {
return getFilesFor('challenges')
.map(function(file) {
return require('./challenges/' + file);
});
} catch (e) {
console.log('error', e);
return [];
}
};

View File

@ -2,29 +2,23 @@
require('babel/register'); require('babel/register');
require('dotenv').load(); require('dotenv').load();
var fs = require('fs'), var Rx = require('rx'),
Rx = require('rx'),
_ = require('lodash'), _ = require('lodash'),
path = require('path'), getChallenges = require('./getChallenges'),
app = require('../server/server'); app = require('../server/server');
function getFilesFor(dir) {
return fs.readdirSync(path.join(__dirname, '/' + dir));
}
var Challenge = app.models.Challenge; var Challenge = app.models.Challenge;
var challenges = getFilesFor('challenges');
var destroy = Rx.Observable.fromNodeCallback(Challenge.destroyAll, Challenge); var destroy = Rx.Observable.fromNodeCallback(Challenge.destroyAll, Challenge);
var create = Rx.Observable.fromNodeCallback(Challenge.create, Challenge); var create = Rx.Observable.fromNodeCallback(Challenge.create, Challenge);
destroy() destroy()
.flatMap(function() { return Rx.Observable.from(challenges); }) .flatMap(function() { return Rx.Observable.from(getChallenges()); })
.flatMap(function(file) { .flatMap(function(challengeSpec) {
var challengeSpec = require('./challenges/' + file);
var order = challengeSpec.order; var order = challengeSpec.order;
var block = challengeSpec.name; var block = challengeSpec.name;
var isBeta = !!challengeSpec.isBeta; var isBeta = !!challengeSpec.isBeta;
console.log('parsed %s successfully', file); console.log('parsed %s successfully', block);
// challenge file has no challenges... // challenge file has no challenges...
if (challengeSpec.challenges.length === 0) { if (challengeSpec.challenges.length === 0) {

View File

@ -1,47 +0,0 @@
[
{
"id": "bd7167d8c441cbafaeb5bdef",
"email": "Ada_Gerlach@gmail.com",
"phone": "1-140-557-0727",
"company": "Livestream",
"country": "Singapore",
"city": "Morar berg",
"state": "South Dakota",
"position": "Junior Backend Developer (Node.js)",
"logo": "https://s3.amazonaws.com/prod-heroku/greenhouse_job_boards/logos/000/001/189/resized/livestream_logo-rgb_standard-cc718e67ce1a0f6fa400f609bdefe605.png?1429547161",
"description": "Live life one inhalation and one exhalation at a time. May you be healthy. Let the muscles in your neck and shoulders relax. May you be safe. Reflect on the fragility and preciousness of life. Empty your mind; be formless, shapeless like water. May you be at peace. Take a deep breath. You can do what you set out to do; yes, you can. You can do what you set out to do; yes, you can. Watch each breath appear and disappear, just breathing. Give yourself a break. Live life one inhalation and one exhalation at a time. Give yourself a break. Just acknowledge what's there and let be. You can get through this. Open your heart to change, forgiveness and lovingkindness. Love is the first seed of the soul. It will be ok. Impermanence and change is a powerful teacher and teaching. Bring love into your heart, into your breath and into your being. Briefly notice any emotions, thoughts or sensations that may be driving fear and anxiety and let them be. This discomfort will pass. Bring love into your heart, into your breath and into your being. Take a deep breath. Reflect on the fragility and preciousness of life."
},
{
"id": "bd7167d8c442cbafaeb5bdef",
"email": "Ada_Gerlach@gmail.com",
"company": "Adobe",
"country": "Singapore",
"city": "Morar berg",
"state": "South Dakota",
"position": "Junior JavaScript Engineer",
"logo": "http://cdn-3.famouslogos.us/images/adobe-logo.jpg",
"description": "Live life one inhalation and one exhalation at a time. May you be healthy. Let the muscles in your neck and shoulders relax. May you be safe. Reflect on the fragility and preciousness of life. Empty your mind; be formless, shapeless like water. May you be at peace. Take a deep breath. You can do what you set out to do; yes, you can. You can do what you set out to do; yes, you can. Watch each breath appear and disappear, just breathing. Give yourself a break. Live life one inhalation and one exhalation at a time. Give yourself a break. Just acknowledge what's there and let be. You can get through this. Open your heart to change, forgiveness and lovingkindness. Love is the first seed of the soul. It will be ok. Impermanence and change is a powerful teacher and teaching. Bring love into your heart, into your breath and into your being. Briefly notice any emotions, thoughts or sensations that may be driving fear and anxiety and let them be. This discomfort will pass. Bring love into your heart, into your breath and into your being. Take a deep breath. Reflect on the fragility and preciousness of life."
},
{
"id": "bd7167d8c443cbafaeb5bdef",
"phone": "1-140-557-0727",
"company": "Bookspan",
"country": "Singapore",
"city": "Morar berg",
"state": "South Dakota",
"position": "Full Stack JavaScript Developer (Junior)",
"logo": "https://tm-prod.global.ssl.fastly.net/uploaded/companies/227/small_logo.png?v=db9dbe",
"description": "Live life one inhalation and one exhalation at a time. May you be healthy. Let the muscles in your neck and shoulders relax. May you be safe. Reflect on the fragility and preciousness of life. Empty your mind; be formless, shapeless like water. May you be at peace. Take a deep breath. You can do what you set out to do; yes, you can. You can do what you set out to do; yes, you can. Watch each breath appear and disappear, just breathing. Give yourself a break. Live life one inhalation and one exhalation at a time. Give yourself a break. Just acknowledge what's there and let be. You can get through this. Open your heart to change, forgiveness and lovingkindness. Love is the first seed of the soul. It will be ok. Impermanence and change is a powerful teacher and teaching. Bring love into your heart, into your breath and into your being. Briefly notice any emotions, thoughts or sensations that may be driving fear and anxiety and let them be. This discomfort will pass. Bring love into your heart, into your breath and into your being. Take a deep breath. Reflect on the fragility and preciousness of life."
},
{
"id": "bd7167d8c444cbafaeb5bdef",
"email": "Ada_Gerlach@gmail.com",
"company": "Good Eggs",
"country": "Singapore",
"city": "Morar berg",
"state": "South Dakota",
"position": "Full Stack Developer",
"logo": "https://d1qb2nb5cznatu.cloudfront.net/startups/i/72165-64efbd521cdfe3357c811758f5436e7d-medium_jpg.jpg",
"description": "Live life one inhalation and one exhalation at a time. May you be healthy. Let the muscles in your neck and shoulders relax. May you be safe. Reflect on the fragility and preciousness of life. Empty your mind; be formless, shapeless like water. May you be at peace. Take a deep breath. You can do what you set out to do; yes, you can. You can do what you set out to do; yes, you can. Watch each breath appear and disappear, just breathing. Give yourself a break. Live life one inhalation and one exhalation at a time. Give yourself a break. Just acknowledge what's there and let be. You can get through this. Open your heart to change, forgiveness and lovingkindness. Love is the first seed of the soul. It will be ok. Impermanence and change is a powerful teacher and teaching. Bring love into your heart, into your breath and into your being. Briefly notice any emotions, thoughts or sensations that may be driving fear and anxiety and let them be. This discomfort will pass. Bring love into your heart, into your breath and into your being. Take a deep breath. Reflect on the fragility and preciousness of life."
}
]

View File

@ -1,47 +0,0 @@
/**
* Created by nathanleniz on 4/25/15.
*/
require('dotenv').load();
var mongodb = require('mongodb'),
Story = require('../models/Story.js'),
secrets = require('../config/secrets');
mongoose = require('mongoose');
mongoose.connect(secrets.db);
function storyLinkCleanup(cb) {
console.log('headLineCleanup');
var i = 1;
var stream = Story.find({}).skip(0).limit(0).batchSize(20000).stream();
stream.on('data', function (story) {
console.log(i++);
this.pause();
story.storyLink = story.storyLink.
replace(/[^a-z0-9\s]/gi, '').
replace(/\s+/g, ' ').
toLowerCase().
trim();
story.save(function (err) {
if (err) {
console.log('woops');
}
this.resume();
}.bind(this));
})
.on('error', function (err) {
console.error(err);
}).on('close', function () {
console.log('done with set');
stream.destroy();
cb();
});
}
function done() {
console.log('Migration script has completed');
process.exit(0);
}
storyLinkCleanup(done);

112
seed/test-challenges.js Normal file
View File

@ -0,0 +1,112 @@
/* eslint-disable no-eval, no-process-exit */
import _ from 'lodash';
import { Observable } from 'rx';
import tape from 'tape';
import getChallenges from './getChallenges';
function createIsAssert(t, isThing) {
const { assert } = t;
return function() {
const args = [...arguments];
args[0] = isThing(args[0]);
assert.apply(t, args);
};
}
function fillAssert(t) {
const assert = t.assert;
assert.isArray = createIsAssert(t, _.isArray);
assert.isBoolean = createIsAssert(t, _.isBoolean);
assert.isString = createIsAssert(t, _.isString);
assert.isNumber = createIsAssert(t, _.isNumber);
assert.isUndefined = createIsAssert(t, _.isUndefined);
assert.deepEqual = t.deepEqual;
assert.equal = t.equal;
assert.strictEqual = t.equal;
assert.sameMembers = function sameMembers() {
const [ first, second, ...args] = arguments;
assert.apply(
t,
[
_.difference(first, second).length === 0 &&
_.difference(second, first).length === 0
].concat(args)
);
};
assert.includeMembers = function includeMembers() {
const [ first, second, ...args] = arguments;
assert.apply(t, [_.difference(second, first).length === 0].concat(args));
};
assert.match = function match() {
const [value, regex, ...args] = arguments;
assert.apply(t, [regex.test(value)].concat(args));
};
return assert;
}
function createTest({ title, tests = [], solutions = [] }) {
const plan = tests.length;
return Observable.fromCallback(tape)(title)
.doOnNext(t => solutions.length ? t.plan(plan) : t.end())
.flatMap(t => {
if (solutions.length <= 0) {
t.comment('No solutions for ' + title);
return Observable.just({
title,
type: 'missing'
});
}
return Observable.just(t)
.map(fillAssert)
/* eslint-disable no-unused-vars */
// assert is used within the eval
.doOnNext(assert => {
/* eslint-enable no-unused-vars */
solutions.forEach(solution => {
tests.forEach(test => {
try {
eval(solution + ';;' + test);
} catch (e) {
t.fail(e);
}
});
});
})
.map(() => ({ title }));
});
}
Observable.from(getChallenges())
.flatMap(challengeSpec => {
return Observable.from(challengeSpec.challenges);
})
.flatMap(challenge => {
return createTest(challenge);
})
.map(({ title, type }) => {
if (type === 'missing') {
return title;
}
return false;
})
.filter(title => !!title)
.toArray()
.subscribe(
(noSolutions) => {
console.log(
'# These challenges have no solutions\n- [ ] ' +
noSolutions.join('\n- [ ] ')
);
},
err => { throw err; },
() => process.exit(0)
);

View File

@ -1,137 +0,0 @@
/*eslint-disable block-scoped-var */
require('dotenv').load();
var User = require('../models/User.js'),
secrets = require('../config/secrets'),
mongoose = require('mongoose'),
R = require('ramda'),
ziplines = require('./challenges/ziplines.json'),
basejumps = require('./challenges/basejumps.json');
mongoose.connect(secrets.db);
var ziplineIds = ziplines.challenges.map(function(elem) {
return elem.id;
});
var basejumpIds = basejumps.challenges.map(function(elem) {
return elem.id;
});
var ziplineAndBaseJumpIds = R.concat(ziplineIds, basejumpIds);
function userModelAssurity(cb) {
console.log('userModelAssurity');
var i = 1;
var stream = User.find({}).skip(0).limit(0).batchSize(20000).stream();
stream.on('data', function (user) {
console.log(i++);
this.pause();
user.needsMigration = true;
user.save(function (err) {
if (err) {
console.log('woops');
}
this.resume();
}.bind(this));
})
.on('error', function (err) {
console.log(err);
}).on('close', function () {
console.log('done with set');
stream.destroy();
cb();
});
}
function migrateIt() {
console.log('migrateIt');
var dones = 0;
var done = function() {
dones++;
if (dones === 2) {
process.exit(0);
}
if (dones === 1) {
userModelMigration(done);
}
};
console.log('calling userModelAssurity');
userModelAssurity(done);
}
function userModelMigration(cb) {
var i = 1;
var stream = User.find({needsMigration: true}).skip(0).limit(0)
.batchSize(20000).stream();
stream.on('data', function (user) {
console.log(i++);
/*
if (user.challengesHash) {
this.pause();
user.needsMigration = false;
var oldChallenges = Object.keys(user.challengesHash).filter(function (key) {
if (user.challengesHash[key]) {
user.progressTimestamps.push(user.challengesHash[key] * 1000);
}
return user.challengesHash[key];
});
newChallenges.forEach(function (challenge) {
if (oldChallenges.indexOf(challenge.oldNumber) !== -1 && challenge.newId) {
user.completedCoursewares.push({
id: challenge.newId,
completedDate: user.challengesHash[challenge.oldNumber] * 1000
});
}
});
user.completedCoursewares.forEach(function (course) {
var indexOfCourse = user.uncompletedCoursewares.indexOf(course.id) !== -1;
if (indexOfCourse !== -1) {
user.uncompletedCoursewares.splice(indexOfCourse, 1);
}
});
user.completedBonfires.forEach(function (bonfire) {
bonfire.completedDate = bonfire.completedDate * 1000;
user.progressTimestamps.push(bonfire.completedDate);
});
}
*/
user.needsMigration = false;
user.completedChallenges = user.completedChallenges.map(function(elem) {
if (ziplineAndBaseJumpIds.indexOf(elem.id) > 0) {
return ({
id: elem.id,
name: elem.name,
completedWith: elem.completedWith,
completedDate: elem.completedDate,
solution: elem.solution,
githubLink: elem.githubLink,
verified: elem.verified,
challengeType: typeof elem.githubLink === 'boolean' ? 4 : 3
});
} else {
return elem;
}
});
var self = this;
user.save(function (err) {
if (err) {
console.log('woops');
}
self.resume();
});
}).on('error', function (err) {
console.log(err);
}).on('close', function () {
console.log('done with set');
stream.destroy();
cb();
});
}
migrateIt();

View File

@ -1,45 +0,0 @@
var request = require('supertest');
var app = require('../server/server.js');
describe('#ROUTES', function () {
describe('GET /', function () {
it('should return 200 OK', (done) => {
request(app)
.get('/')
.expect(200, done);
});
});
describe('GET /signin', function () {
it('should return 200 OK', (done) => {
request(app)
.get('/signin')
.expect(200, done);
});
});
describe('GET /email-signup', function () {
it('should return 200 OK', (done) => {
request(app)
.get('/email-signup')
.expect(200, done);
});
});
describe('GET /random-url', function () {
it('should return 302', (done) => {
request(app)
.get('/reset')
.expect(302, done);
});
});
describe('GET /camperName', function () {
it('should return 200', (done) => {
request(app)
.get('/terakilobyte')
.expect(200, done);
});
});
});

View File

@ -1,2 +0,0 @@
--reporter spec
--timeout 5000