diff --git a/client/commonFramework/add-faux-stream.js b/client/commonFramework/add-faux-stream.js deleted file mode 100644 index 17a57e212c..0000000000 --- a/client/commonFramework/add-faux-stream.js +++ /dev/null @@ -1,24 +0,0 @@ -window.common = (function(global) { - const { - common = { init: [] } - } = global; - - - const faux$ = common.getScriptContent$('/js/faux.js').shareReplay(); - - common.hasJs = function hasJs(code = '') { - return code.match(/\<\s?script\s?\>/gi) && - code.match(/\<\s?\/\s?script\s?\>/gi); - }; - - common.addFaux$ = function addFaux$(code) { - // grab user javaScript - var scriptCode = code - .split(/\<\s?script\s?\>/gi)[1] - .split(/\<\s?\/\s?script\s?\>/gi)[0]; - - return faux$.map(faux => faux + scriptCode); - }; - - return common; -}(window)); diff --git a/client/commonFramework/add-loop-protect.js b/client/commonFramework/add-loop-protect.js new file mode 100644 index 0000000000..65aebd0ed4 --- /dev/null +++ b/client/commonFramework/add-loop-protect.js @@ -0,0 +1,17 @@ +window.common = (function(global) { + const { + loopProtect, + common = { init: [] } + } = global; + + loopProtect.hit = function hit(line) { + var err = `Error: Exiting potential infinite loop at line ${line}.`; + console.error(err); + }; + + common.addLoopProtect = function addLoopProtect(code = '') { + return loopProtect(code); + }; + + return common; +})(window); diff --git a/client/commonFramework/add-test-to-string.js b/client/commonFramework/add-test-to-string.js deleted file mode 100644 index 52e78a82b1..0000000000 --- a/client/commonFramework/add-test-to-string.js +++ /dev/null @@ -1,38 +0,0 @@ -window.common = (function({ common = { init: [] }}) { - - var BDDregex = new RegExp( - '(expect(\\s+)?\\(.*\\;)|' + - '(assert(\\s+)?\\(.*\\;)|' + - '(assert\\.\\w.*\\;)|' + - '(.*\\.should\\..*\\;)/' - ); - - common.addTestsToString = function({ code, tests = [], ...rest }) { - const userTests = []; - - code = tests.reduce((code, test) => code + test + '\n', code + '\n'); - - var counter = 0; - var match = BDDregex.exec(code); - - while (match) { - var replacement = '//' + counter + common.salt; - code = code.substring(0, match.index) + - replacement + - code.substring(match.index + match[0].length); - - userTests.push({ - err: null, - text: match[0], - line: counter - }); - - counter++; - match = BDDregex.exec(code); - } - - return { ...rest, code, userTests }; - }; - - return common; -}(window)); diff --git a/client/commonFramework/detect-loops-stream.js b/client/commonFramework/detect-loops-stream.js deleted file mode 100644 index e60c49eea9..0000000000 --- a/client/commonFramework/detect-loops-stream.js +++ /dev/null @@ -1,79 +0,0 @@ -window.common = (function(global) { - const { - jailed, - document: doc, - Rx: { Observable, Disposable }, - common = { init: [] } - } = global; - - if (!jailed) { - return (code, cb) => cb(new Error('Could not load jailed plugin')); - } - - // obtaining absolute path of this script - var scripts = doc.getElementsByTagName('script'); - var path = scripts[scripts.length - 1].src - .split('?')[0] - .split('/') - .slice(0, -1) - .join('/') + '/'; - - var Sandbox = { - startTimeout() { - this.timeoutId = setTimeout(() => { - this.error = new Error('Plugin failed to initialize'); - this.destroyPlugin(); - }, 3000); - }, - cancelTimout() { - if (this.timeoutId) { - clearTimeout(this.timeoutId); - this.timeoutId = null; - } - }, - createPlugin() { - this.plugin = new jailed.Plugin(path + 'plugin.js'); - this.startTimeout(); - this.plugin.whenConnected(() => { - this.cancelTimout(); - }); - }, - destroyPlugin() { - this.plugin.disconnect(); - } - }; - - - // sends the input to the plugin for evaluation - common.detectLoops$ = function detectLoops$({ code = '', ...rest }) { - return Observable.create(function(observer) { - const sandbox = Object.create(Sandbox); - - sandbox.createPlugin(); - sandbox.plugin.whenConnected(() => { - sandbox.plugin.remote.run(code, (err, data) => { - observer.onNext({ ...rest, err, code, data }); - observer.onCompleted(); - }); - }); - - sandbox.plugin.whenDisconnected(() => { - if (sandbox.disposed) { - return null; - } - - if (sandbox.error) { - observer.onNext({ ...rest, err: sandbox.error, code, data: {} }); - } - observer.onCompleted(); - }); - - return new Disposable(() => { - sandbox.disposed = true; - sandbox.destroyPlugin(); - }); - }); - }; - - return common; -}(window)); diff --git a/client/commonFramework/end.js b/client/commonFramework/end.js index 0c9e914521..811e154192 100644 --- a/client/commonFramework/end.js +++ b/client/commonFramework/end.js @@ -28,18 +28,7 @@ $(document).ready(function() { // only run for HTML .filter(() => common.challengeType === challengeTypes.HTML) .flatMap(code => { - if ( - common.hasJs(code) - ) { - return common.detectUnsafeCode$(code) - .flatMap(code => common.detectLoops$(code)) - .flatMap( - ({ err }) => err ? Observable.throw(err) : Observable.just(code) - ) - .flatMap(code => common.updatePreview$(code)) - .catch(err => Observable.just({ err })); - } - return Observable.just(code) + return common.detectUnsafeCode$(code) .flatMap(code => common.updatePreview$(code)) .catch(err => Observable.just({ err })); }) @@ -66,12 +55,12 @@ $(document).ready(function() { .catch(err => Observable.just({ err })); }) .subscribe( - ({ err, output, original }) => { + ({ err, output, originalCode }) => { if (err) { console.error(err); return common.updateOutputDisplay('' + err); } - common.codeStorage.updateStorage(challengeName, original); + common.codeStorage.updateStorage(challengeName, originalCode); common.updateOutputDisplay('' + output); }, (err) => { @@ -102,11 +91,11 @@ $(document).ready(function() { if (common.challengeType === common.challengeTypes.HTML) { return common.updatePreview$(`
Math.floor(Math.random() * (3 - 1 + 1)) + 1;
"
],
"tests": [
- "assert(typeof runSlots($(\".slot\"))[0] === \"number\" && runSlots($(\".slot\"))[0] > 0 && runSlots($(\".slot\"))[0] < 4, 'message: slotOne
should be a random number.')",
- "assert(typeof runSlots($(\".slot\"))[1] === \"number\" && runSlots($(\".slot\"))[1] > 0 && runSlots($(\".slot\"))[1] < 4, 'message: slotTwo
should be a random number.')",
- "assert(typeof runSlots($(\".slot\"))[2] === \"number\" && runSlots($(\".slot\"))[2] > 0 && runSlots($(\".slot\"))[2] < 4, 'message: slotThree
should be a random number.')",
- "assert((function(){if(editor.match(/Math\\.floor\\(\\s?Math\\.random\\(\\)\\s?\\*\\s?\\(\\s?3\\s?\\-\\s?1\\s?\\+\\s?1\\s?\\)\\s?\\)\\s?\\+\\s?1/gi) !== null){return editor.match(/slot.*?=.*?\\(.*?\\).*?/gi).length >= 3;}else{return false;}})(), 'message: You should have used Math.floor(Math.random() * (3 - 1 + 1)) + 1;
three times to generate your random numbers.')"
+ "assert(typeof runSlots($(\".slot\"))[0] === \"number\" && runSlots($(\".slot\"))[0] > 0 && runSlots($(\".slot\"))[0] < 4, 'message: slotOne
should be a random number.');",
+ "assert(typeof runSlots($(\".slot\"))[1] === \"number\" && runSlots($(\".slot\"))[1] > 0 && runSlots($(\".slot\"))[1] < 4, 'message: slotTwo
should be a random number.');",
+ "assert(typeof runSlots($(\".slot\"))[2] === \"number\" && runSlots($(\".slot\"))[2] > 0 && runSlots($(\".slot\"))[2] < 4, 'message: slotThree
should be a random number.');",
+ "assert((function(){if(code.match(/Math\\.floor\\(\\s?Math\\.random\\(\\)\\s?\\*\\s?\\(\\s?3\\s?\\-\\s?1\\s?\\+\\s?1\\s?\\)\\s?\\)\\s?\\+\\s?1/gi) !== null){return code.match(/slot.*?=.*?\\(.*?\\).*?/gi).length >= 3;}else{return false;}})(), 'message: You should have used Math.floor(Math.random() * (3 - 1 + 1)) + 1;
three times to generate your random numbers.');"
],
"challengeSeed": [
"fccss",
@@ -1825,7 +1825,7 @@
"If all three numbers match, we should also set the text \"It's A Win\"
to the element with class logger
."
],
"tests": [
- "assert((function(){var data = runSlots();return data === null || data.toString().length === 1;})(), 'message: If all three of our random numbers are the same we should return that number. Otherwise we should return null
.')"
+ "assert((function(){var data = runSlots();return data === null || data.toString().length === 1;})(), 'message: If all three of our random numbers are the same we should return that number. Otherwise we should return null
.');"
],
"challengeSeed": [
"fccss",
@@ -1994,8 +1994,8 @@
"Use the above selector to display each number in its corresponding slot."
],
"tests": [
- "assert((function(){runSlots();if($($(\".slot\")[0]).html().replace(/\\s/gi, \"\") !== \"\" && $($(\".slot\")[1]).html().replace(/\\s/gi, \"\") !== \"\" && $($(\".slot\")[2]).html().replace(/\\s/gi, \"\") !== \"\"){return true;}else{return false;}})(), 'message: You should be displaying the result of the slot numbers in the corresponding slots.')",
- "assert((editor.match( /\\$\\s*?\\(\\s*?\\$\\s*?\\(\\s*?(?:'|\")\\s*?\\.slot\\s*?(?:'|\")\\s*?\\)\\[\\d\\]\\s*?\\)/gi) && editor.match( /\\$\\s*?\\(\\s*?\\$\\s*?\\(\\s*?(?:'|\")\\s*?\\.slot\\s*?(?:'|\")\\s*?\\)\\[\\d\\]\\s*?\\)/gi ).length >= 3 && editor.match( /\\.html\\(slotOne\\)/gi ) && editor.match( /\\.html\\(slotTwo\\)/gi ) && editor.match( /\\.html\\(slotThree\\)/gi )), 'message: You should have used the the selector given in the description to select each slot and assign it the value of slotOne
, slotTwo
and slotThree
respectively.')"
+ "assert((function(){runSlots();if($($(\".slot\")[0]).html().replace(/\\s/gi, \"\") !== \"\" && $($(\".slot\")[1]).html().replace(/\\s/gi, \"\") !== \"\" && $($(\".slot\")[2]).html().replace(/\\s/gi, \"\") !== \"\"){return true;}else{return false;}})(), 'message: You should be displaying the result of the slot numbers in the corresponding slots.');",
+ "assert((code.match( /\\$\\s*?\\(\\s*?\\$\\s*?\\(\\s*?(?:'|\")\\s*?\\.slot\\s*?(?:'|\")\\s*?\\)\\[\\d\\]\\s*?\\)/gi) && code.match( /\\$\\s*?\\(\\s*?\\$\\s*?\\(\\s*?(?:'|\")\\s*?\\.slot\\s*?(?:'|\")\\s*?\\)\\[\\d\\]\\s*?\\)/gi ).length >= 3 && code.match( /\\.html\\(slotOne\\)/gi ) && code.match( /\\.html\\(slotTwo\\)/gi ) && code.match( /\\.html\\(slotThree\\)/gi )), 'message: You should have used the the selector given in the description to select each slot and assign it the value of slotOne
, slotTwo
and slotThree
respectively.');"
],
"challengeSeed": [
"fccss",
@@ -2168,13 +2168,13 @@
"Set up all three slots like this, then click the \"Go\" button to play the slot machine."
],
"tests": [
- "assert((editor.match(/\\$\\s*?\\(\\s*?\\$\\s*?\\(\\s*?(?:'|\")\\s*?\\.slot\\s*?(?:'|\")\\s*?\\)\\[\\d\\]\\s*?\\)\\.html\\(\\s*?\\'\\$('.slot')[0]
at least once.')",
- "assert(editor.match(/\\$\\s*?\\(\\s*?\\$\\s*?\\(\\s*?(?:'|\")\\s*?\\.slot\\s*?(?:'|\")\\s*?\\)\\[1\\]\\s*?\\)/gi), 'message: You should have used $('.slot')[1]
at least once.')",
- "assert(editor.match(/\\$\\s*?\\(\\s*?\\$\\s*?\\(\\s*?(?:'|\")\\s*?\\.slot\\s*?(?:'|\")\\s*?\\)\\[2\\]\\s*?\\)/gi), 'message: You should have used $('.slot')[2]
at least once.')",
- "assert(editor.match(/slotOne/gi) && editor.match(/slotOne/gi).length >= 7, 'message: You should have used the slotOne
value at least once.')",
- "assert(editor.match(/slotTwo/gi) && editor.match(/slotTwo/gi).length >= 8, 'message: You should have used the slotTwo
value at least once.')",
- "assert(editor.match(/slotThree/gi) && editor.match(/slotThree/gi).length >= 7, 'message: You should have used the slotThree
value at least once.')"
+ "assert((code.match(/\\$\\s*?\\(\\s*?\\$\\s*?\\(\\s*?(?:'|\")\\s*?\\.slot\\s*?(?:'|\")\\s*?\\)\\[\\d\\]\\s*?\\)\\.html\\(\\s*?\\'\\$('.slot')[0]
at least once.');",
+ "assert(code.match(/\\$\\s*?\\(\\s*?\\$\\s*?\\(\\s*?(?:'|\")\\s*?\\.slot\\s*?(?:'|\")\\s*?\\)\\[1\\]\\s*?\\)/gi), 'message: You should have used $('.slot')[1]
at least once.');",
+ "assert(code.match(/\\$\\s*?\\(\\s*?\\$\\s*?\\(\\s*?(?:'|\")\\s*?\\.slot\\s*?(?:'|\")\\s*?\\)\\[2\\]\\s*?\\)/gi), 'message: You should have used $('.slot')[2]
at least once.');",
+ "assert(code.match(/slotOne/gi) && code.match(/slotOne/gi).length >= 7, 'message: You should have used the slotOne
value at least once.');",
+ "assert(code.match(/slotTwo/gi) && code.match(/slotTwo/gi).length >= 8, 'message: You should have used the slotTwo
value at least once.');",
+ "assert(code.match(/slotThree/gi) && code.match(/slotThree/gi).length >= 7, 'message: You should have used the slotThree
value at least once.');"
],
"challengeSeed": [
"fccss",
diff --git a/seed/challenges/bootstrap.json b/seed/challenges/bootstrap.json
index 80ed2d43d4..76e6d180cf 100644
--- a/seed/challenges/bootstrap.json
+++ b/seed/challenges/bootstrap.json
@@ -16,9 +16,9 @@
"To get started, we should nest all of our HTML in a div
element with the class container-fluid
."
],
"tests": [
- "assert($(\"div\").hasClass(\"container-fluid\"), 'message: Your div
element should have the class container-fluid
.')",
- "assert(editor.match(/<\\/div>/g) && editor.match(/.container-fluid
.')"
+ "assert($(\"div\").hasClass(\"container-fluid\"), 'message: Your div
element should have the class container-fluid
.');",
+ "assert(code.match(/<\\/div>/g) && code.match(/.container-fluid
.');"
],
"challengeSeed": [
"",
@@ -106,11 +106,11 @@
"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 === 2, 'message: You should have a total of two images.')",
- "assert($(\"img:eq(1)\").hasClass(\"img-responsive\"), 'message: Your new image should be below your old one and have the class img-responsive
.')",
- "assert(!$(\"img:eq(1)\").hasClass(\"smaller-image\"), 'message: Your new image should not have the class smaller-image
.')",
- "assert($(\"img:eq(1)\").attr(\"src\") === \"http://bit.ly/fcc-running-cats\", 'message: Your new image should have a src
of http://bit.ly/fcc-running-cats
.')",
- "assert(editor.match(/img-responsive
.');",
+ "assert(!$(\"img:eq(1)\").hasClass(\"smaller-image\"), 'message: Your new image should not have the class smaller-image
.');",
+ "assert($(\"img:eq(1)\").attr(\"src\") === \"http://bit.ly/fcc-running-cats\", 'message: Your new image should have a src
of http://bit.ly/fcc-running-cats
.');",
+ "assert(code.match(/<h2 class=\"red-text text-center\">your text</h2>
"
],
"tests": [
- "assert($(\"h2\").hasClass(\"text-center\"), 'message: Your h2
element should be centered by applying the class text-center
')",
- "assert($(\"h2\").hasClass(\"red-text\"), 'message: Your h2
element should still have the class red-text
')"
+ "assert($(\"h2\").hasClass(\"text-center\"), 'message: Your h2
element should be centered by applying the class text-center
');",
+ "assert($(\"h2\").hasClass(\"red-text\"), 'message: Your h2
element should still have the class red-text
');"
],
"challengeSeed": [
"",
@@ -283,9 +283,9 @@
"Create a new button
element below your large kitten photo. Give it the class btn
and the text of \"Like\"."
],
"tests": [
- "assert(new RegExp(\"like\",\"gi\").test($(\"button\").text()), 'message: Create a new button
element with the text \"Like\".')",
- "assert($(\"button\").hasClass(\"btn\"), 'message: Your new button should have the class btn
.')",
- "assert(editor.match(/<\\/button>/g) && editor.match(/