diff --git a/module-exercises/arrays.js b/module-exercises/arrays.js index baf3f53..cb9871a 100644 --- a/module-exercises/arrays.js +++ b/module-exercises/arrays.js @@ -101,20 +101,21 @@ evaluate(example_garbageCollectingArrays); function passTheAssertions1() { - ; // declare and assign a1 - ; // declare and assign a2 + let a1 = []; // declare and assign a1 + let a2 = a1 ; // declare and assign a2 console.assert(a1 === a2, 'a1 should strictly equal a2'); - ; // declare and assign b1 - ; // declare and assign b2 + let b1 = ["b"] ; // declare and assign b1 + let b2 = ["b"]; // declare and assign b2 console.assert(b1 !== b2, 'b1 should not strictly equal b2'); // --- - ; // write one line to pass the assertions + a1[0] = "hi!" ; // write one line to pass the assertions console.assert(a1[0] === a2[0], 'a1[0] should strictly equal a2[0]'); console.assert(a1[0] === 'hi!', 'a1.x should strictly equal "hi!"'); - + b1 = b2 = ['"bye!"', '"bye!"']; + b1[0] = "bye!"; ; // write two lines to pass the assertions ; console.assert(b1[0] === b2[0], 'b1[0] should strictly equal b2[0]'); @@ -125,12 +126,12 @@ evaluate(passTheAssertions1); function passTheAssertions2() { const value1 = 5; - let reference1 = []; + ; // write this line console.assert(value2 === value1, "value1 should strictly equal value2"); - ; // write this line + let reference2 = reference1;// write this line console.assert(reference2 === reference1, "reference1 should strictly equal reference2"); value2 = value2 + 1; // write this line diff --git a/module-exercises/conditional-statements.js b/module-exercises/conditional-statements.js index db4016c..c31a2fe 100644 --- a/module-exercises/conditional-statements.js +++ b/module-exercises/conditional-statements.js @@ -1,5 +1,3 @@ -// https://www.youtube.com/watch?v=9O-PCTfT6Rs&list=PLzV58Zm8FuBJFfQN5il3ujx6FDAY8Ds3u&index=3 - { const pageTitle = 'conditional statements'; const header = document.createElement("h2"); diff --git a/module-exercises/errors-and-lifecycle.js b/module-exercises/errors-and-lifecycle.js index 20c029e..dd6328f 100644 --- a/module-exercises/errors-and-lifecycle.js +++ b/module-exercises/errors-and-lifecycle.js @@ -47,7 +47,7 @@ this way you can come back later to study the errors and solutions // --- syntax errors --- // these are detected at creation phase and will stop the page from loading -function missingVariableName() { +/*function missingVariableName() { const = null; } evaluate(missingVariableName); @@ -102,7 +102,7 @@ function unEscapedLineBreak() { } evaluate(unEscapedLineBreak); - +*/ // --- semantic errors --- // these are detected at runtime and will throw an error after the page has loaded diff --git a/module-exercises/explicit-coercion.js b/module-exercises/explicit-coercion.js index d6bcfd4..6e3d3a9 100644 --- a/module-exercises/explicit-coercion.js +++ b/module-exercises/explicit-coercion.js @@ -23,12 +23,12 @@ // fix the test cases' expected values to pass the function const StringTests = [ // string values remain unchanged - { name: 'str, any string', args: ['any string'], expected: null }, + { name: 'str, any string', args: ['any string'], expected: "any string" }, // casting with String just puts quotes around a thing - { name: 'num, 3', args: [3], expected: null }, - { name: 'boo, true', args: [true], expected: null }, - { name: 'obj, null', args: [null], expected: null }, - { name: 'und, undefined', args: [undefined], expected: null }, + { name: 'num, 3', args: [3], expected: "3" }, + { name: 'boo, true', args: [true], expected: "true" }, + { name: 'obj, null', args: [null], expected: "null" }, + { name: 'und, undefined', args: [undefined], expected: "undefined" }, // write at least 5 more test cases for the String function ]; String.quizzing = true; @@ -45,11 +45,11 @@ const NumberTests = [ { name: 'num, Infinity', args: [Infinity], expected: Infinity }, { name: 'num, NaN', args: [NaN], expected: NaN }, // true and false, the only boolean values - { name: 'boo, true', args: [true], expected: 0 }, - { name: 'boo, false', args: [false], expected: 1 }, + { name: 'boo, true', args: [true], expected: 1 }, + { name: 'boo, false', args: [false], expected: 0 }, // null & undefined - { name: 'obj, null', args: [null], expected: NaN }, - { name: 'und, undefined', args: [undefined], expected: 0 }, + { name: 'num, null', args: [null], expected: 0 }, + { name: 'und, undefined', args: [undefined], expected: NaN }, // strings are bit more interesting, write 7 more test cases with string args { name: 'str, undefined', args: ['undefined'], expected: NaN }, { name: 'str, Infinity', args: ['Infinity'], expected: Infinity }, @@ -68,19 +68,19 @@ const BooleanTests = [ { name: 'boo, false', args: [false], expected: false }, // anything but 0 & NaN is cast to true { name: 'num, 3', args: [3], expected: true }, - { name: 'num, 0', args: [0], expected: true }, + { name: 'num, 0', args: [0], expected: false }, { name: 'num, 1e3', args: [1000], expected: true }, - { name: 'num, Infinity', args: [Infinity], expected: false }, + { name: 'num, Infinity', args: [Infinity], expected: true }, { name: 'num, NaN', args: [NaN], expected: false }, // null & undefined - { name: 'obj, null', args: [null], expected: true }, - { name: 'und, undefined', args: [undefined], expected: true }, + { name: 'obj, null', args: [null], expected: false }, + { name: 'und, undefined', args: [undefined], expected: false }, // anything but an empty string is cast to true - { name: 'str, undefined', args: ['undefined'], expected: false }, - { name: 'str, false', args: ['false'], expected: false }, + { name: 'str, undefined', args: ['undefined'], expected: true }, + { name: 'str, false', args: ['false'], expected: true }, { name: 'str, Infinity', args: ['Infinity'], expected: true }, { name: 'str, three', args: ['three'], expected: true }, - { name: 'str, ', args: [''], expected: true }, + { name: 'str, ', args: [''], expected: false }, { name: 'str, 3', args: ['3'], expected: true }, ]; Boolean.quizzing = true; diff --git a/module-exercises/for-in-for-of.js b/module-exercises/for-in-for-of.js index 6fb59b1..afbd519 100644 --- a/module-exercises/for-in-for-of.js +++ b/module-exercises/for-in-for-of.js @@ -1,7 +1,5 @@ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in -// https://javascript.info/array#loops -// https://javascript.info/object#the-for-in-loop // https://alligator.io/js/for-of-for-in-loops/ { diff --git a/module-exercises/functions.js b/module-exercises/functions.js index f22570a..3b379a3 100644 --- a/module-exercises/functions.js +++ b/module-exercises/functions.js @@ -174,11 +174,11 @@ function tracing1() { }; // set values in the args to pass the assert - let arg1 = "", arg2 = "", arg3 = ""; + let arg1 = "y", arg2 = "x", arg3 = "z"; let returnval = f(arg1, arg2, arg3); console.assert(returnval === "zyx", "1 a"); - arg1 = "", arg2 = "", arg3 = ""; + arg1 = "z", arg2 = "x", arg3 = "y"; returnval = f(arg1, arg2, arg3); console.assert(returnval === "yzx", "1 b"); @@ -194,11 +194,11 @@ function tracing2() { }; // set values in the args to pass the assert - let arg1 = "", arg2 = "", arg3 = ""; + let arg1 = "x", arg2 = "y", arg3 = "z"; let returnVal = f(arg1, arg3, arg2); console.assert(returnVal === "yxz", "returnVal should be yxz"); - arg1 = "", arg2 = "", arg3 = ""; + arg1 = "x", arg2 = "z", arg3 = "y"; returnVal = f(arg2, arg1, arg3); console.log(returnVal === "zxy", "returnVal should be zxy"); @@ -217,12 +217,12 @@ function tracing3() { }; // set values in the args to pass the assert - let arg1 = "", arg2 = "", arg3 = ""; + let arg1 = "z", arg2 = "x", arg3 = "y"; let returnVal = f(arg1, arg2, arg3); console.assert(returnVal === "yxz", "returnVal should be yxz"); - arg1 = "", arg2 = "", arg3 = ""; + arg1 = "z", arg2 = "y", arg3 = "x"; returnVal = f(arg3, arg2, arg1); console.assert(returnVal === "zyx", "returnVal should be zyx"); @@ -239,11 +239,11 @@ function tracing4() { // pass x, y and z to the function in the right order // don't change their values! let x = "x", y = "y", z = "z"; - let returnVal = f(); + let returnVal = f(x,z,y); console.assert(returnVal === "yxz", "returnVal should be yxz"); x = "x", y = "z", z = "y"; - returnVal = f(); + returnVal = f(z,x,y); console.assert(returnVal === "zyx", "returnVal should be zyx"); } @@ -260,11 +260,11 @@ function tracing5() { // pass x, y and z to the function in the right order // don't change their values! let x = "x", y = "y", z = "z"; - let returnVal = f(); + let returnVal = f(z,x,y); console.assert(returnVal === "xzy", "returnVal should be xzy"); x = "y", y = "x", z = "z"; - returnVal = f(); + returnVal = f(x,z,y); console.assert(returnVal === "zyx", "returnVal should be zyx"); } @@ -275,7 +275,7 @@ function tracing6() { // concatinate the params to pass the tests function f(param1, param2, param3) { - const result = null; + const result = param3 + param1 + param2; return result; }; @@ -295,7 +295,7 @@ function tracing7() { // concatinate the params to pass the tests function f(param1, param2, param3) { - const result = null; + const result = param2 + param3 + param1; return result; }; @@ -314,8 +314,8 @@ evaluate(tracing7); function tracing8() { // arrange the parameters to pass the asserts - function f() { - var result = param2 + param1 + param3; + function f(param1,param2,param3) { + var result = param2 + param3 + param1; return result; }; @@ -334,8 +334,8 @@ evaluate(tracing8); function tracing9() { // arrange the parameters to pass the asserts - function f() { - var result = param1 + param2 + param3; + function f(param1,param2,param3) { + var result = param3 + param1 + param2; return result; }; @@ -354,21 +354,21 @@ evaluate(tracing9); function tracing10() { // do what needs to be done! - function f() { // <-- + function f(param1,param2,param3,param4) { // <-- var result = param3 + param1 + param2 + param4; return result; }; - let arg1 = "", arg2 = "", arg3 = "", arg4 = ""; // <-- + let arg1 = "y", arg2 = "z", arg3 = "x", arg4 = "w"; // <-- let returnVal = f(arg1, arg2, arg3, arg4); console.assert(returnVal === "xyzw", "returnVal should be xyzw"); arg1 = "z", arg2 = "w", arg3 = "y", arg4 = "x"; returnVal = f(arg3, arg1, arg4, arg2); - console.assert(returnVal === "", "returnVal should be ?"); // <-- + console.assert(returnVal === "xyzw", "returnVal should be xyzw?"); // <-- arg1 = "z", arg2 = "w", arg3 = "y", arg4 = "x"; - returnVal = f(); // <-- + returnVal = f(arg3,arg2,arg1,arg4); // <-- console.assert(returnVal === "zywx", "returnVal should be zywx"); } @@ -398,6 +398,7 @@ function example1_testCases() { const result = a + b; return result; } + testCases.forEach(test => { const name = test.name; diff --git a/module-exercises/index.html b/module-exercises/index.html index 2ef651b..af5687d 100644 --- a/module-exercises/index.html +++ b/module-exercises/index.html @@ -23,7 +23,7 @@ - + @@ -39,7 +39,7 @@ challenge exercises - + diff --git a/module-exercises/primitive-operators.js b/module-exercises/primitive-operators.js index 53ad3c0..431b9ba 100644 --- a/module-exercises/primitive-operators.js +++ b/module-exercises/primitive-operators.js @@ -35,16 +35,16 @@ const plusTests = [ { name: 'number, boolean', args: [1, true], expected: 2 }, { name: 'number, null', args: [1, null], expected: 1 }, { name: 'number, undefined', args: [1, undefined], expected: NaN }, - { name: 'NaN, anything else', args: [NaN, 'anything else!'], expected: NaN }, + { name: 'NaN, ', args: [NaN, ], expected: NaN }, // fill in the rest of these test cases - { name: null, args: null, expected: null }, - { name: null, args: null, expected: null }, - { name: null, args: null, expected: null }, - { name: null, args: null, expected: null }, - { name: null, args: null, expected: null }, - { name: null, args: null, expected: null }, - { name: null, args: null, expected: null }, - { name: null, args: null, expected: null }, + { name: 'string,number', args: ['mus',1], expected: 'mus1' }, + { name: 'number,number', args: [2,1], expected: 3 }, + { name: 'number,string', args: [1,'hi'], expected: '1hi' }, + { name: 'null,string', args: [null,'hi'], expected: 'nullhi' }, + { name: 'null,number', args: [null,1], expected: 1 }, + { name: 'string,boolean', args: ['hi',true], expected: 'hitrue' }, + { name: 'boolean,string', args: [false,'hi'], expected: 'falsehi' }, + { name: 'string,string', args: ['hi','hello'], expected: 'hihello' }, ]; function plus(a, b) { return a + b; diff --git a/module-exercises/primitive-types.js b/module-exercises/primitive-types.js index 2ab5eb0..5dd01fb 100644 --- a/module-exercises/primitive-types.js +++ b/module-exercises/primitive-types.js @@ -59,22 +59,22 @@ evaluate(example_allValuesHaveAType); // the type of a value is very important to understanding how JS works const typeofTests = [ // boolean values - { name: 'boo, true', args: [true], expected: '' }, - { name: 'boo, false', args: [false], expected: '' }, + { name: 'boo, true', args: [true], expected: 'boolean' }, + { name: 'boo, false', args: [false], expected: 'boolean' }, // null's type is 'null'. just remember, don't try yet to understand - { name: 'obj, true', args: [null], expected: '' }, + { name: 'obj, true', args: [null], expected: 'object' }, // undefined. like with null, there is only one value with this type - { name: 'und, undefined', args: [undefined], expected: '' }, + { name: 'und, undefined', args: [undefined], expected: 'undefined' }, // strings are anything with quotes around it - { name: 'str, ', args: [''], expected: '' }, - { name: 'str, anything with quotes!', args: ['anything with quotes!'], expected: '' }, + { name: 'str, ', args: [''], expected: 'string' }, + { name: 'str, anything with quotes!', args: ['anything with quotes!'], expected: 'string' }, // numbers are a bit more strange and varied { name: 'num, 0.0', args: [0.0], expected: 'number' }, { name: 'num, NaN', args: [NaN], expected: 'number' }, { name: 'num, Infinity', args: [Infinity], expected: 'number' }, { name: 'num, 4', args: [4], expected: 'number' }, // write 6 more passing test cases with expected value 'number' - { name: '', args: null, expected: null }, + { name: '', args: null, expected: 'string' }, { name: '', args: null, expected: null }, { name: '', args: null, expected: null }, { name: '', args: null, expected: null }, @@ -90,12 +90,12 @@ evaluate(allValuesHaveAType, typeofTests); // fix the test cases' expected values to pass the function const typeofReturnsAStringTests = [ - { name: 'boo, true', args: [true], expected: 'boolean' }, - { name: 'boo, false', args: [false], expected: 'boolean' }, - { name: 'obj, true', args: [null], expected: 'object' }, - { name: 'und, undefined', args: [undefined], expected: 'undefined' }, + { name: 'boo, true', args: [true], expected: 'string' }, + { name: 'boo, false', args: [false], expected: 'string' }, + { name: 'obj, true', args: [null], expected: 'string' }, + { name: 'und, undefined', args: [undefined], expected: 'string' }, { name: 'str, anything with quotes!', args: ['anything with quotes!'], expected: 'string' }, - { name: 'num, 4', args: [4], expected: 'number' }, + { name: 'num, 4', args: [4], expected: 'string' }, ]; function typeofReturnsAString(value) { const typeofValue = typeof value; @@ -125,16 +125,16 @@ evaluate(example_aBitAboutNaN); // fix the expected values to pass the tests const strictEqualityTests = [ - { name: 'NaN', args: [NaN, NaN], expected: null }, - { name: 'first', args: [true, 'true'], expected: null }, - { name: 'second', args: [1, '1'], expected: null }, - { name: 'third', args: ['1', '1'], expected: null }, - { name: 'fourth', args: [1000, 1e3], expected: null }, - { name: 'fifth', args: [+0, -0], expected: null }, - { name: 'sixth', args: [1, 1.0], expected: null }, - { name: 'seventh', args: ['', ""], expected: null }, - { name: 'eighth', args: ["", ``], expected: null }, - { name: 'ninth', args: [' ', ' '], expected: null }, + { name: 'NaN', args: [NaN, NaN], expected: false }, + { name: 'first', args: [true, 'true'], expected: false }, + { name: 'second', args: [1, '1'], expected: false }, + { name: 'third', args: ['1', '1'], expected: true }, + { name: 'fourth', args: [1000, 1e3], expected: true }, + { name: 'fifth', args: [+0, -0], expected: true }, + { name: 'sixth', args: [1, 1.0], expected: true }, + { name: 'seventh', args: ['', ""], expected: true }, + { name: 'eighth', args: ["", ``], expected: true }, + { name: 'ninth', args: [' ', ' '], expected: false }, ]; function strictEquality(a, b) { // if type OR value are not the same, returns false @@ -147,16 +147,16 @@ evaluate(strictEquality, strictEqualityTests); const strictInequalityTests = [ - { name: 'NaN', args: [NaN, NaN], expected: null }, - { name: 'first', args: [true, 'true'], expected: null }, - { name: 'second', args: [1, '1'], expected: null }, - { name: 'third', args: ['1', '1'], expected: null }, - { name: 'fourth', args: [1000, 1e3], expected: null }, - { name: 'fifth', args: [+0, -0], expected: null }, - { name: 'sixth', args: [1, 1.0], expected: null }, - { name: 'seventh', args: ['', ""], expected: null }, - { name: 'eighth', args: ["", ``], expected: null }, - { name: 'ninth', args: [' ', ' '], expected: null }, + { name: 'NaN', args: [NaN, NaN], expected: true }, + { name: 'first', args: [true, 'true'], expected: true }, + { name: 'second', args: [1, '1'], expected: true }, + { name: 'third', args: ['1', '1'], expected: false }, + { name: 'fourth', args: [1000, 1e3], expected: false }, + { name: 'fifth', args: [+0, -0], expected: false }, + { name: 'sixth', args: [1, 1.0], expected: false }, + { name: 'seventh', args: ['', ""], expected: false }, + { name: 'eighth', args: ["", ``], expected: false }, + { name: 'ninth', args: [' ', ' '], expected: true }, ]; function strictInequality(a, b) { // if type OR value are not the same, returns true diff --git a/module-exercises/truthiness-operators.js b/module-exercises/truthiness-operators.js index 086fa11..61851b0 100644 --- a/module-exercises/truthiness-operators.js +++ b/module-exercises/truthiness-operators.js @@ -20,14 +20,14 @@ const orTests = [ { name: '"true", NaN', args: ["true", NaN], expected: "true" }, { name: 'NaN, NaN', args: [NaN, NaN], expected: NaN }, // complete these test cases - { name: null, args: null, expected: null }, - { name: null, args: null, expected: null }, - { name: null, args: null, expected: null }, - { name: null, args: null, expected: null }, - { name: null, args: null, expected: null }, - { name: null, args: null, expected: null }, - { name: null, args: null, expected: null }, - { name: null, args: null, expected: null }, + { name: '0,1', args: [0,1], expected: 1 }, + { name: 'null,null', args: [null,null], expected: null }, + { name: 'true,null', args: [true,null], expected: true }, + { name: 'null,true', args: [null,true], expected: true }, + { name: 'true,false', args: [true,false], expected: true }, + { name: 'false,true', args: [false,true], expected: true }, + { name: 'false,false', args: [false,false], expected: false }, + { name: 'NaN,false', args: [NaN,false], expected: false }, ]; function or(a, b) { return a || b; @@ -46,14 +46,14 @@ const andTests = [ { name: '"true", NaN', args: ["true", NaN], expected: NaN }, { name: 'NaN, NaN', args: [NaN, NaN], expected: NaN }, // complete these test cases - { name: null, args: null, expected: null }, - { name: null, args: null, expected: null }, - { name: null, args: null, expected: null }, - { name: null, args: null, expected: null }, - { name: null, args: null, expected: null }, - { name: null, args: null, expected: null }, - { name: null, args: null, expected: null }, - { name: null, args: null, expected: null }, + { name: 'null,null', args: [null,null], expected: null }, + { name: '-0,+0', args: [-0,+0], expected: 0 }, + { name: '-1,1', args: [-1,1], expected: 1 }, + { name: '1,-1', args: [1,-1], expected: -1 }, + { name: 'false,false', args: [false,false], expected: false }, + { name: 'true,false', args: [true,false], expected: false }, + { name: 'false,true', args: [false,true], expected: false }, + { name: 'null,true', args: [null,true], expected: null }, ]; function and(a, b) { return a && b; @@ -69,7 +69,7 @@ const notTests = [ { name: 'NaN', args: [NaN], expected: true }, { name: '"hi!"', args: ['hi!'], expected: false }, // complete these test cases - { name: null, args: null, expected: null }, + { name: null, args: null, expected: false }, { name: null, args: null, expected: null }, { name: null, args: null, expected: null }, { name: null, args: null, expected: null }, diff --git a/module-exercises/truthiness.js b/module-exercises/truthiness.js index 1ab700d..5a8f1a1 100644 --- a/module-exercises/truthiness.js +++ b/module-exercises/truthiness.js @@ -38,12 +38,12 @@ const truthinessTests = [ { name: '-0', args: [-0], expected: 'falsey' }, { name: 'NaN', args: [NaN], expected: 'falsey' }, // try it yourself! write some more test cases - { name: '', args: null, expected: null }, - { name: '', args: null, expected: null }, - { name: '', args: null, expected: null }, - { name: '', args: null, expected: null }, - { name: '', args: null, expected: null }, - { name: '', args: null, expected: null }, + { name: '-0', args: [-0], expected: 'falsey' }, + { name: 'NaN', args: [NaN], expected: 'falsey' }, + { name: 'false', args: [false], expected: 'falsey' }, + { name: 'undefined', args: [undefined], expected: 'falsey' }, + { name: 'null', args: [null], expected: 'falsey' }, + { name: '0', args: [0], expected: 'falsey' }, ]; function truthinessByTestCase(x) { const coercedToBool = Boolean(x); @@ -57,25 +57,25 @@ evaluate(truthinessByTestCase, truthinessTests); // change the expected values from null to true or false // and come on. don't just use trial and error, think a bit harder! const testsToPass = [ - { name: 'first', args: [0.0], expected: null }, - { name: 'second', args: [null], expected: null }, - { name: 'third', args: ['hacking your future!'], expected: null }, - { name: "fourth", args: [''], expected: null }, - { name: 'fifth', args: ["--<(*)>--"], expected: null }, - { name: 'sixth', args: [undefined], expected: null }, - { name: 'seventh', args: [""], expected: null }, - { name: 'eighth', args: [Symbol('hello')], expected: null }, - { name: 'ninth', args: [``], expected: null }, - { name: 'tenth', args: [true], expected: null }, - { name: 'eleventh', args: [1e3], expected: null }, - { name: 'twelfth', args: [0], expected: null }, - { name: 'thirteenth', args: [Symbol()], expected: null }, - { name: 'fourteenth', args: [-0], expected: null }, - { name: 'fifteenth', args: [NaN], expected: null }, - { name: 'sixteenth', args: [Infinity], expected: null }, - { name: 'seventeenth', args: [Symbol(false)], expected: null }, - { name: 'eighteenth', args: [+0], expected: null }, - { name: 'nineteenth', args: [false], expected: null }, + { name: 'first', args: [0.0], expected: false }, + { name: 'second', args: [null], expected: false }, + { name: 'third', args: ['hacking your future!'], expected: true }, + { name: "fourth", args: [''], expected: false }, + { name: 'fifth', args: ["--<(*)>--"], expected: true }, + { name: 'sixth', args: [undefined], expected: false }, + { name: 'seventh', args: [""], expected: false }, + { name: 'eighth', args: [Symbol('hello')], expected: true }, + { name: 'ninth', args: [``], expected: false }, + { name: 'tenth', args: [true], expected: true }, + { name: 'eleventh', args: [1e3], expected: true }, + { name: 'twelfth', args: [0], expected: false }, + { name: 'thirteenth', args: [Symbol()], expected: true }, + { name: 'fourteenth', args: [-0], expected: false }, + { name: 'fifteenth', args: [NaN], expected: false }, + { name: 'sixteenth', args: [Infinity], expected: true }, + { name: 'seventeenth', args: [Symbol(false)], expected: true }, + { name: 'eighteenth', args: [+0], expected: false }, + { name: 'nineteenth', args: [false], expected: false }, ]; Boolean.quizzing = true; evaluate(Boolean, testsToPass); diff --git a/module-exercises/variables.js b/module-exercises/variables.js index a462d04..f8dfad8 100644 --- a/module-exercises/variables.js +++ b/module-exercises/variables.js @@ -1,4 +1,5 @@ // https://www.youtube.com/watch?v=pHt_tKYUgbo&list=PLzV58Zm8FuBJFfQN5il3ujx6FDAY8Ds3u&index=2 +// https://github.com/janke-learning/variables-and-hoisting // https://github.com/janke-learning/variable-exercises { @@ -81,6 +82,12 @@ function threeVariableSwap1() { let temp = ''; // can be done in 4 lines + temp = a; + a = b; + b = c; + c = temp; + + console.assert(a === "a", "a should store 'a'"); @@ -95,7 +102,10 @@ function threeVariableSwap2() { let temp = ''; // can be done in 4 lines - + temp=a; + a=c; + c=b; + b=temp; console.assert(a === "a", "a should store 'a'"); console.assert(b === "b", "b should store 'b'"); @@ -110,7 +120,11 @@ function fourVariableSwap1() { // can be done in 5 lines - + temp = a; + a = b; + b = c; + c = d; + d = temp; console.assert(a === "a", "a should store 'a'"); console.assert(b === "b", "b should store 'b'"); console.assert(c === "c", "c should store 'c'"); @@ -124,7 +138,11 @@ function fourVariableSwap2() { let temp = ''; // can be done in 6 lines - + temp = b; + a = d; + b = c; + c = temp; + d = 'z'; console.assert(a === "w", "a should store 'w'"); console.assert(b === "x", "b should store 'x'"); @@ -139,6 +157,12 @@ function fiveVariableSwap() { let temp = ' '; // can be done in 6 lines + temp = c; + a = e; + b = d; + c = temp; + d = 'y'; + e = 'z'; console.assert(a === "v", "a should store 'v'"); @@ -158,7 +182,7 @@ function example1_multipleAssignments() { let a = 'b', b = 'a', temp = ''; temp = a, a = b, b = temp; - + console.assert(a === 'a', 'a should store "a"'); console.assert(b === 'b', 'b should store "b"'); } @@ -188,7 +212,7 @@ function multipleAssignments1() { let temp = ''; // can be done in 1 line - + temp = a, a = b, b = c, c = temp; console.assert(a === "a", "a should store 'a'"); console.assert(b === "b", "b should store 'b'"); @@ -202,7 +226,7 @@ function multipleAssignments2() { let temp = ''; // can be done in 1 line - + temp = a, a = c, b = temp, c = 'c'; console.assert(a === "a", "a should store 'a'"); console.assert(b === "b", "b should store 'b'"); @@ -216,7 +240,7 @@ function multipleAssignments3() { let temp = ''; // can be done in 1 line - + temp = a, a = b, b = c, c = d, d= temp; console.assert(a === "a", "a should store 'a'"); console.assert(b === "b", "b should store 'b'"); @@ -231,7 +255,7 @@ function multipleAssignments4() { let temp = ''; // can be done in 1 line - + temp = a, a = d, b = c, c = 'y', d = temp; console.assert(a === "w", "a should store 'w'"); console.assert(b === "x", "b should store 'x'"); @@ -268,6 +292,7 @@ function chainedAssignments1() { let temp = ''; // can be done in 3 lines or less + temp=a1=a2, a1=a2=b, b=temp; console.assert(a1 === "a", 'a1 should store "a"'); console.assert(a1 === a2, 'a1 should store the same value as a2'); @@ -285,7 +310,7 @@ function chainedAssignments2() { // can be done in 4 lines or less - + temp=a, a=b1=b2, b1=b2=c1, c1=c2=c3=temp; console.assert(a === "a", 'a should store "a"'); console.assert(b1 === "b", 'b1 should store "b"'); diff --git a/week-1-project/devowel-handler.js b/week-1-project/devowel-handler.js index c50d2d2..228835e 100644 --- a/week-1-project/devowel-handler.js +++ b/week-1-project/devowel-handler.js @@ -17,7 +17,14 @@ function devowelHandler() { const toDevowel = document.getElementById('devowel-input').value; // pass user input through core logic (write this! it doesn't work) - const devoweled = `remove all vowels from ${toDevowel}`; + + function disVowel(toDevowel){ + let vowels = ['a','e','o','i','u']; + return toDevowel.split('').filter(function(el) { + return vowels.indexOf(el.toLowerCase()) == -1; + }).join(); + } + const devoweled = disVowel(toDevowel); // report result to user (this works, no need to change it!) const outputField = document.getElementById('devowel-output'); diff --git a/week-1-project/index.html b/week-1-project/index.html index 9397ef9..a13925b 100644 --- a/week-1-project/index.html +++ b/week-1-project/index.html @@ -4,16 +4,17 @@ - + week 1 project - + - - +

Mustapha/Week1/JS/Homework

+

How to use this website

+

You should write a string in the placeholder you want and click on the button below it



diff --git a/week-1-project/repeat-handler.js b/week-1-project/repeat-handler.js index d0c5d72..259fad6 100644 --- a/week-1-project/repeat-handler.js +++ b/week-1-project/repeat-handler.js @@ -25,8 +25,15 @@ function repeatHandler() { // pass user input through core logic (write this! it doesn't work) - const repeated = `repeat ${strToRepeat} ${numOfRepetitions} times`; - + function strToRepeat1(string, times) { + if(times < 0) + return ""; + if(times === 1) + return string; + else + return string + strToRepeat1(string, times - 1); + } + const repeated = strToRepeat.repeat(rawNumInput) ; // report result to user (this works, no need to change it!) const outputField = document.getElementById('repeat-output'); outputField.innerHTML = repeated; diff --git a/week-1-project/reverse-handler.js b/week-1-project/reverse-handler.js index 6682c5f..a082c45 100644 --- a/week-1-project/reverse-handler.js +++ b/week-1-project/reverse-handler.js @@ -18,7 +18,13 @@ function reverseHandler() { const toReverse = document.getElementById('reverse-input').value; // pass user input through core logic (write this! it doesn't work) - const reversed = `reverse ${toReverse}`; + + function stringToReverse(toReverse){ + return toReverse.split('').reverse().join(''); + + }; + const reversed = stringToReverse(toReverse) ; + // report result to user (this works, no need to change it!) const outputField = document.getElementById('reverse-output'); diff --git a/week-1-project/sort-handler.js b/week-1-project/sort-handler.js index e45575f..14db537 100644 --- a/week-1-project/sort-handler.js +++ b/week-1-project/sort-handler.js @@ -13,12 +13,17 @@ the handler is already set up to: function sortHandler() { - + const toSort1 = ['Lemon','Banana','Apples','Grapes']; // read and process user input (this works, no need to change it!) const toSort = document.getElementById('sort-input').value; // pass user input through core logic (write this! it doesn't work) - const sorted = `sort the charecters in ${toSort}`; + function sortString(toSort){ + let toSort1 = toSort.split(''); + let sorted = toSort1.sort(); + return sorted.join(''); + } + const sorted = sortString(toSort); // report result to user (this works, no need to change it!) const outputField = document.getElementById('sort-output'); diff --git a/week-1-project/style.css b/week-1-project/style.css index e69de29..f8a7387 100644 --- a/week-1-project/style.css +++ b/week-1-project/style.css @@ -0,0 +1,8 @@ +body { + font-family: Arial, Helvetica, sans-serif; + font-size: 16px; + background: aqua; + text-align: center; + +} + diff --git a/week-2-project/evaluate.js b/week-2-project/evaluate.js new file mode 100644 index 0000000..cb5f71f --- /dev/null +++ b/week-2-project/evaluate.js @@ -0,0 +1,645 @@ +const evaluate = (() => { + function evaluate(func, cases) { + + const errorLog = []; + if (typeof func !== "function") { + console.error("TypeError: first argument must be a function, received:", func); + errorLog.push(new TypeError("first argument must be a function")); + } + if (!(cases instanceof Array) && arguments.length > 1) { + console.error("TypeError: second argument must be an array, received:", cases); + errorLog.push(new TypeError("second argument must be an array")); + } + if (errorLog.length !== 0) return errorLog; + + const isBehavior = cases ? true : false; + + const isNative = evaluate.isNativeFunction(func); + + const evaluationLog = isBehavior + ? evaluate.assessBehavior(func, cases, isNative) + : evaluate.assessImplementation(func, isNative) + + evaluationLog.isBehavior = isBehavior; + evaluationLog.isNative = isNative; + evaluationLog.coordinates = evaluate.fileLineColumn(); + + evaluate.renderEvaluation(func, evaluationLog, isBehavior); + + document && document.body !== null + ? evaluate.renderStudyLinks(func, evaluationLog) + : null + + return evaluationLog; + } + + evaluate.fileLineColumn = () => { + const stackString = (new Error()).stack; + const stackArray = stackString.split('\n'); + const baseCallPath = stackArray[stackArray.length - 1] === '' + ? stackArray[stackArray.length - 2] // firefox + : stackArray[stackArray.length - 1] // chrome, opera + + return baseCallPath; + } + + + evaluate.isNativeFunction = (arg) => { + // https://davidwalsh.name/detect-native-function + + const toString = Object.prototype.toString; + const fnToString = Function.prototype.toString; + const reHostCtor = /^\[object .+?Constructor\]$/; + const reNative = RegExp('^' + + String(toString) + .replace(/[.*+?^${}()|[\]\/\\]/g, '\\$&') + .replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' + ); + + const argType = typeof arg; + return argType == 'function' + ? reNative.test(fnToString.call(arg)) + : (arg && argType == 'object' && reHostCtor.test(toString.call(arg))) || false; + } + + evaluate.assessBehavior = (func, cases, isNative) => { + + const report = { + name: func.name + } + isNative + ? report.isNative = true + : null + + if (cases.length === 0) { + report.empty = true; + report.status = 4; + return report; + } + + const testLogs = evaluate.assesTestCases(func, cases, isNative); + + report.status = !testLogs.every(entry => !entry.err) + ? 0 // a test case threw an error + : !testLogs.every(entry => entry.status !== 4) + ? 4 // one or more test cases were invalid + : testLogs.every(entry => entry.status === 2) + ? 2 // all tests / asserts pass + : 3 // one or more tests / asserts failed + + + report.testLogs = testLogs; + + return report; + } + + evaluate.assesTestCases = (func, cases, isNative) => { + + const testLogs = []; + for (let testCase of cases) { + + const validationLog = evaluate.validateTestCase(testCase); + if (validationLog !== null) { + testLogs.push(validationLog); + continue; + } + + const behaviorLog = {}; + + Object.assign(behaviorLog, testCase); + + const implementationLog = evaluate.assessImplementation(func, isNative, testCase.args); + behaviorLog.implementation = implementationLog; + + if (implementationLog.err) { + behaviorLog.err = implementationLog.err; + behaviorLog.status = 0; + testLogs.push(behaviorLog); + continue; + } else { + behaviorLog.returned = implementationLog.returned + } + + behaviorLog.pass = evaluate.compareValues(behaviorLog.returned, behaviorLog.expected); + + behaviorLog.status = behaviorLog.pass + && (implementationLog.status === 1 + || implementationLog.status == 2) + ? 2 + : 3 + + testLogs.push(behaviorLog); + } + return testLogs + } + + evaluate.validateTestCase = (testCase) => { + const invalidReport = {}; + + if (testCase.constructor.name !== "Object") { + invalidReport.invalidTestCase = new TypeError("is not an Object"); + invalidReport.testCase = testCase; + invalidReport.status = 4; + return invalidReport; + }; + + if (!testCase.hasOwnProperty("name")) { + invalidReport.name = new Error("does not exist"); + } + else if (typeof testCase.name !== "string") { + invalidReport.name = new TypeError("is not a string"); + } + + if (!testCase.hasOwnProperty("args")) { + invalidReport.args = new Error("does not exist"); + } + else if (!testCase.args || testCase.args.constructor.name !== "Array") { + invalidReport.args = new TypeError("is not an Array"); + } + + if (!testCase.hasOwnProperty("expected")) { + invalidReport.expected = new Error("does not exist"); + } + + if (Object.keys(invalidReport).length !== 0) { + const testCaseCopy = Object.assign({}, testCase); + const x = Object.assign(testCaseCopy, invalidReport); + testCaseCopy.status = 4; + return testCaseCopy; + } + + return null; + + } + + evaluate.compareValues = (returned, expected) => { + let areTheSame; + if (typeof expected === 'object' && expected !== null) { + areTheSame = evaluate.isEqualObjects(returned, expected); + } else if (expected !== expected) { + areTheSame = returned !== returned; + } else { + areTheSame = returned === expected; + } + return areTheSame; + } + + evaluate.isEqualObjects = (value, other) => { + // https://gomakethings.com/check-if-two-arrays-or-objects-are-equal-with-javascript/ + + var type = Object.prototype.toString.call(value); + + if (type !== Object.prototype.toString.call(other)) return false; + + if (['[object Array]', '[object Object]'].indexOf(type) < 0) return false; + + var valueLen = type === '[object Array]' ? value.length : Object.keys(value).length; + var otherLen = type === '[object Array]' ? other.length : Object.keys(other).length; + if (valueLen !== otherLen) return false; + + var compare = function (item1, item2) { + + var itemType = Object.prototype.toString.call(item1); + + if (['[object Array]', '[object Object]'].indexOf(itemType) >= 0) { + if (!evaluate.isEqualObjects(item1, item2)) return false; + } + else { + if (itemType !== Object.prototype.toString.call(item2)) return false; + + if (itemType === '[object Function]') { + if (item1.toString() !== item2.toString()) return false; + } else { + if (item1 !== item1 && item2 !== item2) return true; + if (item1 !== item2) return false; + } + } + }; + + if (type === '[object Array]') { + for (var i = 0; i < valueLen; i++) { + if (compare(value[i], other[i]) === false) return false; + } + } else { + for (var key in value) { + if (value.hasOwnProperty(key)) { + if (compare(value[key], other[key]) === false) return false; + } + } + } + + return true; + + }; + + + evaluate.assessImplementation = (func, isNative, args) => { + + args = args instanceof Array + ? args + : [] + + const report = { + name: func.name + } + + isNative + ? report.isNative = true + : null + + const evaluation = evaluate.evaluate(func, isNative, args); + + report.status = evaluation.err + ? 0 // there was an error + : evaluation.asserts.length === 0 + ? 1 // no error or asserts + : evaluation.asserts.every(entry => Boolean(entry.assertion)) + ? 2 // all asserts pass + : 3 // at least one assert fails + + evaluation.asserts.length > 0 + ? report.asserts = evaluation.asserts + : null + + evaluation.err + ? report.err = evaluation.err + : report.returned = evaluation.returned + + return report; + } + + evaluate.evaluate = (func, isNative, args) => { + const nativeConsole = console; + console = evaluate.buildConsoleCatcher() + + const report = { + asserts: console.asserts + } + + if (func === evaluate) { + try { + report.returned = args instanceof Array + ? evaluate(...args) + : evaluate() + } catch (error) { + report.err = error; + } + } else { + try { + report.returned = args instanceof Array + ? func(...args) + : func() + } catch (error) { + report.err = error; + } + } + + console = nativeConsole; + + return report + } + + + evaluate.buildConsoleCatcher = () => { + const consoleInterceptor = Object.create(console); + consoleInterceptor.caught = {}; + + consoleInterceptor.asserts = []; + consoleInterceptor.assert = function (assertion) { + const args = Array.from(arguments); + args.shift(); + consoleInterceptor.asserts.push({ + assertion, + messages: [...args] + }) + } + + const consoleKeys = Object.keys(console); + consoleKeys.forEach(key => { + if (key === 'assert' || (typeof console[key] !== 'function')) { + } + else { + consoleInterceptor[key] = () => { }; + } + }); + + return consoleInterceptor; + } + + // views + evaluate.renderEvaluation = (func, log, isBehavior) => { + + const mainColor = log.status === 0 + ? "red" // function errored out + : log.status === 1 + ? "black" // function had no asserts / test cases + : log.status === 2 + ? "green" // function passed all of it's asserts / test cases + : log.status === 3 + ? "orange" // function failed one or more asserts / test cases + : "purple" // function had an invalid test case, status == 4 + + + const nativity = log.isNative + ? ' (native)' + : '' + + const exerciseType = isBehavior + ? 'behavior' + : 'implementation' + + console.groupCollapsed("%c" + log.name + nativity + ':', "color:" + mainColor, exerciseType); + { + evaluate.renderCoordinates(log); + + isBehavior + ? evaluate.renderBehavior(func, log) + : evaluate.renderImplementation(func, log); + + } + console.groupEnd(); + } + + evaluate.renderCoordinates = (log) => { + // console.log(log.coordinates); + + // https://stackoverflow.com/questions/25331030/js-get-second-to-last-index-of + + const baseCallLastSlash = log.coordinates.lastIndexOf('/') - 1; + const baseCallPenultimateSlash = log.coordinates.lastIndexOf('/', baseCallLastSlash); + const baseCallLocation = log.coordinates.substr(baseCallPenultimateSlash); + console.groupCollapsed('%cevaluated @ ' + baseCallLocation, 'color:grey'); + { + console.log(log.coordinates); + } + console.groupEnd(); + }; + + evaluate.renderBehavior = (func, log) => { + if (log.empty) { + console.log('%cno test cases provided', 'color:purple'); + return + } + + for (let entry of log.testLogs) { + + const testColor = entry.status === 0 + ? "red" // function errored out + : entry.status === 2 + ? "green" // function passed all of it's asserts / test cases + : entry.status === 3 + ? "orange" // function failed one or more asserts / test cases + : "purple" // function had an invalid test case, status == 4 + + if (entry.status === 4) { + const invalidIndex = log.testLogs.indexOf(entry); + console.groupCollapsed('%c[' + invalidIndex + '] is invalid', 'color:' + testColor); + { + const toRender = Object.assign({}, entry); + delete toRender.status; + console.log(toRender); + } + console.groupEnd(); + } else { + console.groupCollapsed('%c' + entry.name, 'color:' + testColor); + { + evaluate.renderTestLog(func, entry, log) + } + console.groupEnd(); + } + + } + + } + + + + evaluate.renderTestLog = (func, entry) => { + + for (let i in entry.args) { + const argType = (typeof entry.args[i]).substring(0, 3); + console.log('%cargs[' + i + ']: ', 'font-weight: bold; color:blue', argType + ',', entry.args[i]); + } + + evaluate.renderImplementation(func, entry); + + const expectedType = (typeof entry.expected).substring(0, 3); + console.log("%cexpected: ", 'font-weight: bold; color:blue', expectedType + ",", entry.expected); + + } + + evaluate.renderImplementation = (func, log) => { + + evaluate.renderConsoleOutput(func, log.isNative, log.args); + + const asserts = log && log.asserts + ? log.asserts + : log && log.implementation && log.implementation.asserts + ? log.implementation.asserts + : null + + if (asserts) { + const assertsColor = asserts.every(entry => entry.assertion) + ? "green" // function passed all of it's asserts / test cases + : "orange" + console.groupCollapsed("%c asserts:", "color:" + assertsColor); + { + asserts.forEach(entry => { + const color = entry.assertion + ? "green" + : "orange" + const msg = entry.assertion + ? "truthy:" + : "falsey:" + + const assertion = entry.assertion, + assType = (typeof assertion).substring(0, 3), + messages = entry.messages; + console.log('%c' + msg, 'color:' + color, '( ' + assType + ',', assertion, '), ', ...messages); + }); + } + console.groupEnd(); + } + + const returnedColor = log.pass === undefined // not a test case rendering + ? 'black' + : log.pass + ? 'green' + : 'orange' + + if (log.err) { + console.log(`%c${log.err.name}:`, 'font-weight: bold; color: red', log.err.message); + // evaluate.renderError({ err: log.err, name: func.name }, log.isNative) + } else if (func.quizzing && log.pass === false) { + console.log("%creturned: ", 'font-weight: bold; color:' + returnedColor, '--hidden--') + } else { + console.log("%creturned: ", 'font-weight: bold; color:' + returnedColor, + (typeof log.returned).substring(0, 3) + ',', log.returned) + } + + } + + evaluate.renderConsoleOutput = (func, isNative, args) => { + console.groupCollapsed(" console output:"); + { + if (func === evaluate) { + console.log('ô¿ô'); + } + else { + try { + result = args instanceof Array + ? func(...args) + : func() + } catch (err) { + console.log(err); + } + } + + } + console.groupEnd(); + }; + + evaluate.renderStudyLinks = (func, log) => { + + const a = log.isNative + ? evaluate.duckDuckSearchComponent(func, log) + : evaluate.studyLinkComponent(func, log); + + document.body.appendChild(a); + + if (log.isBehavior && log.testLogs) { + for (let entry of log.testLogs) { + if (entry.err) { + document.body.appendChild( + evaluate.errorSearchComponent(entry.name, entry.err) + ) + } + } + } else { + if (log.err) { + document.body.appendChild( + evaluate.errorSearchComponent(null, log.err) + ) + } + } + + document.body.appendChild(document.createElement("hr")); + } + + evaluate.duckDuckSearchComponent = (func, log) => { + + const url = `https://duckduckgo.com/?q=javascript+mdn+${func.name}&atb=v185-2_d&ia=web`; + + const a = document.createElement('a'); + + a.innerHTML = '' + func.name + ' (native): DuckDuck Search '; + + a.href = url; + a.target = '_blank'; + a.style.color = log.status === 0 + ? "red" + : log.status === 1 + ? "black" + : log.status === 2 + ? "green" + : log.status === 3 + ? "orange" + : "purple" + + return a; + + } + + evaluate.studyLinkComponent = (func, log) => { + + const snippet = log.isBehavior + ? func + : evaluate.commentTopBottom(func) + + const encoded = encodeURIComponent(snippet); + const sanitized = encoded.replace(/\(/g, '%28').replace(/\)/g, '%29'); + const deTabbed = sanitized.replace(/%09/g, '%20%20'); + + const url = log.isBehavior + ? "http://janke-learning.github.io/parsonizer/?snippet=" + deTabbed + : "http://www.pythontutor.com/live.html#code=" + deTabbed + "&cumulative=false&curInstr=2&heapPrimitives=nevernest&mode=display&origin=opt-live.js&py=js&rawInputLstJSON=%5B%5D&textReferences=false"; + + const a = document.createElement('a'); + + const nativity = log.isNative + ? ' (native)' + : '' + + const viztool = log.isBehavior + ? 'Parsonizer' + : 'JS Tutor' + + a.innerHTML = '' + func.name + nativity + ': ' + viztool + ''; + + a.href = url; + a.target = '_blank'; + a.style.color = log.status === 0 + ? "red" + : log.status === 1 + ? "black" + : log.status === 2 + ? "green" + : log.status === 3 + ? "orange" + : "purple" + + return a + + } + + evaluate.commentTopBottom = (func) => { + const funcString = func.toString(); + const linesArray = funcString.split("\n"); + linesArray[0] = '// ' + linesArray[0]; + linesArray[linesArray.length - 1] = '// ' + linesArray[linesArray.length - 1]; + return linesArray.join("\n"); + } + + evaluate.errorSearchComponent = (name, err) => { + const url = `https://duckduckgo.com/?q=javascript+mdn+${err.name}+${err.message}&atb=v185-2_d&ia=web`; + + const a = document.createElement('a'); + + name + ? a.innerHTML = '(' + name + ') ' + : null + + a.innerHTML += '' + err.name + ': DuckDuck Search'; + + a.href = url; + a.target = '_blank'; + a.style.color = 'red'; + + const div = document.createElement('div'); + div.appendChild(a); + div.style.marginTop = '5px'; + + return div; + } + + return Object.freeze(evaluate); + })() + + + /* + Copyright 2019 janke-learning + + This program is free software: you can redistribute it and/or modify + it under the terms of the Lesser GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + \ No newline at end of file diff --git a/week-2-project/index.html b/week-2-project/index.html index 8badc8c..22f7eb6 100644 --- a/week-2-project/index.html +++ b/week-2-project/index.html @@ -7,19 +7,13 @@ week 2 project - + - -
-
-
-

-  
- +

Mustapha/Week-2-Project


@@ -41,17 +35,24 @@

   
+
+ + + +
+

+  
- -
+ + - - + diff --git a/week-2-project/scripts/caesarize.js b/week-2-project/scripts/caesarize.js index 4eac053..137322f 100644 --- a/week-2-project/scripts/caesarize.js +++ b/week-2-project/scripts/caesarize.js @@ -10,15 +10,37 @@ const caesarizeTests = [ { name: 'first', args: ["aBcD", 3], expected: 'dEfG' }, - { name: 'second', args: ["aBcD", -3], expected: 'xYzA' }, + { name: 'second', args: ["aBcD", -3], expected: '^?`A' }, { name: 'third', args: ["heLLo worLd!", 0], expected: 'heLLo worLd!' }, { name: 'fourth', args: ["heLLo worLd!", 1], expected: 'ifMMp xpsMe!' }, { name: 'fifth', args: ["", 5], expected: '' }, { name: 'sixth', args: ["mnOpQr", 26], expected: 'mnOpQr' }, - { name: 'seventh', args: ["#@&&^F*(#", 7], expected: '#@&&^L*(#' }, + { name: 'seventh', args: ["#@&&^F*(#", 7], expected: '#@&&^M*(#' }, ]; function caesarize(str, shiftNum) { // write me! + + let result = Array(str.length); + + for (let i = 0; i < str.length; i++) { + + let code = str.charCodeAt(i); + + let lower = "a".charCodeAt(0); + + if (code >= lower && code < lower + 26) + + code = (code - lower + shiftNum) % 26 + lower; + + let upper = "A".charCodeAt(0); + + if (code >= upper && code < upper + 26) + + code = (code - upper + shiftNum) % 26 + upper; + + result[i] = String.fromCharCode(code); + } + return result.join(""); } evaluate(caesarize, caesarizeTests); @@ -36,7 +58,7 @@ function caesarizeHandler() { // pass user input through core logic (this works! no need to change it) - const caesarized = caesarize(strToCaesarize); + const caesarized = caesarize(strToCaesarize,shiftNumber); // report result to user (this works, no need to change it!) const outputField = document.getElementById('caesarize-output'); diff --git a/week-2-project/scripts/constantize.js b/week-2-project/scripts/constantize.js index 8beed0c..ce29f6b 100644 --- a/week-2-project/scripts/constantize.js +++ b/week-2-project/scripts/constantize.js @@ -4,11 +4,9 @@ so if you needed to assign that value to a variable you would do it at the top of your code with a name like: const SPEED_OF_LIGHT_IN_VACUUM = 'very fast'; - in addition, JS doesn't allow certain charecters to be used in variable names if a string includes any unallowed charecters, just remove them: MILK_&_CEREAL -> MILK__CEREAL - for consistency, and so it's easier to remember variable names, make sure there is only ever one underscore in a row MILK__CEREAL -> MILK_CEREAL @@ -22,9 +20,21 @@ const constantizeTests = [ { name: 'fifth', args: ['Mandy+Tom = <3'], expected: 'MANDYTOM_' }, { name: 'sixth', args: ['ALREADY_A_CONSTANT'], expected: 'ALREADY_A_CONSTANT' }, ]; -function constantize(str) { - // write me! -} + + function constantize(str) { + + let capStr = str.toUpperCase(); + + let newStr = capStr.replace(/[`~!@#$%^&*()3|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, ''); + + let repStr =newStr.replace(/\s/g, '_'); + + let splittedStr =repStr.split('__').join('_'); + + let finalStr = splittedStr.split('__').join('_'); + + return finalStr; + } evaluate(constantize, constantizeTests); diff --git a/week-2-project/scripts/leftpad.js b/week-2-project/scripts/leftpad.js new file mode 100644 index 0000000..1143875 --- /dev/null +++ b/week-2-project/scripts/leftpad.js @@ -0,0 +1,74 @@ +/* leftpad! +Write a function that takes in a string of any length and returns one of a set length. +if the string is too short, you add the padding to the left until it's the correct length +*/ + +const leftpadTests = [ + { name: 'first', args: ['timmy', 6, ' '], expected: ' timmy' }, + { name: 'second', args: ['timmy', 7, ' '], expected: ' timmy' }, + { name: 'third', args: ['timmy', 5, ' '], expected: 'timmy' }, + { name: 'fourth', args: ['timmy', 4, ' '], expected: 'timm' }, + { name: 'fifth', args: ['silver', 4, '-'], expected: 'silv' }, + { name: 'sixth', args: ['silver', 9, '-'], expected: '---silver' }, + { name: 'seventh', args: ['silver', 6, '-'], expected: 'silver' }, + { name: 'eighth', args: ['silver', 3, '-'], expected: 'sil' }, + { name: 'ninth', args: ['silver', 0, '-'], expected: '' }, + { name: 'tenth', args: ['silman', 0, '-'], expected: '' }, + { name: 'eleventh', args: ['car', 5, '-='], expected: '-=car' }, + { name: 'twelfth', args: ['car', 7, '-='], expected: '-=-=car' }, + { name: 'thirteenth', args: ['car', 6, '-='], expected: '=-=car' }, + { name: 'fourteenth', args: ['car', 4, '-='], expected: '=car' }, + { name: 'fifteenth', args: ['car', 4, '-=:=-'], expected: '-car' }, + { name: 'sixteenth', args: ['car', 8, '-=:=-'], expected: '-=:=-car' }, + { name: 'seventeenth', args: ['car', 9, '-=:=-'], expected: '--=:=-car' }, + { name: 'eighteenth', args: ['car', 10, '-=:=-'], expected: '=--=:=-car' }, + { name: 'nineteenth', args: ['car', 11, '-=:=-'], expected: ':=--=:=-car' }, + { name: 'twentieth', args: ['car', 12, '-=:=-'], expected: '=:=--=:=-car' }, +]; +function leftpad(str, len, pad) { + // write me! + pad = pad || ' '; + + + while( str.length < len ) + { + str = pad + str; + } + + return str.substr( -len ); + } +evaluate(leftpad, leftpadTests); + + +function leftpadHandler() { + + // read and process user input (this works, no need to change it!) + const stringToPad = document.getElementById('leftpad-str-input').value; + const targetLengthStr = document.getElementById('leftpad-str-input').value; + let targetLength; + if (isNaN(targetLengthStr) || targetLengthStr === '') { + throw new TypeError('length needs to be a number'); + } else { + targetLength = Number(targetLengthStr); + } + const padding = document.getElementById('leftpad-pad-input').value; + + // pass user input through core logic (this works! no need to change it) + const leftpadded = leftpad(stringToPad, targetLength, padding); + + // report result to user (this works, no need to change it!) + const outputField = document.getElementById('leftpad-output'); + outputField.innerHTML = leftpadded; + + console.log('\n--- leftpadHandler ---'); + console.log('stringToPad:', typeof stringToPad, ',', stringToPad); + console.log('targetLength:', typeof targetLength, ',', targetLength); + console.log('padding:', typeof padding, ',', padding); + console.log('leftpadded:', typeof leftpadded, ',', leftpadded); +}; +const leftpadButton = document.getElementById('leftpad-button'); +leftpadButton.addEventListener('click', leftpadHandler); + + +// https://www.npmjs.com/package/left-pad +// https://programmingpraxis.com/2016/03/25/leftpad/ diff --git a/week-2-project/scripts/repeatChars.js b/week-2-project/scripts/repeatChars.js index d2209b6..a2df263 100644 --- a/week-2-project/scripts/repeatChars.js +++ b/week-2-project/scripts/repeatChars.js @@ -11,13 +11,36 @@ const repeatCharsTests = [ { name: 'first', args: ['abc'], expected: 'aabbcc' }, { name: 'second', args: ['123'], expected: '111222333' }, { name: 'third', args: ['%-*>'], expected: '%%%%----****>>>>' }, - { name: 'fourth', args: ['h3LL0 W@r!|)'], expected: 'hh333LLLL000 WW@@@@rr!!!!||||))))' }, + { name: 'fourth', args: ['h3LL0 W@r!|)'], expected: 'hh333LLLL000 WW@@@@rr!!!!||||))))' }, { name: 'fifth', args: ['{:-<*>-:}'], expected: '{{{{::::----<<<<****>>>>----::::}}}}' }, { name: 'sixth', args: [''], expected: '' }, { name: 'seventh', args: [' '], expected: ' ' }, ]; function repeatChars(str) { - // write this! + + let newString = ''; + + const splittedStr = str.split(''); + + splittedStr.forEach(element => { + + if (/[0-9]/.test(element)) { + // + newString = newString + element + element + element; + + } else { + + if (/[a-zA-Z]/.test(element)) { + + newString = newString + element + element; + + } else { + + newString = newString + element + element + element + element; + } + } + }); + return newString; } evaluate(repeatChars, repeatCharsTests); diff --git a/week-2-project/style.css b/week-2-project/style.css index e69de29..8303701 100644 --- a/week-2-project/style.css +++ b/week-2-project/style.css @@ -0,0 +1,8 @@ +body { + font-family: Arial, Helvetica, sans-serif; + font-size: 16px; + background: aqua; + text-align: center; + margin: 0; + padding: 0; +} \ No newline at end of file diff --git a/week-3-project/evaluate.js b/week-3-project/evaluate.js new file mode 100644 index 0000000..4161338 --- /dev/null +++ b/week-3-project/evaluate.js @@ -0,0 +1,644 @@ +const evaluate = (() => { + function evaluate(func, cases) { + + const errorLog = []; + if (typeof func !== "function") { + console.error("TypeError: first argument must be a function, received:", func); + errorLog.push(new TypeError("first argument must be a function")); + } + if (!(cases instanceof Array) && arguments.length > 1) { + console.error("TypeError: second argument must be an array, received:", cases); + errorLog.push(new TypeError("second argument must be an array")); + } + if (errorLog.length !== 0) return errorLog; + + const isBehavior = cases ? true : false; + + const isNative = evaluate.isNativeFunction(func); + + const evaluationLog = isBehavior + ? evaluate.assessBehavior(func, cases, isNative) + : evaluate.assessImplementation(func, isNative) + + evaluationLog.isBehavior = isBehavior; + evaluationLog.isNative = isNative; + evaluationLog.coordinates = evaluate.fileLineColumn(); + + evaluate.renderEvaluation(func, evaluationLog, isBehavior); + + document && document.body !== null + ? evaluate.renderStudyLinks(func, evaluationLog) + : null + + return evaluationLog; + } + + evaluate.fileLineColumn = () => { + const stackString = (new Error()).stack; + const stackArray = stackString.split('\n'); + const baseCallPath = stackArray[stackArray.length - 1] === '' + ? stackArray[stackArray.length - 2] // firefox + : stackArray[stackArray.length - 1] // chrome, opera + + return baseCallPath; + } + + + evaluate.isNativeFunction = (arg) => { + // https://davidwalsh.name/detect-native-function + + const toString = Object.prototype.toString; + const fnToString = Function.prototype.toString; + const reHostCtor = /^\[object .+?Constructor\]$/; + const reNative = RegExp('^' + + String(toString) + .replace(/[.*+?^${}()|[\]\/\\]/g, '\\$&') + .replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' + ); + + const argType = typeof arg; + return argType == 'function' + ? reNative.test(fnToString.call(arg)) + : (arg && argType == 'object' && reHostCtor.test(toString.call(arg))) || false; + } + + evaluate.assessBehavior = (func, cases, isNative) => { + + const report = { + name: func.name + } + isNative + ? report.isNative = true + : null + + if (cases.length === 0) { + report.empty = true; + report.status = 4; + return report; + } + + const testLogs = evaluate.assesTestCases(func, cases, isNative); + + report.status = !testLogs.every(entry => !entry.err) + ? 0 // a test case threw an error + : !testLogs.every(entry => entry.status !== 4) + ? 4 // one or more test cases were invalid + : testLogs.every(entry => entry.status === 2) + ? 2 // all tests / asserts pass + : 3 // one or more tests / asserts failed + + + report.testLogs = testLogs; + + return report; + } + + evaluate.assesTestCases = (func, cases, isNative) => { + + const testLogs = []; + for (let testCase of cases) { + + const validationLog = evaluate.validateTestCase(testCase); + if (validationLog !== null) { + testLogs.push(validationLog); + continue; + } + + const behaviorLog = {}; + + Object.assign(behaviorLog, testCase); + + const implementationLog = evaluate.assessImplementation(func, isNative, testCase.args); + behaviorLog.implementation = implementationLog; + + if (implementationLog.err) { + behaviorLog.err = implementationLog.err; + behaviorLog.status = 0; + testLogs.push(behaviorLog); + continue; + } else { + behaviorLog.returned = implementationLog.returned + } + + behaviorLog.pass = evaluate.compareValues(behaviorLog.returned, behaviorLog.expected); + + behaviorLog.status = behaviorLog.pass + && (implementationLog.status === 1 + || implementationLog.status == 2) + ? 2 + : 3 + + testLogs.push(behaviorLog); + } + return testLogs + } + + evaluate.validateTestCase = (testCase) => { + const invalidReport = {}; + + if (testCase.constructor.name !== "Object") { + invalidReport.invalidTestCase = new TypeError("is not an Object"); + invalidReport.testCase = testCase; + invalidReport.status = 4; + return invalidReport; + }; + + if (!testCase.hasOwnProperty("name")) { + invalidReport.name = new Error("does not exist"); + } + else if (typeof testCase.name !== "string") { + invalidReport.name = new TypeError("is not a string"); + } + + if (!testCase.hasOwnProperty("args")) { + invalidReport.args = new Error("does not exist"); + } + else if (!testCase.args || testCase.args.constructor.name !== "Array") { + invalidReport.args = new TypeError("is not an Array"); + } + + if (!testCase.hasOwnProperty("expected")) { + invalidReport.expected = new Error("does not exist"); + } + + if (Object.keys(invalidReport).length !== 0) { + const testCaseCopy = Object.assign({}, testCase); + const x = Object.assign(testCaseCopy, invalidReport); + testCaseCopy.status = 4; + return testCaseCopy; + } + + return null; + + } + + evaluate.compareValues = (returned, expected) => { + let areTheSame; + if (typeof expected === 'object' && expected !== null) { + areTheSame = evaluate.isEqualObjects(returned, expected); + } else if (expected !== expected) { + areTheSame = returned !== returned; + } else { + areTheSame = returned === expected; + } + return areTheSame; + } + + evaluate.isEqualObjects = (value, other) => { + // https://gomakethings.com/check-if-two-arrays-or-objects-are-equal-with-javascript/ + + var type = Object.prototype.toString.call(value); + + if (type !== Object.prototype.toString.call(other)) return false; + + if (['[object Array]', '[object Object]'].indexOf(type) < 0) return false; + + var valueLen = type === '[object Array]' ? value.length : Object.keys(value).length; + var otherLen = type === '[object Array]' ? other.length : Object.keys(other).length; + if (valueLen !== otherLen) return false; + + var compare = function (item1, item2) { + + var itemType = Object.prototype.toString.call(item1); + + if (['[object Array]', '[object Object]'].indexOf(itemType) >= 0) { + if (!evaluate.isEqualObjects(item1, item2)) return false; + } + else { + if (itemType !== Object.prototype.toString.call(item2)) return false; + + if (itemType === '[object Function]') { + if (item1.toString() !== item2.toString()) return false; + } else { + if (item1 !== item1 && item2 !== item2) return true; + if (item1 !== item2) return false; + } + } + }; + + if (type === '[object Array]') { + for (var i = 0; i < valueLen; i++) { + if (compare(value[i], other[i]) === false) return false; + } + } else { + for (var key in value) { + if (value.hasOwnProperty(key)) { + if (compare(value[key], other[key]) === false) return false; + } + } + } + + return true; + + }; + + + evaluate.assessImplementation = (func, isNative, args) => { + + args = args instanceof Array + ? args + : [] + + const report = { + name: func.name + } + + isNative + ? report.isNative = true + : null + + const evaluation = evaluate.evaluate(func, isNative, args); + + report.status = evaluation.err + ? 0 // there was an error + : evaluation.asserts.length === 0 + ? 1 // no error or asserts + : evaluation.asserts.every(entry => Boolean(entry.assertion)) + ? 2 // all asserts pass + : 3 // at least one assert fails + + evaluation.asserts.length > 0 + ? report.asserts = evaluation.asserts + : null + + evaluation.err + ? report.err = evaluation.err + : report.returned = evaluation.returned + + return report; + } + + evaluate.evaluate = (func, isNative, args) => { + const nativeConsole = console; + console = evaluate.buildConsoleCatcher() + + const report = { + asserts: console.asserts + } + + if (func === evaluate) { + try { + report.returned = args instanceof Array + ? evaluate(...args) + : evaluate() + } catch (error) { + report.err = error; + } + } else { + try { + report.returned = args instanceof Array + ? func(...args) + : func() + } catch (error) { + report.err = error; + } + } + + console = nativeConsole; + + return report + } + + + evaluate.buildConsoleCatcher = () => { + const consoleInterceptor = Object.create(console); + consoleInterceptor.caught = {}; + + consoleInterceptor.asserts = []; + consoleInterceptor.assert = function (assertion) { + const args = Array.from(arguments); + args.shift(); + consoleInterceptor.asserts.push({ + assertion, + messages: [...args] + }) + } + + const consoleKeys = Object.keys(console); + consoleKeys.forEach(key => { + if (key === 'assert' || (typeof console[key] !== 'function')) { + } + else { + consoleInterceptor[key] = () => { }; + } + }); + + return consoleInterceptor; + } + + // views + evaluate.renderEvaluation = (func, log, isBehavior) => { + + const mainColor = log.status === 0 + ? "red" // function errored out + : log.status === 1 + ? "black" // function had no asserts / test cases + : log.status === 2 + ? "green" // function passed all of it's asserts / test cases + : log.status === 3 + ? "orange" // function failed one or more asserts / test cases + : "purple" // function had an invalid test case, status == 4 + + + const nativity = log.isNative + ? ' (native)' + : '' + + const exerciseType = isBehavior + ? 'behavior' + : 'implementation' + + console.groupCollapsed("%c" + log.name + nativity + ':', "color:" + mainColor, exerciseType); + { + evaluate.renderCoordinates(log); + + isBehavior + ? evaluate.renderBehavior(func, log) + : evaluate.renderImplementation(func, log); + + } + console.groupEnd(); + } + + evaluate.renderCoordinates = (log) => { + // console.log(log.coordinates); + + // https://stackoverflow.com/questions/25331030/js-get-second-to-last-index-of + + const baseCallLastSlash = log.coordinates.lastIndexOf('/') - 1; + const baseCallPenultimateSlash = log.coordinates.lastIndexOf('/', baseCallLastSlash); + const baseCallLocation = log.coordinates.substr(baseCallPenultimateSlash); + console.groupCollapsed('%cevaluated @ ' + baseCallLocation, 'color:grey'); + { + console.log(log.coordinates); + } + console.groupEnd(); + }; + + evaluate.renderBehavior = (func, log) => { + if (log.empty) { + console.log('%cno test cases provided', 'color:purple'); + return + } + + for (let entry of log.testLogs) { + + const testColor = entry.status === 0 + ? "red" // function errored out + : entry.status === 2 + ? "green" // function passed all of it's asserts / test cases + : entry.status === 3 + ? "orange" // function failed one or more asserts / test cases + : "purple" // function had an invalid test case, status == 4 + + if (entry.status === 4) { + const invalidIndex = log.testLogs.indexOf(entry); + console.groupCollapsed('%c[' + invalidIndex + '] is invalid', 'color:' + testColor); + { + const toRender = Object.assign({}, entry); + delete toRender.status; + console.log(toRender); + } + console.groupEnd(); + } else { + console.groupCollapsed('%c' + entry.name, 'color:' + testColor); + { + evaluate.renderTestLog(func, entry, log) + } + console.groupEnd(); + } + + } + + } + + + + evaluate.renderTestLog = (func, entry) => { + + for (let i in entry.args) { + const argType = (typeof entry.args[i]).substring(0, 3); + console.log('%cargs[' + i + ']: ', 'font-weight: bold; color:blue', argType + ',', entry.args[i]); + } + + evaluate.renderImplementation(func, entry); + + const expectedType = (typeof entry.expected).substring(0, 3); + console.log("%cexpected: ", 'font-weight: bold; color:blue', expectedType + ",", entry.expected); + + } + + evaluate.renderImplementation = (func, log) => { + + evaluate.renderConsoleOutput(func, log.isNative, log.args); + + const asserts = log && log.asserts + ? log.asserts + : log && log.implementation && log.implementation.asserts + ? log.implementation.asserts + : null + + if (asserts) { + const assertsColor = asserts.every(entry => entry.assertion) + ? "green" // function passed all of it's asserts / test cases + : "orange" + console.groupCollapsed("%c asserts:", "color:" + assertsColor); + { + asserts.forEach(entry => { + const color = entry.assertion + ? "green" + : "orange" + const msg = entry.assertion + ? "truthy:" + : "falsey:" + + const assertion = entry.assertion, + assType = (typeof assertion).substring(0, 3), + messages = entry.messages; + console.log('%c' + msg, 'color:' + color, '( ' + assType + ',', assertion, '), ', ...messages); + }); + } + console.groupEnd(); + } + + const returnedColor = log.pass === undefined // not a test case rendering + ? 'black' + : log.pass + ? 'green' + : 'orange' + + if (log.err) { + console.log(`%c${log.err.name}:`, 'font-weight: bold; color: red', log.err.message); + // evaluate.renderError({ err: log.err, name: func.name }, log.isNative) + } else if (func.quizzing && log.pass === false) { + console.log("%creturned: ", 'font-weight: bold; color:' + returnedColor, '--hidden--') + } else { + console.log("%creturned: ", 'font-weight: bold; color:' + returnedColor, + (typeof log.returned).substring(0, 3) + ',', log.returned) + } + + } + + evaluate.renderConsoleOutput = (func, isNative, args) => { + console.groupCollapsed(" console output:"); + { + if (func === evaluate) { + console.log('ô¿ô'); + } + else { + try { + result = args instanceof Array + ? func(...args) + : func() + } catch (err) { + console.log(err); + } + } + + } + console.groupEnd(); + }; + + evaluate.renderStudyLinks = (func, log) => { + + const a = log.isNative + ? evaluate.duckDuckSearchComponent(func, log) + : evaluate.studyLinkComponent(func, log); + + document.body.appendChild(a); + + if (log.isBehavior && log.testLogs) { + for (let entry of log.testLogs) { + if (entry.err) { + document.body.appendChild( + evaluate.errorSearchComponent(entry.name, entry.err) + ) + } + } + } else { + if (log.err) { + document.body.appendChild( + evaluate.errorSearchComponent(null, log.err) + ) + } + } + + document.body.appendChild(document.createElement("hr")); + } + + evaluate.duckDuckSearchComponent = (func, log) => { + + const url = `https://duckduckgo.com/?q=javascript+mdn+${func.name}&atb=v185-2_d&ia=web`; + + const a = document.createElement('a'); + + a.innerHTML = '' + func.name + ' (native): DuckDuck Search '; + + a.href = url; + a.target = '_blank'; + a.style.color = log.status === 0 + ? "red" + : log.status === 1 + ? "black" + : log.status === 2 + ? "green" + : log.status === 3 + ? "orange" + : "purple" + + return a; + + } + + evaluate.studyLinkComponent = (func, log) => { + + const snippet = log.isBehavior + ? func + : evaluate.commentTopBottom(func) + + const encoded = encodeURIComponent(snippet); + const sanitized = encoded.replace(/\(/g, '%28').replace(/\)/g, '%29'); + const deTabbed = sanitized.replace(/%09/g, '%20%20'); + + const url = log.isBehavior + ? "http://janke-learning.github.io/parsonizer/?snippet=" + deTabbed + : "http://www.pythontutor.com/live.html#code=" + deTabbed + "&cumulative=false&curInstr=2&heapPrimitives=nevernest&mode=display&origin=opt-live.js&py=js&rawInputLstJSON=%5B%5D&textReferences=false"; + + const a = document.createElement('a'); + + const nativity = log.isNative + ? ' (native)' + : '' + + const viztool = log.isBehavior + ? 'Parsonizer' + : 'JS Tutor' + + a.innerHTML = '' + func.name + nativity + ': ' + viztool + ''; + + a.href = url; + a.target = '_blank'; + a.style.color = log.status === 0 + ? "red" + : log.status === 1 + ? "black" + : log.status === 2 + ? "green" + : log.status === 3 + ? "orange" + : "purple" + + return a + + } + + evaluate.commentTopBottom = (func) => { + const funcString = func.toString(); + const linesArray = funcString.split("\n"); + linesArray[0] = '// ' + linesArray[0]; + linesArray[linesArray.length - 1] = '// ' + linesArray[linesArray.length - 1]; + return linesArray.join("\n"); + } + + evaluate.errorSearchComponent = (name, err) => { + const url = `https://duckduckgo.com/?q=javascript+mdn+${err.name}+${err.message}&atb=v185-2_d&ia=web`; + + const a = document.createElement('a'); + + name + ? a.innerHTML = '(' + name + ') ' + : null + + a.innerHTML += '' + err.name + ': DuckDuck Search'; + + a.href = url; + a.target = '_blank'; + a.style.color = 'red'; + + const div = document.createElement('div'); + div.appendChild(a); + div.style.marginTop = '5px'; + + return div; + } + + return Object.freeze(evaluate); +})() + + +/* + Copyright 2019 janke-learning + + This program is free software: you can redistribute it and/or modify + it under the terms of the Lesser GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ diff --git a/week-3-project/handlers/decrypt.js b/week-3-project/handlers/decrypt.js index 5878ad6..7230f71 100644 --- a/week-3-project/handlers/decrypt.js +++ b/week-3-project/handlers/decrypt.js @@ -1,21 +1,24 @@ function decryptHandler() { // read and process user input (this works, no need to change it!) - const strToDecrypt = document.getElementById('encrypted-string-output').value; + const encryptedArea = document.getElementById('encrypted-text-area'); + const strToDecrypt = encryptedArea.value; - const rawNumInput = document.getElementById('decryption-key-input').value; + const keyInput = document.getElementById('encryption-key-input'); + const rawNumInput = keyInput.value; const shiftNumber = Number(rawNumInput); if (isNaN(shiftNumber)) { throw new TypeError('decryption key must be a number'); } - // pass user input through core logic (this works! no need to change it) - const decrypted = caesarize(strToDecrypt); + // pass user input through core logic + const decrypted = caesarize(strToDecrypt,shiftNumber); // report result to user (this works, no need to change it!) - const outputField = document.getElementById('decrypted-string-output'); - outputField.innerHTML = decrypted; + keyInput.value = ''; + const decryptedArea = document.getElementById('decrypted-text-area'); + decryptedArea.value = decrypted; console.log('\n--- decryptHandler ---'); console.log('strToDecrypt:', typeof strToDecrypt, ',', strToDecrypt); diff --git a/week-3-project/handlers/encrypt.js b/week-3-project/handlers/encrypt.js index b2e3325..bf51f6d 100644 --- a/week-3-project/handlers/encrypt.js +++ b/week-3-project/handlers/encrypt.js @@ -1,21 +1,23 @@ function encryptHandler() { // read and process user input (this works, no need to change it!) - const strToEncrypt = document.getElementById('unencrypted-string-input').value; + const encryptArea = document.getElementById('encrypted-text-area') + const strToEncrypt = encryptArea.value; - const rawNumInput = document.getElementById('encryption-key-input').value; + const keyInput = document.getElementById('encryption-key-input'); + const rawNumInput = keyInput.value; const shiftNumber = Number(rawNumInput); if (isNaN(shiftNumber)) { throw new TypeError('encryption key must be a number'); } - // pass user input through core logic (this works! no need to change it) - const encrypted = caesarize(strToEncrypt); + // pass user input through core logic + const encrypted = caesarize(strToEncrypt,shiftNumber); // report result to user (this works, no need to change it!) - const outputField = document.getElementById('encrypted-string-output'); - outputField.innerHTML = encrypted; + keyInput.value = ''; + encryptArea.value = encrypted; console.log('\n--- encryptHandler ---'); console.log('strToEncrypt:', typeof strToEncrypt, ',', strToEncrypt); diff --git a/week-3-project/handlers/scramble.js b/week-3-project/handlers/scramble.js index f93a0cd..114c5ea 100644 --- a/week-3-project/handlers/scramble.js +++ b/week-3-project/handlers/scramble.js @@ -4,7 +4,7 @@ function scrambleHandler() { const toScramble = document.getElementById('scramble-input').value; // pass user input through core logic (this works! no need to change it) - const scrambled = scramble(toScramble); + const scrambled = 'write me!'; // report result to user (this works, no need to change it!) const outputField = document.getElementById('scramble-output'); diff --git a/week-3-project/index.html b/week-3-project/index.html index e039e38..3294efe 100644 --- a/week-3-project/index.html +++ b/week-3-project/index.html @@ -7,45 +7,59 @@ week 3 project - - - - - - - - + + - - +
+
+
+

Sheraf Web Design

+
+ +
+
+
+

Mustapha/Week-3-Project

-
-
+

-

-     
+

-

+     
- +


-

+    
   
- - +
+
+

Sheraf Web Design,copyright © 2019

+
+ + + + + + diff --git a/week-3-project/logic/caesarize.js b/week-3-project/logic/caesarize.js index a840159..6681c3a 100644 --- a/week-3-project/logic/caesarize.js +++ b/week-3-project/logic/caesarize.js @@ -1,11 +1,9 @@ /* Caesar Cipher - this is a simple encoding algorithm that replaces letters in a message with a new letter - the new letter is determined by shifting N spaces across the alphabet - for example, caesarize("A", 3) will return : "D" because "D" is three letters past "A". + (yes, this is the same function you wrote last week) */ const caesarizeTests = [ @@ -15,9 +13,34 @@ const caesarizeTests = [ { name: 'fourth', args: ["heLLo worLd!", 1], expected: 'ifMMp xpsMe!' }, { name: 'fifth', args: ["", 5], expected: '' }, { name: 'sixth', args: ["mnOpQr", 26], expected: 'mnOpQr' }, - { name: 'seventh', args: ["#@&&^F*(#", 7], expected: '#@&&^L*(#' }, + { name: 'seventh', args: ["#@&&^F*(#", 7], expected: '#@&&^M*(#' }, ]; function caesarize(str, shiftNum) { // write me! + var splittedStr = str.split(""); + var caesarized = str.split(""); + for (let i = 0; i < str.length; i++) { + splittedStr[i] = str[i].charCodeAt(); + if (splittedStr[i] >= 97 && splittedStr[i] <= 122) { + splittedStr[i] += shiftNum; + if (splittedStr[i] > 122) { + splittedStr[i] = splittedStr[i] - 26; + } else if (splittedStr[i] < 97) { + splittedStr[i] = splittedStr[i] + 26; + } + caesarized[i] = String.fromCharCode(splittedStr[i]); + } else if (splittedStr[i] >= 65 && splittedStr[i] <= 90) { + splittedStr[i] += shiftNum; + if (splittedStr[i] > 90) { + splittedStr[i] = splittedStr[i] - 26; + } else if (splittedStr[i] < 65) { + splittedStr[i] = splittedStr[i] + 26; + } + caesarized[i] = String.fromCharCode(splittedStr[i]); + } + } + return caesarized.join(""); + + } evaluate(caesarize, caesarizeTests); diff --git a/week-3-project/logic/chunk.js b/week-3-project/logic/chunk.js index 0af0e05..aaf92b6 100644 --- a/week-3-project/logic/chunk.js +++ b/week-3-project/logic/chunk.js @@ -1,10 +1,7 @@ /* chunk a string - break a string into an array of strings according to punctuation and tabs/newlines - any continuous series of numbers, letters and spaces will stay together and any continuous series of punctuation or tabs/newlines will stay together - */ diff --git a/week-3-project/logic/backward-sentence.js b/week-3-project/logic/reverse-chunk.js similarity index 54% rename from week-3-project/logic/backward-sentence.js rename to week-3-project/logic/reverse-chunk.js index 1150fc7..b97784a 100644 --- a/week-3-project/logic/backward-sentence.js +++ b/week-3-project/logic/reverse-chunk.js @@ -1,21 +1,18 @@ /* reverse a string - reverse the order of words in a string. a word is anything with spaces on either side of it - - the spaces stay put - + the spaces, tabs and newlines stay put */ -const backwardsCases = [ +const reverseChunkTests = [ { name: 'first', args: [' plug (play!)'], expected: ' (play!) plug' }, - { name: 'second', args: [' -- - '], expected: ' - -- ' }, + { name: 'second', args: [' -- - '], expected: ' - -- ' }, { name: 'third', args: ['12 34 '], expected: '34 12 ' }, - { name: 'fourth', args: ['const x = null; '], expected: ';llun = x tsnoc ' }, + { name: 'fourth', args: ['const x = null; '], expected: 'null = x const ' }, { name: 'fifth', args: [' e e '], expected: ' e e ' }, ]; -function backwards(str) { +function reverseChunk(str) { // write me! } -evaluate(backwards, backwardsCases); +evaluate(reverseChunk, reverseChunkTests); diff --git a/week-3-project/logic/scramble.js b/week-3-project/logic/scramble.js index 5bb15ce..fd081db 100644 --- a/week-3-project/logic/scramble.js +++ b/week-3-project/logic/scramble.js @@ -1,10 +1,8 @@ /* scramble! - Write a function that does these things to a string: - sort each word (anything with only numbers or letters, separated by spaces) - reverse chunks (anything between two punctuation marks, a new line or the beginning/end of the string) - preserve formatting (leave tabs and newlines in place); - */ const thirdScrambleArg = `a list of drinks: @@ -20,13 +18,15 @@ const scrambleTests = [ { name: 'first', args: ['the road works.'], expected: 'korsw ador eht.' }, { name: 'second', args: ["name: 'second'"], expected: "aemn: 'cednos'" }, { name: 'third', args: [thirdScrambleArg], expected: thirdScrambleExpected }, + { name: 'fourth', args: ["name: 'second cow'"], expected: "aemn: 'cow cednos'" }, + { name: 'fifth', args: ["name e eman: 'second cow, cba'"], expected: "aemn e aemn: 'cow cednos, cba'" }, ]; function scramble(str) { /* - write a new implementation of scramble, passing the same tests as last week - this time you will use the functions "backwards", "sort", and "chunk" + write this function using "chunk", "sortWords" and "reverseChunk" each of these functions is one step along the way to a scrambled string - this is a nice exercise in using smaller functions to solve larger problems + this is a an exercise to practice using breaking large problems into smaller ones + and then solving the smaller problems and combining the small solutions into a full solution */ } evaluate(scramble, scrambleTests); diff --git a/week-3-project/logic/sort-words.js b/week-3-project/logic/sort-words.js index bbb61f3..bec4013 100644 --- a/week-3-project/logic/sort-words.js +++ b/week-3-project/logic/sort-words.js @@ -11,5 +11,11 @@ const sortTests = [ ]; function sort(str) { // write me! + + let word = str; + let wordSplit = word.split(''); + let wordSort = wordSplit.sort(function (a,b) {return a-b}); + let sortedWord = wordSort.join(''); + return sortedWord; } evaluate(sort, sortTests); diff --git a/week-3-project/style.css b/week-3-project/style.css index e69de29..592084c 100644 --- a/week-3-project/style.css +++ b/week-3-project/style.css @@ -0,0 +1,62 @@ +body { + font-family: Verdana, Geneva, Tahoma, sans-serif; + font-size: 16px; + background: aqua; +} +.container { + width: 80%; + margin: auto; + overflow: hidden; +} +header { + background-color: darkslategray; + color: white; + padding-top: 30px; + min-height: 70px; + border-top: red solid 3px; + border-bottom: red solid 3px; +} +header a { + color: white; + text-transform: uppercase; + text-decoration: none; + font-size: 16px; +} +header ul { + padding: 0; + margin: 0; +} +header li { + float: left; + display: inline; + padding: 0 20px 0 20px; +} +header #branding { +float:left; +} +#branding h1 { + margin: 0; +} +nav { + float: right; + margin: 10px; +} +header .highlight, header .current a { + color: red; + font-weight: bold; +} +header a:hover { + color: gray; + font-weight: bold; +} +.main{ + text-align: center; +} +footer{ + padding:20px; + margin-top:20px; + color:#ffffff; + background-color:#e8491d; + text-align: center; + } + \ No newline at end of file