+
+
+
+
+
\ No newline at end of file
diff --git a/jquery_exercise/script.js b/jquery_exercise/script.js
new file mode 100644
index 00000000..0eee8a7b
--- /dev/null
+++ b/jquery_exercise/script.js
@@ -0,0 +1,55 @@
+$(document).ready(function(){
+ var $submitLink = $(".submit");
+ var $submitForm = $(".submit-form");
+ var $submitBtn = $(".submit-button");
+ var $linkItemsOl = $(".link-items");
+ var star = "";
+ var $title = $("#title");
+ var $url = $("#url");
+ var $favSpan = $(".favorites");
+
+ $submitLink.on("click", function(){
+ $submitForm.toggle();
+ });
+
+ $("body").on("click", ".glyphicon", function(e){
+ $(e.target).toggleClass("glyphicon-star-empty glyphicon-star");
+ });
+
+ $submitBtn.on("click", function(e){
+ e.preventDefault();
+ var title = $("#title").val();
+ var url = $("#url").val();
+ var $newItem = $("
");
+ var aTag = ` ${title}`;
+ $newItem.html(star + " " + aTag);
+ $linkItemsOl.append($newItem);
+ console.log(aTag);
+ $title.val("");
+ $url.val("https://");
+ });
+
+ $favSpan.on("click", function(e){
+ var stars = $(".glyphicon");
+ if ($favSpan.hasClass("favorites")) {
+ for (let i = 0; i < stars.length; i++) {
+ console.log(stars[i]);
+ if ($(stars[i]).hasClass("glyphicon-star-empty")) {
+ $(stars[i]).parent().hide();
+ }
+ }
+ $favSpan.text("all");
+ }
+ else if ($favSpan.hasClass("all")) {
+ for (let i = 0; i < stars.length; i++) {
+ console.log(stars[i]);
+ if ($(stars[i]).hasClass("glyphicon-star-empty")) {
+ $(stars[i]).parent().show();
+ }
+ }
+ $favSpan.text("favorites");
+ }
+ $favSpan.toggleClass("favorites all");
+ });
+
+});
\ No newline at end of file
diff --git a/jquery_exercise/style.css b/jquery_exercise/style.css
new file mode 100644
index 00000000..ff6065ee
--- /dev/null
+++ b/jquery_exercise/style.css
@@ -0,0 +1,50 @@
+.title, .submit, .favorites {
+ height: 3em;
+ margin: 5px;
+}
+
+.submit:hover, .favorites:hover, .all:hover {
+ text-decoration: underline;
+ cursor: pointer;
+}
+
+.glyphicon:hover {
+ cursor: pointer;
+}
+
+.title {
+ font-size: 1.5em;
+ font-weight: bold;
+}
+
+.wrapper {
+ background-color: #f6f6ef;
+ width: 80%;
+ margin-top: 1em;
+ margin-left: auto;
+ margin-right: auto;
+ color: #828282;
+}
+
+
+.panel > .panel-heading, .custom-panel {
+ background-image: none;
+ background-color: rgb(255, 102, 0);
+ color: black;
+ border: 1px solid rgb(255, 102, 0);
+}
+
+.custom-form {
+ width: 30%;
+ margin-left: 5em;
+ margin-bottom: 2em;
+ display: none;
+}
+
+a, a:hover {
+ color: black;
+}
+
+.link-items {
+ margin-bottom: 50px;
+}
\ No newline at end of file
diff --git a/lodash_exercise/index.html b/lodash_exercise/index.html
index 01b829ff..8570e625 100644
--- a/lodash_exercise/index.html
+++ b/lodash_exercise/index.html
@@ -1,7 +1,6 @@
-
Document
diff --git a/lodash_exercise/lodash.js b/lodash_exercise/lodash.js
index 483d734a..6e2206b2 100644
--- a/lodash_exercise/lodash.js
+++ b/lodash_exercise/lodash.js
@@ -1,99 +1,314 @@
-function drop(){
-
+function drop(arr, num=1){
+ if (num === 1) {
+ return arr.slice(1);
+ }
+ return arr.slice(num);
}
-function fromPairs(){
-
+function fromPairs(arr){
+ // assuming arr is an array of arrays containing key value pairs
+ // e.g. [[key, value],[key, value],[key, value]]
+ if (arr.length === 0) {
+ return {};
+ } else {
+ var result = {};
+ for (var i = 0; i < arr.length; i++) {
+ result[arr[i][0]] = arr[i][1];
+ }
+ return result;
+ }
}
-function head(){
-
+function head(arr){
+ if (arr.length === 0) {
+ return undefined;
+ }
+ return arr[0];
}
-function take(){
-
+function take(arr, num=1){
+ return arr.slice(0, num);
}
-function takeRight(){
-
+function takeRight(arr, num=1){
+ if (num === 0) {
+ return []
+ }
+ return arr.slice(num*-1);
}
function union(){
-
-}
-
-function zipObject(){
-
+ // assuming arguments will be an "array" of arrays
+ var result = [];
+ for (var i = 0; i < arguments.length; i++) {
+ for (var j = 0; j < arguments[i].length; j++) {
+ if (result.indexOf(arguments[i][j]) === -1) {
+ result.push(arguments[i][j]);
+ }
+ }
+ }
+ return result;
}
-function includes(){
-
+function zipObject(keysArr, valuesArr){
+ var result = {};
+ for (var i = 0; i < keysArr.length; i++) {
+ result[keysArr[i]] = valuesArr[i];
+ }
+ return result;
}
-function sample(){
-
+function includes(collection, val, fromIndex=0){
+ // collection can be an array, string, or object
+ if (typeof collection === "object" && Array.isArray(collection) !== true) {
+ for (var key in collection) {
+ if (collection[key] === val) {
+ return true;
+ }
+ }
+ return false;
+ }
+ return collection.slice(fromIndex).indexOf(val) !== -1 ? true : false;
}
-function cloneDeep(){
-
+function sample(arr){
+ return arr[Math.floor(Math.random()*arr.length-1)];
}
-function sumBy(){
-
+function cloneDeep(collection){ // [1, 2, 3, [4, [5]]]
+ var result;
+ if (Array.isArray(collection)) {
+ result = [];
+ collection.forEach(function(val){
+ // we want to make all the references different
+ result.concat(cloneDeep(val));
+ });
+ } else {
+ result = {};
+ for (var key in collection) {
+ result[key] = collection[key];
+ }
+ }
+ return result;
}
-function inRange(){
-
+function sumBy(arrOfObj, iteratee){
+ if (typeof iteratee === "string") {
+ return arrOfObj.reduce(function(acc, obj){
+ acc += obj[iteratee];
+ return acc;
+ }, 0);
+ } else {
+ var sum = 0;
+ for (var i = 0; i < arrOfObj.length; i++) {
+ sum += iteratee(arrOfObj[i]);
+ }
+ return sum;
+ }
}
-function has(){
-
+function inRange(num, start=0, end){
+ // Checks if n is between start and up to, but not including, end.
+ // If end is not specified, it's set to start with start then set to 0.
+ // If start is greater than end the params are swapped to support negative ranges.
+ if (end === undefined) {
+ end = start;
+ start = 0;
+ }
+ if (start > end) {
+ var hold = start;
+ start = end;
+ end = hold;
+ }
+ return (num > start && num < end);
}
-function omit(){
-
+function has(obj, path) {
+ // returns true if obj.path exists
+ // returns false if obj.path is not valid
+
+ // if path is just a string, just look for immediate key
+ if (typeof path === "string") {
+ for (var key in obj) {
+ if (key === path) return true;
+ }
+ }
+
+ // if path is an array, find if first element is immediate key
+ // then do again if there's a deeper layer
+ if (Array.isArray(path)) {
+ // if path array only has one element
+ if (path.length === 1) {
+ for (var key in obj) {
+ if (key === path[0]) return true;
+ }
+ return false;
+ }
+ // if the path array contains more than one element
+ for (var key in obj) {
+ if (key === path[0]) return has(obj[path[0]], path.slice(1));
+ }
+ }
+}
+
+function omit(obj, arrKeysToOmit){
+ var result = {};
+ for (var key in obj) {
+ if (arrKeysToOmit.indexOf(key) === -1) {
+ result[key] = obj[key];
+ }
+ }
+ return result;
}
-function pick(){
-
+function pick(obj, arrKeysToPick){
+ var result = {};
+ for (var key in obj) {
+ if (arrKeysToPick.indexOf(key) !== -1) {
+ result[key] = obj[key];
+ }
+ }
+ return result;
}
-function pickBy(){
-
+function pickBy(obj, callback){
+ var result = {};
+ for (var key in obj) {
+ if (callback(obj[key])) {
+ result[key] = obj[key];
+ }
+ }
+ return result;
}
-function omitBy(){
-
+function omitBy(obj, callback){
+ var result = {};
+ for (var key in obj) {
+ if (!callback(obj[key])) {
+ result[key] = obj[key];
+ }
+ }
+ return result;
}
-function padEnd(){
-
+function padEnd(str, finalLength, chars=" "){
+ var result = str.slice();
+ // if the desired length is less than or equal to the original string's length
+ // there is nothing to pad to the end, so return it.
+ // or if we pass in an empty string to pad to the end
+ if (str.length >= finalLength || chars.length === 0) {
+ return result;
+ }
+ var times = Math.floor((finalLength-str.length)/chars.length);
+ var remainder = (finalLength-str.length)%chars.length;
+ for (let i = 0; i < times; i++) {
+ // so I learned today that .concat() doesn't modify the original string
+ // and that you need to reassign it to capture the returned new string
+ // so I'm just going to use += from now on...
+ result += chars;
+ }
+ for (let j = 0; j < remainder; j++) {
+ result += chars[j];
+ }
+ return result;
}
-function repeat(){
+function repeat(str, times){
+ if (times === 0) return "";
+ if (times === 1) return str;
+ var result = "";
+ for (var i = 0; i < times; i++) {
+ result = result.concat(str);
+ }
+ return result;
}
function upperFirst(str){
-
+ var result = "";
+ return result.concat(str[0].toUpperCase() + str.slice(1));
}
-function flatten(){
-
+function flatten(arr){
+ var result = [];
+ for (var i = 0; i < arr.length; i++) {
+ result = result.concat(arr[i]);
+ }
+ return result;
}
-function zip(){
+// BONUS
+// passes in X number of arrays
+// first array containing first elements, 2nd containing 2nd, etc.
+// returns X number of arrays with those elements as listed
+// e.g. [a,b,c], [1,2,3], [x,y,z] ==> [[a,1,x], [b,2,y], [c,3,z]]
+function zip(){
+ var result = [];
+ for (let n = 0; n < arguments[0].length; n++) {
+ result.push([]);
+ }
+ // there should be N nested arrays for N elements in each array passed in
+ // e.g. if first array has 10 elements, resulting number of nested arrays is 10
+
+ // loop through the arguments (they are all arrays)
+ // grab first/i element of each one, add to a new array
+ // add that new array to the result
+ for (let i = 0; i < arguments[0].length; i++) {
+ for (let j = 0; j < arguments.length; j++) {
+ result[i].push(arguments[j][i]);
+ }
+ }
+ return result;
+} // note that this will only work if the longest array in the arguments is the 1st one passed in
+// otherwise we would have to first find the longest array from the arguments
+
+
+function unzip(){ // unzip takes in a result in the format of what's returned from zip
+ // e.g. [['a', 1, true], ['b', 2, false]], which has a length of 1
+ var result = [];
+ // there should be N nested arrays for N elements in each arg
+ for (let n = 0; n < arguments[0][0].length; n++) {
+ result.push([]);
+ }
+
+ // loop through the arguments (they are all arrays)
+ // grab first/i element of each one, add to a new array
+ // add that new array to the result
+ for (let i = 0; i < result.length; i++) {
+ for (let j = 0; j < arguments[0].length; j++) {
+ result[i].push(arguments[0][j][i]);
+ }
+ }
+ return result;
}
-function unzip(){
-
+function flip(callback){
+ // callback(arguments) ==> run stuff in callback on arguments.reverse
+ return function() {
+ // grab arguments and reverse them
+ var args = [];
+ for (var i = 0; i < arguments.length; i++) {
+ args.push(arguments[i]);
+ }
+ args.reverse();
+ // spread out arguments so they're not in an array anymore and run through callback
+ return callback(...args);
+ }
}
-function flip(){
-
+function flattenDeep(arr){
+ var result = [];
+ for (var i = 0; i < arr.length; i++) {
+ if (Array.isArray(arr[i])) {
+ // if the current element is an array,
+ // we need to go down a layer to flatten that as well
+ // and then remember to add it to the result and reassign since concat doesn't modify original arr
+ result = result.concat(flattenDeep(arr[i]));
+ } else {
+ result.push(arr[i]);
+ }
+ }
+ return result;
}
-function flattenDeep(){
-
-}
diff --git a/lodash_exercise/lodashSpec.js b/lodash_exercise/lodashSpec.js
index f0e90e9c..fcd548c8 100644
--- a/lodash_exercise/lodashSpec.js
+++ b/lodash_exercise/lodashSpec.js
@@ -161,6 +161,9 @@ describe("#has", function(){
it("should handle an array of keys as a parameter as well", function(){
expect(has(object, ['a', 'b'])).to.equal(true)
});
+ it("should return true if path is valid even with nested objects and >1 keys", function(){
+ expect(has({'x': {}, 'a': {'b':3, 'c':4}, 'b': 3}, ['a','c'])).to.equal(true)
+ });
});
diff --git a/prototypes_exercise/prototypes.js b/prototypes_exercise/prototypes.js
index e69de29b..10cf59bb 100644
--- a/prototypes_exercise/prototypes.js
+++ b/prototypes_exercise/prototypes.js
@@ -0,0 +1,53 @@
+// PART 1
+
+function Person(firstName, lastName, favoriteColor, favoriteNumber, favoriteFoods=[]) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.favoriteColor = favoriteColor;
+ this.favoriteNumber = favoriteNumber;
+ this.favoriteFoods = favoriteFoods;
+ this.family = [];
+}
+
+Person.prototype.fullName = function() {
+ return `${this.firstName} ${this.lastName}`;
+}
+
+Person.prototype.toString = function() {
+ return `${this.firstName} ${this.lastName}, Favorite Color: ${this.favoriteColor}, Favorite Number: ${this.favoriteNumber}`;
+}
+
+Person.prototype.addToFamily = function(personObj) {
+ // check if personObj is actually a Person object & if there is a duplicate
+ if (personObj instanceof Person && this.family.indexOf(personObj) === -1) {
+ this.family.push(personObj);
+ }
+ return this.family.length;
+}
+
+// PART 2
+
+Array.prototype.map = function(fn) {
+ var result = [];
+ for (let i = 0; i < this.length; i++) {
+ result.push(fn(this[i], i, this));
+ }
+ return result;
+}
+
+String.prototype.reverse = function() {
+ var result = [];
+ let temp = this.split("");
+ for (let i = temp.length-1; i >= 0; i--) {
+ result.push(temp[i]);
+ }
+ return result.join("");
+}
+
+Function.prototype.bind = function(thisArg, ...outerArgs) { // anon func takes thisArg to reset the this, and other arguments if needed
+ var _this = this; // refers to the function that bind was called on
+ // _this takes whatever arguments that it usually would
+ return function(...innerArgs) {
+ return _this.apply(thisArg, outerArgs.concat(innerArgs));
+ }
+}
\ No newline at end of file
diff --git a/recursion_exercise/recursion.js b/recursion_exercise/recursion.js
index e69de29b..2be46951 100644
--- a/recursion_exercise/recursion.js
+++ b/recursion_exercise/recursion.js
@@ -0,0 +1,89 @@
+function productOfArray(arr) {
+ if (arr.length === 1) {
+ return arr[0];
+ }
+ return arr[0] * productOfArray(arr.slice(1));
+}
+
+function collectStrings(obj) {
+ var strings = [];
+ function collectStringsHelper(obj) {
+ for (var key in obj) {
+ if (typeof(obj[key]) === "string") {
+ strings.push(obj[key]);
+ } else {
+ collectStringsHelper(obj[key]);
+ }
+ }
+ }
+ collectStringsHelper(obj);
+ return strings;
+}
+
+function contains(nestedObj, searchTerm) {
+ for (var key in nestedObj) {
+ if (typeof(nestedObj[key]) === "object") {
+ if (contains(nestedObj[key], searchTerm)) {
+ return true;
+ };
+ } else if (nestedObj[key] === searchTerm) {
+ return true;
+ }
+ }
+ return false;
+}
+
+function search(arr, val, currentIndex=0) {
+ if (arr[0] === val) {
+ return currentIndex;
+ }
+ // if an empty array is passed in, value is not found
+ else if (arr.length === 0) {
+ return -1;
+ }
+ // otherwise, increment the index to keep track of it, and then remove the
+ // value that was already checked, and pass in a shorter array to search()
+ else {
+ currentIndex++;
+ currentIndex = search(arr.slice(1), val, currentIndex);
+ }
+ return currentIndex;
+}
+
+function binarySearch(arr, val) {
+ // sort the array, or assume sorted
+ // find the middle, compare
+ // need some value to store current index of the original array
+ var pivot = Math.floor(arr.length/2);
+ if (arr[pivot] === val) {
+ return pivot;
+ }
+ if (arr[pivot] > val) {
+ return binarySearch(arr.slice(0, pivot), val);
+ }
+ if (arr[pivot] < val) {
+ return binarySearch(arr.slice(pivot), val);
+ }
+ return -1;
+ // remove the middle and everything before or after it,
+ // depending on the comparison
+ // repeat
+}
+
+function stringifyNumbers(obj, newObj={}) {
+// Write a function called `stringifyNumbers` which takes in an object and
+// finds all of the values which are numbers and converts them to strings.
+// Return new obj with all numbers as strings
+ for (var key in obj) {
+ if (typeof obj[key] === "number") {
+ newObj[key] = obj[key].toString();
+ }
+ else if (typeof obj[key] === "object" && Array.isArray(obj[key]) === false) {
+ newObj[key] = stringifyNumbers(obj[key]);
+ }
+ else {
+ newObj[key] = obj[key];
+ }
+ }
+ return newObj;
+}
\ No newline at end of file
diff --git a/recursion_exercise/recursionSpec.js b/recursion_exercise/recursionSpec.js
index 5bc841fe..2306ee0a 100644
--- a/recursion_exercise/recursionSpec.js
+++ b/recursion_exercise/recursionSpec.js
@@ -78,8 +78,8 @@ describe("#search", function(){
expect(search([1,2,3,4,5,6,7],6)).to.equal(5)
});
it("should return -1 if the value is not found", function(){
- expect(search([1,2,3,4]),0).to.equal(-1)
- expect(search([1,2]),11).to.equal(-1)
+ expect(search([1,2,3,4],0)).to.equal(-1)
+ expect(search([1,2],11)).to.equal(-1)
});
});
diff --git a/testing_exercise/testing.js b/testing_exercise/testing.js
index e69de29b..3a93df66 100644
--- a/testing_exercise/testing.js
+++ b/testing_exercise/testing.js
@@ -0,0 +1,48 @@
+function replaceWith(str, replaceThisChar, replacementChar) {
+ // var arrayOfChars = str.split("");
+ // arrayOfChars.forEach(function(val, index){
+ // if (val === replaceThisChar) {
+ // arrayOfChars[index] = replacementChar;
+ // }
+ // });
+ // return arrayOfChars.join("");
+ return str.split("").map(function(val, index, array){
+ if (val === replaceThisChar) return replacementChar;
+ return val;
+ }).join("");
+}
+
+function expand(arr, num) {
+ var result = arr;
+ for (var i = 1; i < num; i++) {
+ result = result.concat(arr);
+ }
+ return result;
+}
+
+function acceptNumbersOnly() {
+ for (var i = 0; i < arguments.length; i++) {
+ if (typeof(arguments[i]) !== "number" || isNaN(arguments[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+function mergeArrays(arr1, arr2) {
+ var mergedArr = arr1.concat(arr2);
+ return mergedArr.sort(function(a, b){
+ return a - b;
+ });
+}
+
+function mergeObjects(obj1, obj2) {
+ var result = {};
+ for (var key in obj1) {
+ result[key] = obj1[key];
+ }
+ for (var key in obj2) {
+ result[key] = obj2[key];
+ }
+ return result;
+}
\ No newline at end of file
diff --git a/testing_exercise/testingSpec.js b/testing_exercise/testingSpec.js
index aef56b1d..0d9cbecc 100644
--- a/testing_exercise/testingSpec.js
+++ b/testing_exercise/testingSpec.js
@@ -1,3 +1,71 @@
var expect = chai.expect;
-// WRITE YOUR TESTS HERE!
\ No newline at end of file
+describe("replaceWith", function(){
+ it("returns a string", function(){
+ expect(replaceWith("test", "t", "x")).to.be.a("string");
+ });
+ it("removes the designated character", function(){
+ expect(replaceWith("test", "t", "x")).to.not.have.string("t");
+ });
+ it("inserts the designated character", function(){
+ expect(replaceWith("test", "t", "x")).to.have.string("x");
+ });
+ it("replaces specific char with designated char", function() {
+ expect(replaceWith("awesome", "e", "z")).to.deep.equal("awzsomz");
+ expect(replaceWith("Foo", "F", "B")).to.deep.equal("Boo");
+ });
+ it("is case sensitive", function(){
+ expect(replaceWith("aBcBbBbBb", "B", "c")).to.deep.equal("acccbcbcb");
+ });
+});
+
+describe("expand", function(){
+ it("returns an array", function(){
+ expect(expand([1,2,3],3)).to.be.an("array");
+ });
+ it("should return an array that contains the original array a number of times", function(){
+ expect(expand([1,2,3],3)).to.include.members([1,2,3]);
+ expect(expand([1,2,3],3)).to.deep.equal([1,2,3,1,2,3,1,2,3]);
+ });
+});
+
+describe("acceptNumbersOnly", function(){
+ it("returns a boolean", function(){
+ expect(acceptNumbersOnly(1,2,3,4,5,6,7)).to.equal(true);
+ expect(acceptNumbersOnly(1,2,3,4,5,6,"hi")).to.equal(false);
+ });
+ it("returns true if all items in array are numbers", function(){
+ expect(acceptNumbersOnly(1,2,3,4,5,6,7)).to.be.true;
+ expect(acceptNumbersOnly(100,200,300,400)).to.be.true;
+ });
+ it("returns false if not all items numbers", function(){
+ expect(acceptNumbersOnly(1, "foo")).to.be.false;
+ });
+ it("returns false if NaN is present", function(){
+ expect(acceptNumbersOnly(1,2,3,4,5,6,NaN)).to.be.false;
+ });
+});
+
+describe("mergeArrays", function(){
+ it("returns an array", function(){
+ expect(mergeArrays([2,1],[3,4])).to.be.an("array");
+ });
+ it("returns the array sorted", function(){
+ expect(mergeArrays([2,1],[3,4])).to.deep.equal([1,2,3,4]);
+ });
+});
+
+describe("mergeObjects", function(){
+ it("should return an object", function(){
+ expect(mergeObjects({hello:1, bye:2}, {hello2:3, bye2:4})).to.be.an("object");
+ });
+ it("should override value in first passed in obj if both objs have the same key", function(){
+ expect(mergeObjects({hello:1, bye:2}, {hello:3, bye:4})).to.deep.equal({hello:3, bye:4});
+ });
+ it("should return an object with all the keys from both objs", function(){
+ expect(mergeObjects({hello:1, bye:2}, {hello2:3, bye2:4})).to.have.all.keys("hello", "bye", "hello2", "bye2");
+ });
+ it("should not change the key-value pairs", function(){
+ expect(mergeObjects({hello:1, bye:2}, {hello2:3, bye2:4})).to.deep.equal({hello:1, bye:2, hello2:3, bye2:4});
+ });
+});
\ No newline at end of file