diff --git a/client/package-lock.json b/client/package-lock.json index b3f4c9144e..c0f90f22c0 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1236,11 +1236,6 @@ "prop-types": "^15.5.10" } }, - "@freecodecamp/loop-protect": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@freecodecamp/loop-protect/-/loop-protect-2.2.0.tgz", - "integrity": "sha512-WwYmQn6Xrk7KE22xANbye/qyg3U0aupWtMaJpN/k22/cdSBpWyjdrGSStEqg3DxFxdJoR/O/yhe8gqbtTYKI3g==" - }, "@freecodecamp/react-bootstrap": { "version": "0.32.3", "resolved": "https://registry.npmjs.org/@freecodecamp/react-bootstrap/-/react-bootstrap-0.32.3.tgz", @@ -15518,6 +15513,11 @@ "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.3.tgz", "integrity": "sha512-9lz5IVdpwsKLMzQi0MQ+oD9EA0mIGcWYP7jXMTZVXP8D42PwuAk+M/HBFYQoxt1G5OR8m7aSIgb1UymfWGBWEw==" }, + "loop-protect": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/loop-protect/-/loop-protect-2.1.6.tgz", + "integrity": "sha512-eGNk917T5jQ9A/ER/zJlEXCGD/NQepYyLnLBgVPSuspHauG2HUiDx5oKDSpyVQOzGb+yUKMA1k41+Old2ZmcRQ==" + }, "loose-envify": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", diff --git a/client/package.json b/client/package.json index f6b01ce3b1..e08641d2e9 100644 --- a/client/package.json +++ b/client/package.json @@ -14,7 +14,6 @@ "@fortawesome/free-regular-svg-icons": "^5.11.2", "@fortawesome/free-solid-svg-icons": "^5.11.2", "@fortawesome/react-fontawesome": "^0.1.4", - "@freecodecamp/loop-protect": "^2.2.0", "@freecodecamp/react-bootstrap": "^0.32.3", "@reach/router": "^1.2.1", "algoliasearch": "^3.35.1", @@ -41,6 +40,7 @@ "gatsby-transformer-remark": "^2.6.30", "jquery": "^3.4.1", "lodash": "^4.17.15", + "loop-protect": "^2.1.6", "monaco-editor": "^0.18.1", "monaco-editor-webpack-plugin": "^1.7.0", "nanoid": "^1.2.2", diff --git a/client/src/templates/Challenges/rechallenge/transformers.js b/client/src/templates/Challenges/rechallenge/transformers.js index a47a1e4f0d..bb80a89ae0 100644 --- a/client/src/templates/Challenges/rechallenge/transformers.js +++ b/client/src/templates/Challenges/rechallenge/transformers.js @@ -13,7 +13,7 @@ import { import * as Babel from '@babel/standalone'; import presetEnv from '@babel/preset-env'; import presetReact from '@babel/preset-react'; -import protect from '@freecodecamp/loop-protect'; +import protect from 'loop-protect'; import * as vinyl from '../utils/polyvinyl.js'; import createWorker from '../utils/worker-executor'; @@ -23,26 +23,7 @@ import createWorker from '../utils/worker-executor'; import { filename as sassCompile } from '../../../../config/sass-compile'; const protectTimeout = 100; -const testProtectTimeout = 1500; -const loopsPerTimeoutCheck = 2000; - -function loopProtectCB(line) { - console.log( - `Potential infinite loop detected on line ${line}. Tests may fail if this is not changed.` - ); -} - -function testLoopProtectCB(line) { - console.log( - `Potential infinite loop detected on line ${line}. Tests may be failing because of this.` - ); -} - -Babel.registerPlugin('loopProtection', protect(protectTimeout, loopProtectCB)); -Babel.registerPlugin( - 'testLoopProtection', - protect(testProtectTimeout, testLoopProtectCB, loopsPerTimeoutCheck) -); +Babel.registerPlugin('loopProtection', protect(protectTimeout)); const babelOptionsJSX = { plugins: ['loopProtection'], @@ -50,15 +31,9 @@ const babelOptionsJSX = { }; const babelOptionsJS = { - plugins: ['testLoopProtection'], presets: [presetEnv] }; -const babelOptionsJSPreview = { - ...babelOptionsJS, - plugins: ['loopProtection'] -}; - const babelTransformCode = options => code => Babel.transform(code, options).code; @@ -94,31 +69,28 @@ function tryTransform(wrap = identity) { }; } -const babelTransformer = (preview = false) => - cond([ - [ - testJS, - flow( - partial( - vinyl.transformHeadTailAndContents, - tryTransform( - babelTransformCode(preview ? babelOptionsJSPreview : babelOptionsJS) - ) - ) +export const babelTransformer = cond([ + [ + testJS, + flow( + partial( + vinyl.transformHeadTailAndContents, + tryTransform(babelTransformCode(babelOptionsJS)) ) - ], - [ - testJSX, - flow( - partial( - vinyl.transformHeadTailAndContents, - tryTransform(babelTransformCode(babelOptionsJSX)) - ), - partial(vinyl.setExt, 'js') - ) - ], - [stubTrue, identity] - ]); + ) + ], + [ + testJSX, + flow( + partial( + vinyl.transformHeadTailAndContents, + tryTransform(babelTransformCode(babelOptionsJSX)) + ), + partial(vinyl.setExt, 'js') + ) + ], + [stubTrue, identity] +]); const sassWorker = createWorker(sassCompile); async function transformSASS(element) { @@ -169,14 +141,7 @@ export const htmlTransformer = cond([ export const transformers = [ replaceNBSP, - babelTransformer(), - composeHTML, - htmlTransformer -]; - -export const transformersPreview = [ - replaceNBSP, - babelTransformer(true), + babelTransformer, composeHTML, htmlTransformer ]; diff --git a/client/src/templates/Challenges/redux/execute-challenge-saga.js b/client/src/templates/Challenges/redux/execute-challenge-saga.js index 54970ee726..477cf0dbf5 100644 --- a/client/src/templates/Challenges/redux/execute-challenge-saga.js +++ b/client/src/templates/Challenges/redux/execute-challenge-saga.js @@ -33,9 +33,6 @@ import { isJavaScriptChallenge } from '../utils/build'; -// How long before bailing out of a preview. -const previewTimeout = 2500; - export function* executeChallengeSaga() { const isBuildEnabled = yield select(isBuildEnabledSelector); if (!isBuildEnabled) { @@ -93,9 +90,9 @@ function* takeEveryConsole(channel) { }); } -function* buildChallengeData(challengeData, preview) { +function* buildChallengeData(challengeData) { try { - return yield call(buildChallenge, challengeData, preview); + return yield call(buildChallenge, challengeData); } catch (e) { yield put(disableBuildOnError()); throw e; @@ -158,7 +155,7 @@ function* previewChallengeSaga() { const challengeData = yield select(challengeDataSelector); if (canBuildChallenge(challengeData)) { - const buildData = yield buildChallengeData(challengeData, true); + const buildData = yield buildChallengeData(challengeData); // evaluate the user code in the preview frame or in the worker if (challengeHasPreview(challengeData)) { const document = yield getContext('document'); @@ -166,14 +163,10 @@ function* previewChallengeSaga() { } else if (isJavaScriptChallenge(challengeData)) { const runUserCode = getTestRunner(buildData, { proxyLogger }); // without a testString the testRunner just evaluates the user's code - yield call(runUserCode, null, previewTimeout); + yield call(runUserCode, null, 5000); } } } catch (err) { - if (err === 'timeout') { - // eslint-disable-next-line no-ex-assign - err = `The code you have written is taking longer than the ${previewTimeout}ms our challenges allow. You may have created an infinite loop or need to write a more efficient algorithm`; - } console.log(err); yield put(updateConsole(escape(err))); } diff --git a/client/src/templates/Challenges/utils/build.js b/client/src/templates/Challenges/utils/build.js index 0121cd957f..e38188c7e5 100644 --- a/client/src/templates/Challenges/utils/build.js +++ b/client/src/templates/Challenges/utils/build.js @@ -1,4 +1,4 @@ -import { transformers, transformersPreview } from '../rechallenge/transformers'; +import { transformers } from '../rechallenge/transformers'; import { cssToHtml, jsToHtml, concatHtml } from '../rechallenge/builders.js'; import { challengeTypes } from '../../../../utils/challengeTypes'; import createWorker from './worker-executor'; @@ -76,11 +76,11 @@ export function canBuildChallenge(challengeData) { return buildFunctions.hasOwnProperty(challengeType); } -export async function buildChallenge(challengeData, preview = false) { +export async function buildChallenge(challengeData) { const { challengeType } = challengeData; let build = buildFunctions[challengeType]; if (build) { - return build(challengeData, preview); + return build(challengeData); } throw new Error(`Cannot build challenge of type ${challengeType}`); } @@ -137,10 +137,8 @@ export function buildDOMChallenge({ files, required = [], template = '' }) { })); } -export function buildJSChallenge({ files }, preview = false) { - const pipeLine = preview - ? composeFunctions(...transformersPreview) - : composeFunctions(...transformers); +export function buildJSChallenge({ files }) { + const pipeLine = composeFunctions(...transformers); const finalFiles = Object.keys(files) .map(key => files[key]) .map(pipeLine); diff --git a/curriculum/challenges/english/08-coding-interview-prep/project-euler/problem-12-highly-divisible-triangular-number.english.md b/curriculum/challenges/english/08-coding-interview-prep/project-euler/problem-12-highly-divisible-triangular-number.english.md index ec923be79e..e2a97c4a89 100644 --- a/curriculum/challenges/english/08-coding-interview-prep/project-euler/problem-12-highly-divisible-triangular-number.english.md +++ b/curriculum/challenges/english/08-coding-interview-prep/project-euler/problem-12-highly-divisible-triangular-number.english.md @@ -62,67 +62,44 @@ divisibleTriangleNumber(500); + + ## Solution
+ ```js function divisibleTriangleNumber(n) { - if (n === 1) return 3; let counter = 1; let triangleNumber = counter++; + function getFactors(num) { + let factors = []; - while (noOfFactors(triangleNumber) < n) { - triangleNumber += counter++; - } -return triangleNumber; -} + let possibleFactor = 1; + let sqrt = Math.sqrt(num); -function noOfFactors(num) { - const primeFactors = getPrimeFactors(num); - let prod = 1; - for(let p in primeFactors) { - prod *= (primeFactors[p] + 1) - } - return prod; -} - -function getPrimeFactors(num) { - let n = num; - let primes = {}; - - let p = 2; - let sqrt = Math.sqrt(num); - - function checkAndUpdate(inc) { - if (n % p === 0) { - const curr = primes[p]; - if (curr) { - primes[p]++ - } else { - primes[p] = 1; + while (possibleFactor <= sqrt) { + if (num % possibleFactor == 0) { + factors.push(possibleFactor); + var otherPossibleFactor = num / possibleFactor; + if (otherPossibleFactor > possibleFactor) { + factors.push(otherPossibleFactor); + } } - n /= p; - } else { - p += inc; + possibleFactor++; } + + return factors; } - while(p === 2 && p <= n) { - checkAndUpdate(1); + while (getFactors(triangleNumber).length < n) { + triangleNumber += counter++; } - - while (p <= n && p <= sqrt) { - checkAndUpdate(2); - } - if(Object.keys(primes).length === 0) { - primes[num] = 1; - } else if(n !== 1) { - primes[n] = 1; - } - return primes; + console.log(triangleNumber) + return triangleNumber; } ``` diff --git a/curriculum/challenges/english/08-coding-interview-prep/project-euler/problem-14-longest-collatz-sequence.english.md b/curriculum/challenges/english/08-coding-interview-prep/project-euler/problem-14-longest-collatz-sequence.english.md index 3d6ad37cbe..a550092b37 100644 --- a/curriculum/challenges/english/08-coding-interview-prep/project-euler/problem-14-longest-collatz-sequence.english.md +++ b/curriculum/challenges/english/08-coding-interview-prep/project-euler/problem-14-longest-collatz-sequence.english.md @@ -35,8 +35,8 @@ tests: testString: assert.strictEqual(longestCollatzSequence(46500), 35655); - text: longestCollatzSequence(54512) should return 52527. testString: assert.strictEqual(longestCollatzSequence(54512), 52527); - - text: longestCollatzSequence(100000) should return 77031. - testString: assert.strictEqual(longestCollatzSequence(100000), 77031); + - text: longestCollatzSequence(1000000) should return 837799. + testString: assert.strictEqual(longestCollatzSequence(1000000), 837799); ``` diff --git a/curriculum/challenges/english/08-coding-interview-prep/project-euler/problem-7-10001st-prime.english.md b/curriculum/challenges/english/08-coding-interview-prep/project-euler/problem-7-10001st-prime.english.md index 436dfc60b0..ab7834db33 100644 --- a/curriculum/challenges/english/08-coding-interview-prep/project-euler/problem-7-10001st-prime.english.md +++ b/curriculum/challenges/english/08-coding-interview-prep/project-euler/problem-7-10001st-prime.english.md @@ -61,22 +61,21 @@ nthPrime(10001); ```js -const nthPrime = n => { - let pN = 2; - let step = 0; - while (step < n) { - let isPrime = true; - let rootN = Math.sqrt(pN); - for (let i = 2; i <= rootN; i++) { - if (!(pN % i)) { +const nthPrime = (number)=>{ + let pN = 2; + let step = 0; + while (stepemirps(20,true) should return [13,17,31,37,71,73,79,97,107,113,149,157,167,179,199,311,337,347,359,389] testString: assert.deepEqual(emirps(20, true), [13, 17, 31, 37, 71, 73, 79, 97, 107, 113, 149, 157, 167, 179, 199, 311, 337, 347, 359, 389]); - - text: emirps(1000) should return 70529 - testString: assert.deepEqual(emirps(1000), 70529); + - text: emirps(10000) should return 948349 + testString: assert.deepEqual(emirps(10000), 948349); - text: emirps([7700,8000],true) should return [7717,7757,7817,7841,7867,7879,7901,7927,7949,7951,7963] testString: assert.deepEqual(emirps([7700, 8000], true), [7717, 7757, 7817, 7841, 7867, 7879, 7901, 7927, 7949, 7951, 7963]); - text: emirps([7700,8000],true) should return 11