diff --git a/AlgoCasts b/AlgoCasts
deleted file mode 160000
index 7d6ff43..0000000
--- a/AlgoCasts
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 7d6ff439f752c868a341ad0b8360084a88540549
diff --git a/AlgoCasts_3 b/AlgoCasts_3
deleted file mode 160000
index feeab87..0000000
--- a/AlgoCasts_3
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit feeab87936c294d647721184753b164bbf9f46d6
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/.gitignore b/Grider-Stephen-AlgoCasts-JS-Practice/.gitignore
new file mode 100644
index 0000000..e43b0f9
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/.gitignore
@@ -0,0 +1 @@
+.DS_Store
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/anagrams/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/anagrams/index.js
new file mode 100644
index 0000000..1a1b598
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/anagrams/index.js
@@ -0,0 +1,51 @@
+// --- Directions
+// Check to see if two provided strings are anagrams of eachother.
+// One string is an anagram of another if it uses the same characters
+// in the same quantity. Only consider characters, not spaces
+// or punctuation. Consider capital letters to be the same as lower case
+// --- Examples
+// anagrams('rail safety', 'fairy tales') --> True
+// anagrams('RAIL! SAFETY!', 'fairy tales') --> True
+// anagrams('Hi there', 'Bye there') --> False
+
+function anagrams(stringA, stringB) {
+ return cleanString(stringA) === cleanString(stringB);
+}
+
+function cleanString(str) {
+ return str
+ .replace(/[^\w]/g, '')
+ .toLowerCase()
+ .split('')
+ .sort()
+ .join('');
+}
+
+module.exports = anagrams;
+
+// function anagrams(stringA, stringB) {
+// const aCharMap = buildCharMap(stringA);
+// const bCharMap = buildCharMap(stringB);
+//
+// if (Object.keys(aCharMap).length !== Object.keys(bCharMap).length) {
+// return false;
+// }
+//
+// for (let char in aCharMap) {
+// if (aCharMap[char] !== bCharMap[char]) {
+// return false;
+// }
+// }
+//
+// return true;
+// }
+//
+// function buildCharMap(str) {
+// const charMap = {};
+//
+// for (let char of str.replace(/[^\w]/g, '').toLowerCase()) {
+// charMap[char] = charMap[char] + 1 || 1;
+// }
+//
+// return charMap;
+// }
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/anagrams/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/anagrams/test.js
new file mode 100644
index 0000000..60f117b
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/anagrams/test.js
@@ -0,0 +1,27 @@
+const anagrams = require('./index.js');
+
+test('anagrams function exists', () => {
+ expect(typeof anagrams).toEqual('function');
+});
+
+test('"hello" is an anagram of "llohe"', () => {
+ expect(anagrams('hello', 'llohe')).toBeTruthy();
+});
+
+test('"Whoa! Hi!" is an anagram of "Hi! Whoa!"', () => {
+ expect(anagrams('Whoa! Hi!', 'Hi! Whoa!')).toBeTruthy();
+});
+
+test('"One One" is not an anagram of "Two two two"', () => {
+ expect(anagrams('One One', 'Two two two')).toBeFalsy();
+});
+
+test('"One one" is not an anagram of "One one c"', () => {
+ expect(anagrams('One one', 'One one c')).toBeFalsy();
+});
+
+test('"A tree, a life, a bench" is not an anagram of "A tree, a fence, a yard"', () => {
+ expect(
+ anagrams('A tree, a life, a bench', 'A tree, a fence, a yard')
+ ).toBeFalsy();
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/bst/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/bst/index.js
new file mode 100644
index 0000000..673fd7d
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/bst/index.js
@@ -0,0 +1,49 @@
+// --- Directions
+// 1) Implement the Node class to create
+// a binary search tree. The constructor
+// should initialize values 'data', 'left',
+// and 'right'.
+// 2) Implement the 'insert' method for the
+// Node class. Insert should accept an argument
+// 'data', then create an insert a new node
+// at the appropriate location in the tree.
+// 3) Implement the 'contains' method for the Node
+// class. Contains should accept a 'data' argument
+// and return the Node in the tree with the same value.
+// If the value isn't in the tree return null.
+
+class Node {
+ constructor(data) {
+ this.data = data;
+ this.left = null;
+ this.right = null;
+ }
+
+ insert(data) {
+ if (data < this.data && this.left) {
+ this.left.insert(data);
+ } else if (data < this.data) {
+ this.left = new Node(data);
+ } else if (data > this.data && this.right) {
+ this.right.insert(data);
+ } else if (data > this.data) {
+ this.right = new Node(data);
+ }
+ }
+
+ contains(data) {
+ if (this.data === data) {
+ return this;
+ }
+
+ if (this.data < data && this.right) {
+ return this.right.contains(data);
+ } else if (this.data > data && this.left) {
+ return this.left.contains(data);
+ }
+
+ return null;
+ }
+}
+
+module.exports = Node;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/bst/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/bst/test.js
new file mode 100644
index 0000000..331ae22
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/bst/test.js
@@ -0,0 +1,41 @@
+const Node = require('./index');
+
+test('Node is a constructor', () => {
+ expect(typeof Node.prototype.constructor).toEqual('function');
+});
+
+test('Node can insert correctly', () => {
+ const node = new Node(10);
+ node.insert(5);
+ node.insert(15);
+ node.insert(17);
+
+ expect(node.left.data).toEqual(5);
+ expect(node.right.data).toEqual(15);
+ expect(node.right.right.data).toEqual(17);
+});
+
+test('Contains returns node with the same data', () => {
+ const node = new Node(10);
+ node.insert(5);
+ node.insert(15);
+ node.insert(20);
+ node.insert(0);
+ node.insert(-5);
+ node.insert(3);
+
+ const three = node.left.left.right;
+ expect(node.contains(3)).toEqual(three);
+});
+
+test('Contains returns null if value not found', () => {
+ const node = new Node(10);
+ node.insert(5);
+ node.insert(15);
+ node.insert(20);
+ node.insert(0);
+ node.insert(-5);
+ node.insert(3);
+
+ expect(node.contains(9999)).toEqual(null);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/capitalize/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/capitalize/index.js
new file mode 100644
index 0000000..353993f
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/capitalize/index.js
@@ -0,0 +1,34 @@
+// --- Directions
+// Write a function that accepts a string. The function should
+// capitalize the first letter of each word in the string then
+// return the capitalized string.
+// --- Examples
+// capitalize('a short sentence') --> 'A Short Sentence'
+// capitalize('a lazy fox') --> 'A Lazy Fox'
+// capitalize('look, it is working!') --> 'Look, It Is Working!'
+
+function capitalize(str) {
+ let result = str[0].toUpperCase();
+
+ for (let i = 1; i < str.length; i++) {
+ if (str[i - 1] === ' ') {
+ result += str[i].toUpperCase();
+ } else {
+ result += str[i];
+ }
+ }
+
+ return result;
+}
+
+module.exports = capitalize;
+
+// function capitalize(str) {
+// const words = [];
+//
+// for (let word of str.split(' ')) {
+// words.push(word[0].toUpperCase() + word.slice(1));
+// }
+//
+// return words.join(' ');
+// }
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/capitalize/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/capitalize/test.js
new file mode 100644
index 0000000..21a2423
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/capitalize/test.js
@@ -0,0 +1,17 @@
+const capitalize = require('./index');
+
+test('Capitalize is a function', () => {
+ expect(typeof capitalize).toEqual('function');
+});
+
+test('capitalizes the first letter of every word in a sentence', () => {
+ expect(capitalize('hi there, how is it going?')).toEqual(
+ 'Hi There, How Is It Going?'
+ );
+});
+
+test('capitalizes the first letter', () => {
+ expect(capitalize('i love breakfast at bill miller bbq')).toEqual(
+ 'I Love Breakfast At Bill Miller Bbq'
+ );
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/chunk/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/chunk/index.js
new file mode 100644
index 0000000..02c9bbb
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/chunk/index.js
@@ -0,0 +1,39 @@
+// --- Directions
+// Given an array and chunk size, divide the array into many subarrays
+// where each subarray is of length size
+// --- Examples
+// chunk([1, 2, 3, 4], 2) --> [[ 1, 2], [3, 4]]
+// chunk([1, 2, 3, 4, 5], 2) --> [[ 1, 2], [3, 4], [5]]
+// chunk([1, 2, 3, 4, 5, 6, 7, 8], 3) --> [[ 1, 2, 3], [4, 5, 6], [7, 8]]
+// chunk([1, 2, 3, 4, 5], 4) --> [[ 1, 2, 3, 4], [5]]
+// chunk([1, 2, 3, 4, 5], 10) --> [[ 1, 2, 3, 4, 5]]
+
+function chunk(array, size) {
+ const chunked = [];
+ let index = 0;
+
+ while (index < array.length) {
+ chunked.push(array.slice(index, index + size));
+ index += size;
+ }
+
+ return chunked;
+}
+
+module.exports = chunk;
+
+// function chunk(array, size) {
+// const chunked = [];
+//
+// for (let element of array) {
+// const last = chunked[chunked.length - 1];
+//
+// if (!last || last.length === size) {
+// chunked.push([element]);
+// } else {
+// last.push(element);
+// }
+// }
+//
+// return chunked;
+// }
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/chunk/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/chunk/test.js
new file mode 100644
index 0000000..ef3d645
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/chunk/test.js
@@ -0,0 +1,33 @@
+const chunk = require('./index');
+
+test('function chunk exists', () => {
+ expect(typeof chunk).toEqual('function');
+});
+
+test('chunk divides an array of 10 elements with chunk size 2', () => {
+ const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ const chunked = chunk(arr, 2);
+
+ expect(chunked).toEqual([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]);
+});
+
+test('chunk divides an array of 3 elements with chunk size 1', () => {
+ const arr = [1, 2, 3];
+ const chunked = chunk(arr, 1);
+
+ expect(chunked).toEqual([[1], [2], [3]]);
+});
+
+test('chunk divides an array of 5 elements with chunk size 3', () => {
+ const arr = [1, 2, 3, 4, 5];
+ const chunked = chunk(arr, 3);
+
+ expect(chunked).toEqual([[1, 2, 3], [4, 5]]);
+});
+
+test('chunk divides an array of 13 elements with chunk size 5', () => {
+ const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
+ const chunked = chunk(arr, 5);
+
+ expect(chunked).toEqual([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13]]);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/circular/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/circular/index.js
new file mode 100644
index 0000000..508b09f
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/circular/index.js
@@ -0,0 +1,31 @@
+// --- Directions
+// Given a linked list, return true if the list
+// is circular, false if it is not.
+// --- Examples
+// const l = new List();
+// const a = new Node('a');
+// const b = new Node('b');
+// const c = new Node('c');
+// l.head = a;
+// a.next = b;
+// b.next = c;
+// c.next = b;
+// circular(l) // true
+
+function circular(list) {
+ let slow = list.getFirst();
+ let fast = list.getFirst();
+
+ while (fast.next && fast.next.next) {
+ slow = slow.next;
+ fast = fast.next.next;
+
+ if (slow === fast) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+module.exports = circular;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/circular/linkedlist.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/circular/linkedlist.js
new file mode 100644
index 0000000..b7da56b
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/circular/linkedlist.js
@@ -0,0 +1,178 @@
+class Node {
+ constructor(data, next = null) {
+ this.data = data;
+ this.next = next;
+ }
+}
+
+class LinkedList {
+ constructor(values = []) {
+ this.head = null;
+
+ for (let value of values) {
+ this.insertLast(value);
+ }
+ }
+
+ clear() {
+ this.head = null;
+ }
+
+ size() {
+ let counter = 0;
+ let node = this.head;
+
+ while (node) {
+ counter++;
+ node = node.next;
+ }
+
+ return counter;
+ }
+
+ getAt(index) {
+ if (!this.head) {
+ return null;
+ }
+
+ let counter = 0;
+ let node = this.head;
+ while (node) {
+ if (counter === index) {
+ return node;
+ }
+ node = node.next;
+ counter++;
+ }
+ return null;
+ }
+
+ insertAt(data, index) {
+ if (!this.head) {
+ this.head = new Node(data);
+ return;
+ }
+
+ if (index === 0) {
+ this.head = new Node(data, this.head);
+ return;
+ }
+
+ let counter = 1;
+ let previous = this.head;
+ let node = this.head.next;
+ while (node) {
+ if (counter === index) {
+ previous.next = new Node(data, node);
+ return;
+ }
+ previous = node;
+ node = node.next;
+ counter++;
+ }
+
+ previous.next = new Node(data, node);
+ }
+
+ removeFirst() {
+ if (!this.head) {
+ return;
+ }
+
+ this.head = this.head.next;
+ }
+
+ removeLast() {
+ if (!this.head) {
+ return;
+ }
+
+ if (!this.head.next) {
+ this.head = null;
+ return;
+ }
+
+ let previous = this.head;
+ let node = this.head.next;
+ while (node.next) {
+ previous = node;
+ node = node.next;
+ }
+ previous.next = null;
+ }
+
+ removeAt(index) {
+ if (!this.head) {
+ return;
+ }
+
+ let counter = 0;
+ let node = this.head;
+ while (node) {
+ if (counter === index - 1) {
+ if (node.next) {
+ return (node.next = node.next.next);
+ } else {
+ return (node.next = null);
+ }
+ }
+ node = node.next;
+ counter++;
+ }
+ }
+
+ getFirst() {
+ return this.head;
+ }
+
+ insertFirst(data) {
+ this.head = new Node(data, this.getFirst());
+ }
+
+ getLast() {
+ if (!this.head) {
+ return null;
+ }
+
+ let node = this.head;
+ while (node.next) {
+ node = node.next;
+ }
+
+ return node;
+ }
+
+ insertLast(data) {
+ const last = this.getLast();
+
+ if (last) {
+ last.next = new Node(data);
+ return last.next;
+ } else {
+ this.head = new Node(data);
+ return this.head;
+ }
+ }
+
+ forEach(fn) {
+ if (!this.head) {
+ return null;
+ }
+
+ let node = this.head;
+ while (node) {
+ fn(node);
+ node = node.next;
+ }
+ }
+
+ *[Symbol.iterator]() {
+ let node = this.head;
+ while (node) {
+ yield node;
+ node = node.next;
+ }
+ }
+}
+
+module.exports = { Node, LinkedList };
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/circular/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/circular/test.js
new file mode 100644
index 0000000..99c21fe
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/circular/test.js
@@ -0,0 +1,50 @@
+const circular = require('./index');
+const L = require('./linkedlist');
+const List = L.LinkedList;
+const Node = L.Node;
+
+test('circular function is defined', () => {
+ expect(typeof circular).toEqual('function');
+});
+
+test('circular detects circular linked lists', () => {
+ const l = new List();
+ const a = new Node('a');
+ const b = new Node('b');
+ const c = new Node('c');
+
+ l.head = a;
+ a.next = b;
+ b.next = c;
+ c.next = b;
+
+ expect(circular(l)).toEqual(true);
+});
+
+test('circular detects circular linked lists linked at the head', () => {
+ const l = new List();
+ const a = new Node('a');
+ const b = new Node('b');
+ const c = new Node('c');
+
+ l.head = a;
+ a.next = b;
+ b.next = c;
+ c.next = a;
+
+ expect(circular(l)).toEqual(true);
+});
+
+test('circular detects non-circular linked lists', () => {
+ const l = new List();
+ const a = new Node('a');
+ const b = new Node('b');
+ const c = new Node('c');
+
+ l.head = a;
+ a.next = b;
+ b.next = c;
+ c.next = null;
+
+ expect(circular(l)).toEqual(false);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/events/example.html b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/events/example.html
new file mode 100644
index 0000000..c1a8303
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/events/example.html
@@ -0,0 +1,19 @@
+
+
+
+
+
Click the button
+
+
+
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/events/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/events/index.js
new file mode 100644
index 0000000..ee5a600
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/events/index.js
@@ -0,0 +1,37 @@
+// --- Directions
+// Create an 'eventing' library out of the
+// Events class. The Events class should
+// have methods 'on', 'trigger', and 'off'.
+
+class Events {
+ constructor() {
+ this.events = {};
+ }
+
+ // Register an event handler
+ on(eventName, callback) {
+ if (this.events[eventName]) {
+ this.events[eventName].push(callback);
+ } else {
+ this.events[eventName] = [callback];
+ }
+ }
+
+ // Trigger all callbacks associated
+ // with a given eventName
+ trigger(eventName) {
+ if (this.events[eventName]) {
+ for (let cb of this.events[eventName]) {
+ cb();
+ }
+ }
+ }
+
+ // Remove all event handlers associated
+ // with the given eventName
+ off(eventName) {
+ delete this.events[eventName];
+ }
+}
+
+module.exports = Events;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/events/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/events/test.js
new file mode 100644
index 0000000..e015819
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/events/test.js
@@ -0,0 +1,77 @@
+const Events = require('./index');
+
+test('Events can be registered then triggered', () => {
+ const events = new Events();
+
+ const cb1 = jest.fn();
+
+ events.on('click', cb1);
+ events.trigger('click');
+
+ expect(cb1.mock.calls.length).toBe(1);
+});
+
+test('Multiple events can be registered then triggered', () => {
+ const events = new Events();
+
+ const cb1 = jest.fn();
+ const cb2 = jest.fn();
+
+ events.on('click', cb1);
+ events.on('click', cb2);
+ events.trigger('click');
+
+ expect(cb1.mock.calls.length).toBe(1);
+ expect(cb2.mock.calls.length).toBe(1);
+});
+
+test('Events can be triggered multiple times', () => {
+ const events = new Events();
+
+ const cb1 = jest.fn();
+ const cb2 = jest.fn();
+
+ events.on('click', cb1);
+ events.trigger('click');
+ events.on('click', cb2);
+ events.trigger('click');
+ events.trigger('click');
+
+ expect(cb1.mock.calls.length).toBe(3);
+ expect(cb2.mock.calls.length).toBe(2);
+});
+
+test('Events can have different names', () => {
+ const events = new Events();
+
+ const cb1 = jest.fn();
+ const cb2 = jest.fn();
+
+ events.on('click', cb1);
+ events.trigger('click');
+ events.on('hover', cb2);
+ events.trigger('click');
+ events.trigger('hover');
+
+ expect(cb1.mock.calls.length).toBe(2);
+ expect(cb2.mock.calls.length).toBe(1);
+});
+
+test('Events can be toggled off', () => {
+ const events = new Events();
+
+ const cb1 = jest.fn();
+ const cb2 = jest.fn();
+
+ events.on('hover', cb2);
+
+ events.on('click', cb1);
+ events.trigger('click');
+ events.off('click');
+ events.trigger('click');
+
+ events.trigger('hover');
+
+ expect(cb1.mock.calls.length).toBe(1);
+ expect(cb2.mock.calls.length).toBe(1);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/fib/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/fib/index.js
new file mode 100644
index 0000000..51e2ae1
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/fib/index.js
@@ -0,0 +1,48 @@
+// --- Directions
+// Print out the n-th entry in the fibonacci series.
+// The fibonacci series is an ordering of numbers where
+// each number is the sum of the preceeding two.
+// For example, the sequence
+// [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
+// forms the first ten entries of the fibonacci series.
+// Example:
+// fib(4) === 3
+
+function memoize(fn) {
+ const cache = {};
+ return function(...args) {
+ if (cache[args]) {
+ return cache[args];
+ }
+
+ const result = fn.apply(this, args);
+ cache[args] = result;
+
+ return result;
+ };
+}
+
+function slowFib(n) {
+ if (n < 2) {
+ return n;
+ }
+
+ return fib(n - 1) + fib(n - 2);
+}
+
+const fib = memoize(slowFib);
+
+module.exports = fib;
+
+// function fib(n) {
+// const result = [0, 1];
+//
+// for (let i = 2; i <= n; i++) {
+// const a = result[i - 1];
+// const b = result[i - 2];
+//
+// result.push(a + b);
+// }
+//
+// return result[n];
+// }
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/fib/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/fib/test.js
new file mode 100644
index 0000000..02a385d
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/fib/test.js
@@ -0,0 +1,25 @@
+const fib = require('./index');
+
+test('Fib function is defined', () => {
+ expect(typeof fib).toEqual('function');
+});
+
+test('calculates correct fib value for 1', () => {
+ expect(fib(1)).toEqual(1);
+});
+
+test('calculates correct fib value for 2', () => {
+ expect(fib(2)).toEqual(1);
+});
+
+test('calculates correct fib value for 3', () => {
+ expect(fib(3)).toEqual(2);
+});
+
+test('calculates correct fib value for 4', () => {
+ expect(fib(4)).toEqual(3);
+});
+
+test('calculates correct fib value for 15', () => {
+ expect(fib(39)).toEqual(63245986);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/fizzbuzz/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/fizzbuzz/index.js
new file mode 100644
index 0000000..8fe64c4
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/fizzbuzz/index.js
@@ -0,0 +1,31 @@
+// --- Directions
+// Write a program that console logs the numbers
+// from 1 to n. But for multiples of three print
+// “fizz” instead of the number and for the multiples
+// of five print “buzz”. For numbers which are multiples
+// of both three and five print “fizzbuzz”.
+// --- Example
+// fizzBuzz(5);
+// 1
+// 2
+// fizz
+// 4
+// buzz
+
+function fizzBuzz(n) {
+ for (let i = 1; i <= n; i++) {
+ // Is the number a multiple of 3 and 5?
+ if (i % 3 === 0 && i % 5 === 0) {
+ console.log('fizzbuzz');
+ } else if (i % 3 === 0) {
+ // Is the number a multiple of 3?
+ console.log('fizz');
+ } else if (i % 5 === 0) {
+ console.log('buzz');
+ } else {
+ console.log(i);
+ }
+ }
+}
+
+module.exports = fizzBuzz;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/fizzbuzz/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/fizzbuzz/test.js
new file mode 100644
index 0000000..fa5108e
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/fizzbuzz/test.js
@@ -0,0 +1,39 @@
+const fizzBuzz = require('./index');
+
+test('fizzBuzz function is defined', () => {
+ expect(fizzBuzz).toBeDefined();
+});
+
+test('Calling fizzbuzz with `5` prints out 5 statements', () => {
+ fizzBuzz(5);
+
+ expect(console.log.mock.calls.length).toEqual(5);
+});
+
+test('Calling fizzbuzz with 15 prints out the correct values', () => {
+ fizzBuzz(15);
+
+ expect(console.log.mock.calls[0][0]).toEqual(1);
+ expect(console.log.mock.calls[1][0]).toEqual(2);
+ expect(console.log.mock.calls[2][0]).toEqual('fizz');
+ expect(console.log.mock.calls[3][0]).toEqual(4);
+ expect(console.log.mock.calls[4][0]).toEqual('buzz');
+ expect(console.log.mock.calls[5][0]).toEqual('fizz');
+ expect(console.log.mock.calls[6][0]).toEqual(7);
+ expect(console.log.mock.calls[7][0]).toEqual(8);
+ expect(console.log.mock.calls[8][0]).toEqual('fizz');
+ expect(console.log.mock.calls[9][0]).toEqual('buzz');
+ expect(console.log.mock.calls[10][0]).toEqual(11);
+ expect(console.log.mock.calls[11][0]).toEqual('fizz');
+ expect(console.log.mock.calls[12][0]).toEqual(13);
+ expect(console.log.mock.calls[13][0]).toEqual(14);
+ expect(console.log.mock.calls[14][0]).toEqual('fizzbuzz');
+});
+
+beforeEach(() => {
+ jest.spyOn(console, 'log').mockImplementation(() => {});
+});
+
+afterEach(() => {
+ console.log.mockRestore();
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/fromlast/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/fromlast/index.js
new file mode 100644
index 0000000..935ca22
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/fromlast/index.js
@@ -0,0 +1,31 @@
+// --- Directions
+// Given a linked list and integer n, return the element n
+// spaces from the last node in the list. Do not call the
+// 'size' method of the linked list. Assume that n will always
+// be less than the length of the list.
+// --- Examples
+// const list = new List();
+// list.insertLast('a');
+// list.insertLast('b');
+// list.insertLast('c');
+// list.insertLast('d');
+// fromLast(list, 2).data // 'b'
+
+function fromLast(list, n) {
+ let slow = list.getFirst();
+ let fast = list.getFirst();
+
+ while (n > 0) {
+ fast = fast.next;
+ n--;
+ }
+
+ while (fast.next) {
+ slow = slow.next;
+ fast = fast.next;
+ }
+
+ return slow;
+}
+
+module.exports = fromLast;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/fromlast/linkedlist.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/fromlast/linkedlist.js
new file mode 100644
index 0000000..2029b3b
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/fromlast/linkedlist.js
@@ -0,0 +1,156 @@
+class Node {
+ constructor(data, next = null) {
+ this.data = data;
+ this.next = next;
+ }
+}
+
+class LinkedList {
+ constructor() {
+ this.head = null;
+ }
+
+ insertFirst(data) {
+ this.head = new Node(data, this.head);
+ }
+
+ size() {
+ let counter = 0;
+ let node = this.head;
+
+ while (node) {
+ counter++;
+ node = node.next;
+ }
+
+ return counter;
+ }
+
+ getFirst() {
+ return this.head;
+ }
+
+ getLast() {
+ if (!this.head) {
+ return null;
+ }
+
+ let node = this.head;
+ while (node) {
+ if (!node.next) {
+ return node;
+ }
+ node = node.next;
+ }
+ }
+
+ clear() {
+ this.head = null;
+ }
+
+ removeFirst() {
+ if (!this.head) {
+ return;
+ }
+
+ this.head = this.head.next;
+ }
+
+ removeLast() {
+ if (!this.head) {
+ return;
+ }
+
+ if (!this.head.next) {
+ this.head = null;
+ return;
+ }
+
+ let previous = this.head;
+ let node = this.head.next;
+ while (node.next) {
+ previous = node;
+ node = node.next;
+ }
+ previous.next = null;
+ }
+
+ insertLast(data) {
+ const last = this.getLast();
+
+ if (last) {
+ // There are some existing nodes in our chain
+ last.next = new Node(data);
+ } else {
+ // The chain is empty!
+ this.head = new Node(data);
+ }
+ }
+
+ getAt(index) {
+ let counter = 0;
+ let node = this.head;
+ while (node) {
+ if (counter === index) {
+ return node;
+ }
+
+ counter++;
+ node = node.next;
+ }
+ return null;
+ }
+
+ removeAt(index) {
+ if (!this.head) {
+ return;
+ }
+
+ if (index === 0) {
+ this.head = this.head.next;
+ return;
+ }
+
+ const previous = this.getAt(index - 1);
+ if (!previous || !previous.next) {
+ return;
+ }
+ previous.next = previous.next.next;
+ }
+
+ insertAt(data, index) {
+ if (!this.head) {
+ this.head = new Node(data);
+ return;
+ }
+
+ if (index === 0) {
+ this.head = new Node(data, this.head);
+ return;
+ }
+
+ const previous = this.getAt(index - 1) || this.getLast();
+ const node = new Node(data, previous.next);
+ previous.next = node;
+ }
+
+ forEach(fn) {
+ let node = this.head;
+ let counter = 0;
+ while (node) {
+ fn(node, counter);
+ node = node.next;
+ counter++;
+ }
+ }
+
+ *[Symbol.iterator]() {
+ let node = this.head;
+ while (node) {
+ yield node;
+ node = node.next;
+ }
+ }
+}
+
+module.exports = { Node, LinkedList };
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/fromlast/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/fromlast/test.js
new file mode 100644
index 0000000..e4684d5
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/fromlast/test.js
@@ -0,0 +1,20 @@
+const fromLast = require('./index');
+const L = require('./linkedlist');
+const List = L.LinkedList;
+const Node = L.Node;
+
+test('fromLast is a function', () => {
+ expect(typeof fromLast).toEqual('function');
+});
+
+test('fromLast returns the node n elements from the end', () => {
+ const l = new List();
+
+ l.insertLast('a');
+ l.insertLast('b');
+ l.insertLast('c');
+ l.insertLast('d');
+ l.insertLast('e');
+
+ expect(fromLast(l, 3).data).toEqual('b');
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/levelwidth/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/levelwidth/index.js
new file mode 100644
index 0000000..349c0c4
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/levelwidth/index.js
@@ -0,0 +1,33 @@
+// --- Directions
+// Given the root node of a tree, return
+// an array where each element is the width
+// of the tree at each level.
+// --- Example
+// Given:
+// 0
+// / | \
+// 1 2 3
+// | |
+// 4 5
+// Answer: [1, 3, 2]
+
+function levelWidth(root) {
+ const arr = [root, 's'];
+ const counters = [0];
+
+ while (arr.length > 1) {
+ const node = arr.shift();
+
+ if (node === 's') {
+ counters.push(0);
+ arr.push('s');
+ } else {
+ arr.push(...node.children);
+ counters[counters.length - 1]++;
+ }
+ }
+
+ return counters;
+}
+
+module.exports = levelWidth;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/levelwidth/node.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/levelwidth/node.js
new file mode 100644
index 0000000..5238e8f
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/levelwidth/node.js
@@ -0,0 +1,10 @@
+module.exports = class Node {
+ constructor(data) {
+ this.data = data;
+ this.children = [];
+ }
+
+ add(data) {
+ this.children.push(new Node(data));
+ }
+};
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/levelwidth/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/levelwidth/test.js
new file mode 100644
index 0000000..35d20c2
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/levelwidth/test.js
@@ -0,0 +1,27 @@
+const Node = require('./node');
+const levelWidth = require('./index');
+
+test('levelWidth is a function', () => {
+ expect(typeof levelWidth).toEqual('function');
+});
+
+test('levelWidth returns number of nodes at widest point', () => {
+ const root = new Node(0);
+ root.add(1);
+ root.add(2);
+ root.add(3);
+ root.children[0].add(4);
+ root.children[2].add(5);
+
+ expect(levelWidth(root)).toEqual([1, 3, 2]);
+});
+
+test('levelWidth returns number of nodes at widest point', () => {
+ const root = new Node(0);
+ root.add(1);
+ root.children[0].add(2);
+ root.children[0].add(3);
+ root.children[0].children[0].add(4);
+
+ expect(levelWidth(root)).toEqual([1, 1, 2, 1]);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/linkedlist/directions.html b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/linkedlist/directions.html
new file mode 100644
index 0000000..3bae946
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/linkedlist/directions.html
@@ -0,0 +1,378 @@
+
+
+
+
+
+
Node Class API
+
+
+
+
Function
+
Arguments
+
Returns
+
Directions
+
Example
+
+
+
+
+
constructor
+
(Data, Node)
+
Node
+
+ Creates a class instance to represent a node. The node should
+ have two properties, 'data' and 'next'. Accept both
+ of these as arguments to the 'Node' constructor, then
+ assign them to the instance as properties 'data' and 'next'.
+ If 'next' is not provided to the constructor, then default its
+ value to be 'null'.
+
+
+
+ const n = new Node('Hi');
+ n.data // 'Hi'
+ n.next // null
+ const n2 = new Node('There', n);
+ n.next // returns n
+
+
+
+
+
+
+
LinkedList Class API
+
+
+
+
Function
+
Arguments
+
Returns
+
Directions
+
Example
+
+
+
+
+
constructor
+
-
+
(LinkedList)
+
+ Create a class to represent a linked list. When created,
+ a linked list should have *no* head node associated with it.
+ The LinkedList instance will have one property, 'head', which
+ is a reference to the first node of the linked list. By default
+ 'head' should be 'null'.
+
+
+
+ const list = new LinkedList();
+ list.head // null
+
+
+
+
+
insertFirst
+
(data)
+
-
+
+ Creates a new Node from argument 'data' and assigns the resulting
+ node to the 'head' property. Make sure to handle the case in which
+ the linked list already has a node assigned to the 'head' property.
+
+
+
+ const list = new LinkedList();
+ list.insertFirst('Hi There'); // List has one node
+
+
+
+
+
size
+
-
+
(integer)
+
+ Returns the number of nodes in the linked list.
+
+
+
+ const list = new LinkedList();
+ list.insertFirst('a');
+ list.insertFirst('b');
+ list.insertFirst('c');
+ list.size(); // returns 3
+
+
+
+
+
getFirst
+
-
+
(Node)
+
+ Returns the first node of the linked list.
+
+
+
+ const list = new LinkedList();
+ list.insertFirst('a');
+ list.insertFirst('b');
+ list.getFirst(); // returns Node instance with data 'a'
+
+
+
+
+
+ getLast
+
+
+ -
+
+
+ (Node)
+
+
+ Returns the last node of the linked list
+
+
+
+ const list = new LinkedList();
+ list.insertFirst('a');
+ list.insertFirst('b');
+ list.getLast(); // returns node with data 'a'
+
+
+
+
+
+ clear
+
+
+ -
+
+
+ -
+
+
+ Empties the linked list of any nodes.
+
+
+
+ const list = new LinkedList();
+ list.insertFirst('a');
+ list.insertFirst('b');
+ list.clear();
+ list.size(); // returns 0
+
+
+
+
+
+ removeFirst
+
+
+ -
+
+
+ -
+
+
+ Removes only the first node of the linked list. The list's head should
+ now be the second element.
+
+
+
+ const list = new LinkedList();
+ list.insertFirst('a');
+ list.insertFirst('b');
+ list.removeFirst();
+ list.getFirst(); // returns node with data 'a'
+
+
+
+
+
+ removeLast
+
+
+ -
+
+
+ -
+
+
+ Removes the last node of the chain
+
+
+
+ const list = new LinkedList();
+ list.insertFirst('a');
+ list.insertFirst('b');
+ list.removeLast();
+ list.size(); // returns 1
+ list.getLast(); // returns node with data of 'b'
+
+
+
+
+
+ insertLast
+
+
+ (Data)
+
+
+ -
+
+
+ Inserts a new node with provided data at the end of the chain
+
+
+
+ const list = new LinkedList();
+ list.insertFirst('a');
+ list.insertFirst('b');
+ list.insertLast('c');
+ list.getLast(); // returns node with data 'C'
+
+
+
+
+
+ getAt
+
+
+ (integer)
+
+
+ (Node)
+
+
+ Returns the node at the provided index
+
+
+
+ const list = new List();
+ list.insertFirst('a');
+ list.insertFirst('b');
+ list.insertFirst('c');
+ list.getAt(1); // returns node with data 'b'
+
+
+
+
+
+ removeAt
+
+
+ (integer)
+
+
+ -
+
+
+ Removes node at the provided index
+
+
+
+ const list = new List();
+ list.insertFirst('a');
+ list.insertFirst('b');
+ list.insertFirst('c');
+ list.removeAt(1);
+ list.getAt(1); // returns node with data 'a'
+
+
+
+
+
+ insertAt
+
+
+ (Data, integer)
+
+
+ -
+
+
+ Create an insert a new node at provided index.
+ If index is out of bounds, add the node to the end
+ of the list.
+
+
+
+ const list = new List();
+ list.insertFirst('a');
+ list.insertFirst('b');
+ list.insertFirst('c');
+ list.insertAt('Hi', 1)
+ list.getAt(1); // returns node with data 'Hi'
+
+
+
+
+
+ forEach
+
+
+ (function)
+
+
+ -
+
+
+ Calls the provided function with every node of the chain and the index
+ of the node.
+
+
+
+ const list = new List();
+
+ list.insertLast(1);
+ list.insertLast(2);
+ list.insertLast(3);
+ list.insertLast(4);
+
+ list.forEach((node, index) => {
+ node.data += 10;
+ });
+ list.getAt(0); // Returns node with data '11'
+
+
+
+
+
+ for...of Loop
+
+
+ -
+
+
+ -
+
+
+ Linked list should be compatible as the subject of a 'for...of' loop
+
+
+
+ const list = new List();
+
+ list.insertLast(1);
+ list.insertLast(2);
+ list.insertLast(3);
+ list.insertLast(4);
+
+ for (let node of list) {
+ node.data += 10;
+ }
+
+ node.getAt(1); // returns node with data 11
+
+
+
+
+
+
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/linkedlist/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/linkedlist/index.js
new file mode 100644
index 0000000..5bd5efb
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/linkedlist/index.js
@@ -0,0 +1,160 @@
+// --- Directions
+// Implement classes Node and Linked Lists
+// See 'directions' document
+
+class Node {
+ constructor(data, next = null) {
+ this.data = data;
+ this.next = next;
+ }
+}
+
+class LinkedList {
+ constructor() {
+ this.head = null;
+ }
+
+ insertFirst(data) {
+ this.head = new Node(data, this.head);
+ }
+
+ size() {
+ let counter = 0;
+ let node = this.head;
+
+ while (node) {
+ counter++;
+ node = node.next;
+ }
+
+ return counter;
+ }
+
+ getFirst() {
+ return this.head;
+ }
+
+ getLast() {
+ if (!this.head) {
+ return null;
+ }
+
+ let node = this.head;
+ while (node) {
+ if (!node.next) {
+ return node;
+ }
+ node = node.next;
+ }
+ }
+
+ clear() {
+ this.head = null;
+ }
+
+ removeFirst() {
+ if (!this.head) {
+ return;
+ }
+
+ this.head = this.head.next;
+ }
+
+ removeLast() {
+ if (!this.head) {
+ return;
+ }
+
+ if (!this.head.next) {
+ this.head = null;
+ return;
+ }
+
+ let previous = this.head;
+ let node = this.head.next;
+ while (node.next) {
+ previous = node;
+ node = node.next;
+ }
+ previous.next = null;
+ }
+
+ insertLast(data) {
+ const last = this.getLast();
+
+ if (last) {
+ // There are some existing nodes in our chain
+ last.next = new Node(data);
+ } else {
+ // The chain is empty!
+ this.head = new Node(data);
+ }
+ }
+
+ getAt(index) {
+ let counter = 0;
+ let node = this.head;
+ while (node) {
+ if (counter === index) {
+ return node;
+ }
+
+ counter++;
+ node = node.next;
+ }
+ return null;
+ }
+
+ removeAt(index) {
+ if (!this.head) {
+ return;
+ }
+
+ if (index === 0) {
+ this.head = this.head.next;
+ return;
+ }
+
+ const previous = this.getAt(index - 1);
+ if (!previous || !previous.next) {
+ return;
+ }
+ previous.next = previous.next.next;
+ }
+
+ insertAt(data, index) {
+ if (!this.head) {
+ this.head = new Node(data);
+ return;
+ }
+
+ if (index === 0) {
+ this.head = new Node(data, this.head);
+ return;
+ }
+
+ const previous = this.getAt(index - 1) || this.getLast();
+ const node = new Node(data, previous.next);
+ previous.next = node;
+ }
+
+ forEach(fn) {
+ let node = this.head;
+ let counter = 0;
+ while (node) {
+ fn(node, counter);
+ node = node.next;
+ counter++;
+ }
+ }
+
+ *[Symbol.iterator]() {
+ let node = this.head;
+ while (node) {
+ yield node;
+ node = node.next;
+ }
+ }
+}
+
+module.exports = { Node, LinkedList };
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/linkedlist/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/linkedlist/test.js
new file mode 100644
index 0000000..f4de046
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/linkedlist/test.js
@@ -0,0 +1,321 @@
+const L = require('./index');
+const List = L.LinkedList;
+const Node = L.Node;
+
+test('List is a class', () => {
+ expect(typeof List.prototype.constructor).toEqual('function');
+});
+
+test('Node is a class', () => {
+ expect(typeof Node.prototype.constructor).toEqual('function');
+});
+
+describe('A Node', () => {
+ test('has properties "data" and "next"', () => {
+ const node = new Node('a', 'b');
+ expect(node.data).toEqual('a');
+ expect(node.next).toEqual('b');
+ });
+});
+
+describe('Insert First', () => {
+ test('appends a node to the start of the list', () => {
+ const l = new List();
+ l.insertFirst(1);
+ expect(l.head.data).toEqual(1);
+ l.insertFirst(2);
+ expect(l.head.data).toEqual(2);
+ });
+});
+
+describe('Size', () => {
+ test('returns the number of items in the linked list', () => {
+ const l = new List();
+ expect(l.size()).toEqual(0);
+ l.insertFirst(1);
+ l.insertFirst(1);
+ l.insertFirst(1);
+ l.insertFirst(1);
+ expect(l.size()).toEqual(4);
+ });
+});
+
+describe('GetFirst', () => {
+ test('returns the first element', () => {
+ const l = new List();
+ l.insertFirst(1);
+ expect(l.getFirst().data).toEqual(1);
+ l.insertFirst(2);
+ expect(l.getFirst().data).toEqual(2);
+ });
+});
+
+describe('GetLast', () => {
+ test('returns the last element', () => {
+ const l = new List();
+ l.insertFirst(2);
+ expect(l.getLast()).toEqual({ data: 2, next: null });
+ l.insertFirst(1);
+ expect(l.getLast()).toEqual({ data: 2, next: null });
+ });
+});
+
+describe('Clear', () => {
+ test('empties out the list', () => {
+ const l = new List();
+ expect(l.size()).toEqual(0);
+ l.insertFirst(1);
+ l.insertFirst(1);
+ l.insertFirst(1);
+ l.insertFirst(1);
+ expect(l.size()).toEqual(4);
+ l.clear();
+ expect(l.size()).toEqual(0);
+ });
+});
+
+describe('RemoveFirst', () => {
+ test('removes the first node when the list has a size of one', () => {
+ const l = new List();
+ l.insertFirst('a');
+ l.removeFirst();
+ expect(l.size()).toEqual(0);
+ expect(l.getFirst()).toEqual(null);
+ });
+
+ test('removes the first node when the list has a size of three', () => {
+ const l = new List();
+ l.insertFirst('c');
+ l.insertFirst('b');
+ l.insertFirst('a');
+ l.removeFirst();
+ expect(l.size()).toEqual(2);
+ expect(l.getFirst().data).toEqual('b');
+ l.removeFirst();
+ expect(l.size()).toEqual(1);
+ expect(l.getFirst().data).toEqual('c');
+ });
+});
+
+describe('RemoveLast', () => {
+ test('RemoveLast removes the last node when list is empty', () => {
+ const l = new List();
+ expect(() => {
+ l.removeLast();
+ }).not.toThrow();
+ });
+
+ test('RemoveLast removes the last node when list is length 1', () => {
+ const l = new List();
+ l.insertFirst('a');
+ l.removeLast();
+ expect(l.head).toEqual(null);
+ });
+
+ test('RemoveLast removes the last node when list is length 2', () => {
+ const l = new List();
+ l.insertFirst('b');
+ l.insertFirst('a');
+
+ l.removeLast();
+
+ expect(l.size()).toEqual(1);
+ expect(l.head.data).toEqual('a');
+ });
+
+ test('RemoveLast removes the last node when list is length 3', () => {
+ const l = new List();
+ l.insertFirst('c');
+ l.insertFirst('b');
+ l.insertFirst('a');
+ l.removeLast();
+
+ expect(l.size()).toEqual(2);
+ expect(l.getLast().data).toEqual('b');
+ });
+});
+
+describe('InsertLast', () => {
+ test('adds to the end of the list', () => {
+ const l = new List();
+ l.insertFirst('a');
+
+ l.insertLast('b');
+
+ expect(l.size()).toEqual(2);
+ expect(l.getLast().data).toEqual('b');
+ });
+});
+
+describe('GetAt', () => {
+ test('returns the node at given index', () => {
+ const l = new List();
+ expect(l.getAt(10)).toEqual(null);
+
+ l.insertLast(1);
+ l.insertLast(2);
+ l.insertLast(3);
+ l.insertLast(4);
+
+ expect(l.getAt(0).data).toEqual(1);
+ expect(l.getAt(1).data).toEqual(2);
+ expect(l.getAt(2).data).toEqual(3);
+ expect(l.getAt(3).data).toEqual(4);
+ });
+});
+
+describe('RemoveAt', () => {
+ test('removeAt doesnt crash on an empty list', () => {
+ const l = new List();
+ expect(() => {
+ l.removeAt(0);
+ l.removeAt(1);
+ l.removeAt(2);
+ }).not.toThrow();
+ });
+
+ test('removeAt doesnt crash on an index out of bounds', () => {
+ const l = new List();
+ expect(() => {
+ const l = new List();
+ l.insertFirst('a');
+ l.removeAt(1);
+ }).not.toThrow();
+ });
+
+ test('removeAt deletes the first node', () => {
+ const l = new List();
+ l.insertLast(1);
+ l.insertLast(2);
+ l.insertLast(3);
+ l.insertLast(4);
+ expect(l.getAt(0).data).toEqual(1);
+ l.removeAt(0);
+ expect(l.getAt(0).data).toEqual(2);
+ });
+
+ test('removeAt deletes the node at the given index', () => {
+ const l = new List();
+ l.insertLast(1);
+ l.insertLast(2);
+ l.insertLast(3);
+ l.insertLast(4);
+ expect(l.getAt(1).data).toEqual(2);
+ l.removeAt(1);
+ expect(l.getAt(1).data).toEqual(3);
+ });
+
+ test('removeAt works on the last node', () => {
+ const l = new List();
+ l.insertLast(1);
+ l.insertLast(2);
+ l.insertLast(3);
+ l.insertLast(4);
+ expect(l.getAt(3).data).toEqual(4);
+ l.removeAt(3);
+ expect(l.getAt(3)).toEqual(null);
+ });
+});
+
+describe('InsertAt', () => {
+ test('inserts a new node with data at the 0 index when the list is empty', () => {
+ const l = new List();
+ l.insertAt('hi', 0);
+ expect(l.getFirst().data).toEqual('hi');
+ });
+
+ test('inserts a new node with data at the 0 index when the list has elements', () => {
+ const l = new List();
+ l.insertLast('a');
+ l.insertLast('b');
+ l.insertLast('c');
+ l.insertAt('hi', 0);
+ expect(l.getAt(0).data).toEqual('hi');
+ expect(l.getAt(1).data).toEqual('a');
+ expect(l.getAt(2).data).toEqual('b');
+ expect(l.getAt(3).data).toEqual('c');
+ });
+
+ test('inserts a new node with data at a middle index', () => {
+ const l = new List();
+ l.insertLast('a');
+ l.insertLast('b');
+ l.insertLast('c');
+ l.insertLast('d');
+ l.insertAt('hi', 2);
+ expect(l.getAt(0).data).toEqual('a');
+ expect(l.getAt(1).data).toEqual('b');
+ expect(l.getAt(2).data).toEqual('hi');
+ expect(l.getAt(3).data).toEqual('c');
+ expect(l.getAt(4).data).toEqual('d');
+ });
+
+ test('inserts a new node with data at a last index', () => {
+ const l = new List();
+ l.insertLast('a');
+ l.insertLast('b');
+ l.insertAt('hi', 2);
+ expect(l.getAt(0).data).toEqual('a');
+ expect(l.getAt(1).data).toEqual('b');
+ expect(l.getAt(2).data).toEqual('hi');
+ });
+
+ test('insert a new node when index is out of bounds', () => {
+ const l = new List();
+ l.insertLast('a');
+ l.insertLast('b');
+ l.insertAt('hi', 30);
+
+ expect(l.getAt(0).data).toEqual('a');
+ expect(l.getAt(1).data).toEqual('b');
+ expect(l.getAt(2).data).toEqual('hi');
+ });
+});
+
+describe('ForEach', () => {
+ test('applies a transform to each node', () => {
+ const l = new List();
+
+ l.insertLast(1);
+ l.insertLast(2);
+ l.insertLast(3);
+ l.insertLast(4);
+
+ l.forEach(node => {
+ node.data += 10;
+ });
+
+ expect(l.getAt(0).data).toEqual(11);
+ expect(l.getAt(1).data).toEqual(12);
+ expect(l.getAt(2).data).toEqual(13);
+ expect(l.getAt(3).data).toEqual(14);
+ });
+});
+
+describe('for...of loops', () => {
+ test('works with the linked list', () => {
+ const l = new List();
+
+ l.insertLast(1);
+ l.insertLast(2);
+ l.insertLast(3);
+ l.insertLast(4);
+
+ for (let node of l) {
+ node.data += 10;
+ }
+
+ expect(l.getAt(0).data).toEqual(11);
+ expect(l.getAt(1).data).toEqual(12);
+ expect(l.getAt(2).data).toEqual(13);
+ expect(l.getAt(3).data).toEqual(14);
+ });
+
+ test('for...of works on an empty list', () => {
+ const l = new List();
+ expect(() => {
+ for (let node of l) {
+ }
+ }).not.toThrow();
+ });
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/matrix/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/matrix/index.js
new file mode 100644
index 0000000..f1d0651
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/matrix/index.js
@@ -0,0 +1,63 @@
+// --- Directions
+// Write a function that accepts an integer N
+// and returns a NxN spiral matrix.
+// --- Examples
+// matrix(2)
+// [[undefined, undefined],
+// [undefined, undefined]]
+// matrix(3)
+// [[1, 2, 3],
+// [8, 9, 4],
+// [7, 6, 5]]
+// matrix(4)
+// [[1, 2, 3, 4],
+// [12, 13, 14, 5],
+// [11, 16, 15, 6],
+// [10, 9, 8, 7]]
+
+function matrix(n) {
+ const results = [];
+
+ for (let i = 0; i < n; i++) {
+ results.push([]);
+ }
+
+ let counter = 1;
+ let startColumn = 0;
+ let endColumn = n - 1;
+ let startRow = 0;
+ let endRow = n - 1;
+ while (startColumn <= endColumn && startRow <= endRow) {
+ // Top row
+ for (let i = startColumn; i <= endColumn; i++) {
+ results[startRow][i] = counter;
+ counter++;
+ }
+ startRow++;
+
+ // Right column
+ for (let i = startRow; i <= endRow; i++) {
+ results[i][endColumn] = counter;
+ counter++;
+ }
+ endColumn--;
+
+ // Bottom row
+ for (let i = endColumn; i >= startColumn; i--) {
+ results[endRow][i] = counter;
+ counter++;
+ }
+ endRow--;
+
+ // start column
+ for (let i = endRow; i >= startRow; i--) {
+ results[i][startColumn] = counter;
+ counter++;
+ }
+ startColumn++;
+ }
+
+ return results;
+}
+
+module.exports = matrix;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/matrix/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/matrix/test.js
new file mode 100644
index 0000000..4476dda
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/matrix/test.js
@@ -0,0 +1,29 @@
+const matrix = require('./index');
+
+test('matrix is a function', () => {
+ expect(typeof matrix).toEqual('function');
+});
+
+test('matrix produces a 2x2 array', () => {
+ const m = matrix(2);
+ expect(m.length).toEqual(2);
+ expect(m[0]).toEqual([1, 2]);
+ expect(m[1]).toEqual([4, 3]);
+});
+
+test('matrix produces a 3x3 array', () => {
+ const m = matrix(3);
+ expect(m.length).toEqual(3);
+ expect(m[0]).toEqual([1, 2, 3]);
+ expect(m[1]).toEqual([8, 9, 4]);
+ expect(m[2]).toEqual([7, 6, 5]);
+});
+
+test('matrix produces a 4x4 array', () => {
+ const m = matrix(4);
+ expect(m.length).toEqual(4);
+ expect(m[0]).toEqual([1, 2, 3, 4]);
+ expect(m[1]).toEqual([12, 13, 14, 5]);
+ expect(m[2]).toEqual([11, 16, 15, 6]);
+ expect(m[3]).toEqual([10, 9, 8, 7]);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/maxchar/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/maxchar/index.js
new file mode 100644
index 0000000..4ddbeac
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/maxchar/index.js
@@ -0,0 +1,31 @@
+// --- Directions
+// Given a string, return the character that is most
+// commonly used in the string.
+// --- Examples
+// maxChar("abcccccccd") === "c"
+// maxChar("apple 1231111") === "1"
+
+function maxChar(str) {
+ const charMap = {};
+ let max = 0;
+ let maxChar = '';
+
+ for (let char of str) {
+ if (charMap[char]) {
+ charMap[char]++;
+ } else {
+ charMap[char] = 1;
+ }
+ }
+
+ for (let char in charMap) {
+ if (charMap[char] > max) {
+ max = charMap[char];
+ maxChar = char;
+ }
+ }
+
+ return maxChar;
+}
+
+module.exports = maxChar;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/maxchar/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/maxchar/test.js
new file mode 100644
index 0000000..14918ee
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/maxchar/test.js
@@ -0,0 +1,14 @@
+const maxChar = require('./index');
+
+test('maxChar function exists', () => {
+ expect(typeof maxChar).toEqual('function');
+});
+
+test('Finds the most frequently used char', () => {
+ expect(maxChar('a')).toEqual('a');
+ expect(maxChar('abcdefghijklmnaaaaa')).toEqual('a');
+});
+
+test('Works with numbers in the string', () => {
+ expect(maxChar('ab1c1d1e1f1g1')).toEqual('1');
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/midpoint/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/midpoint/index.js
new file mode 100644
index 0000000..10503dc
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/midpoint/index.js
@@ -0,0 +1,27 @@
+// --- Directions
+// Return the 'middle' node of a linked list.
+// If the list has an even number of elements, return
+// the node at the end of the first half of the list.
+// *Do not* use a counter variable, *do not* retrieve
+// the size of the list, and only iterate
+// through the list one time.
+// --- Example
+// const l = new LinkedList();
+// l.insertLast('a')
+// l.insertLast('b')
+// l.insertLast('c')
+// midpoint(l); // returns { data: 'b' }
+
+function midpoint(list) {
+ let slow = list.getFirst();
+ let fast = list.getFirst();
+
+ while (fast.next && fast.next.next) {
+ slow = slow.next;
+ fast = fast.next.next;
+ }
+
+ return slow;
+}
+
+module.exports = midpoint;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/midpoint/linkedlist.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/midpoint/linkedlist.js
new file mode 100644
index 0000000..b7da56b
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/midpoint/linkedlist.js
@@ -0,0 +1,178 @@
+class Node {
+ constructor(data, next = null) {
+ this.data = data;
+ this.next = next;
+ }
+}
+
+class LinkedList {
+ constructor(values = []) {
+ this.head = null;
+
+ for (let value of values) {
+ this.insertLast(value);
+ }
+ }
+
+ clear() {
+ this.head = null;
+ }
+
+ size() {
+ let counter = 0;
+ let node = this.head;
+
+ while (node) {
+ counter++;
+ node = node.next;
+ }
+
+ return counter;
+ }
+
+ getAt(index) {
+ if (!this.head) {
+ return null;
+ }
+
+ let counter = 0;
+ let node = this.head;
+ while (node) {
+ if (counter === index) {
+ return node;
+ }
+ node = node.next;
+ counter++;
+ }
+ return null;
+ }
+
+ insertAt(data, index) {
+ if (!this.head) {
+ this.head = new Node(data);
+ return;
+ }
+
+ if (index === 0) {
+ this.head = new Node(data, this.head);
+ return;
+ }
+
+ let counter = 1;
+ let previous = this.head;
+ let node = this.head.next;
+ while (node) {
+ if (counter === index) {
+ previous.next = new Node(data, node);
+ return;
+ }
+ previous = node;
+ node = node.next;
+ counter++;
+ }
+
+ previous.next = new Node(data, node);
+ }
+
+ removeFirst() {
+ if (!this.head) {
+ return;
+ }
+
+ this.head = this.head.next;
+ }
+
+ removeLast() {
+ if (!this.head) {
+ return;
+ }
+
+ if (!this.head.next) {
+ this.head = null;
+ return;
+ }
+
+ let previous = this.head;
+ let node = this.head.next;
+ while (node.next) {
+ previous = node;
+ node = node.next;
+ }
+ previous.next = null;
+ }
+
+ removeAt(index) {
+ if (!this.head) {
+ return;
+ }
+
+ let counter = 0;
+ let node = this.head;
+ while (node) {
+ if (counter === index - 1) {
+ if (node.next) {
+ return (node.next = node.next.next);
+ } else {
+ return (node.next = null);
+ }
+ }
+ node = node.next;
+ counter++;
+ }
+ }
+
+ getFirst() {
+ return this.head;
+ }
+
+ insertFirst(data) {
+ this.head = new Node(data, this.getFirst());
+ }
+
+ getLast() {
+ if (!this.head) {
+ return null;
+ }
+
+ let node = this.head;
+ while (node.next) {
+ node = node.next;
+ }
+
+ return node;
+ }
+
+ insertLast(data) {
+ const last = this.getLast();
+
+ if (last) {
+ last.next = new Node(data);
+ return last.next;
+ } else {
+ this.head = new Node(data);
+ return this.head;
+ }
+ }
+
+ forEach(fn) {
+ if (!this.head) {
+ return null;
+ }
+
+ let node = this.head;
+ while (node) {
+ fn(node);
+ node = node.next;
+ }
+ }
+
+ *[Symbol.iterator]() {
+ let node = this.head;
+ while (node) {
+ yield node;
+ node = node.next;
+ }
+ }
+}
+
+module.exports = { Node, LinkedList };
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/midpoint/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/midpoint/test.js
new file mode 100644
index 0000000..277597e
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/midpoint/test.js
@@ -0,0 +1,46 @@
+const midpoint = require('./index');
+const L = require('./linkedlist');
+const Node = L.Node;
+const LinkedList = L.LinkedList;
+
+test('Midpoint is a function', () => {
+ expect(typeof midpoint).toEqual('function');
+});
+
+describe('Midpoint returns the middle node of an odd numbered list', () => {
+ test('when the list has 3 elements', () => {
+ const l = new LinkedList();
+ l.insertLast('a');
+ l.insertLast('b');
+ l.insertLast('c');
+ expect(midpoint(l).data).toEqual('b');
+ });
+
+ test('when the list has 5 elements', () => {
+ const l = new LinkedList();
+ l.insertLast('a');
+ l.insertLast('b');
+ l.insertLast('c');
+ l.insertLast('d');
+ l.insertLast('e');
+ expect(midpoint(l).data).toEqual('c');
+ });
+});
+
+describe('Midpoint returns the middle node of an even numbered list', () => {
+ test('when the list has 2 elements', () => {
+ const l = new LinkedList();
+ l.insertLast('a');
+ l.insertLast('b');
+ expect(midpoint(l).data).toEqual('a');
+ });
+
+ test('when the list has 4 elements', () => {
+ const l = new LinkedList();
+ l.insertLast('a');
+ l.insertLast('b');
+ l.insertLast('c');
+ l.insertLast('d');
+ expect(midpoint(l).data).toEqual('b');
+ });
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/package.json b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/package.json
new file mode 100644
index 0000000..7ab32a4
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "dev",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "ISC"
+}
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/palindrome/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/palindrome/index.js
new file mode 100644
index 0000000..43bffe8
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/palindrome/index.js
@@ -0,0 +1,25 @@
+// --- Directions
+// Given a string, return true if the string is a palindrome
+// or false if it is not. Palindromes are strings that
+// form the same word if it is reversed. *Do* include spaces
+// and punctuation in determining if the string is a palindrome.
+// --- Examples:
+// palindrome("abba") === true
+// palindrome("abcdefg") === false
+
+function palindrome(str) {
+ return str.split('').every((char, i) => {
+ return char === str[str.length - i - 1];
+ });
+}
+
+module.exports = palindrome;
+
+// function palindrome(str) {
+// const reversed = str
+// .split('')
+// .reverse()
+// .join('');
+//
+// return str === reversed;
+// }
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/palindrome/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/palindrome/test.js
new file mode 100644
index 0000000..abdbcb1
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/palindrome/test.js
@@ -0,0 +1,33 @@
+const palindrome = require('./index');
+
+test('palindrome function is defined', () => {
+ expect(typeof palindrome).toEqual('function');
+});
+
+test('"aba" is a palindrome', () => {
+ expect(palindrome('aba')).toBeTruthy();
+});
+
+test('" aba" is not a palindrome', () => {
+ expect(palindrome(' aba')).toBeFalsy();
+});
+
+test('"aba " is not a palindrome', () => {
+ expect(palindrome('aba ')).toBeFalsy();
+});
+
+test('"greetings" is not a palindrome', () => {
+ expect(palindrome('greetings')).toBeFalsy();
+});
+
+test('"1000000001" a palindrome', () => {
+ expect(palindrome('1000000001')).toBeTruthy();
+});
+
+test('"Fish hsif" is not a palindrome', () => {
+ expect(palindrome('Fish hsif')).toBeFalsy();
+});
+
+test('"pennep" a palindrome', () => {
+ expect(palindrome('pennep')).toBeTruthy();
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/pyramid/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/pyramid/index.js
new file mode 100644
index 0000000..003b0a0
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/pyramid/index.js
@@ -0,0 +1,55 @@
+// --- Directions
+// Write a function that accepts a positive number N.
+// The function should console log a pyramid shape
+// with N levels using the # character. Make sure the
+// pyramid has spaces on both the left *and* right hand sides
+// --- Examples
+// pyramid(1)
+// '#'
+// pyramid(2)
+// ' # '
+// '###'
+// pyramid(3)
+// ' # '
+// ' ### '
+// '#####'
+
+function pyramid(n, row = 0, level = '') {
+ if (row === n) {
+ return;
+ }
+
+ if (level.length === 2 * n - 1) {
+ console.log(level);
+ return pyramid(n, row + 1);
+ }
+
+ const midpoint = Math.floor((2 * n - 1) / 2);
+ let add;
+ if (midpoint - row <= level.length && midpoint + row >= level.length) {
+ add = '#';
+ } else {
+ add = ' ';
+ }
+ pyramid(n, row, level + add);
+}
+
+module.exports = pyramid;
+//
+// function pyramid(n) {
+// const midpoint = Math.floor((2 * n - 1) / 2);
+//
+// for (let row = 0; row < n; row++) {
+// let level = '';
+//
+// for (let column = 0; column < 2 * n - 1; column++) {
+// if (midpoint - row <= column && midpoint + row >= column) {
+// level += '#';
+// } else {
+// level += ' ';
+// }
+// }
+//
+// console.log(level);
+// }
+// }
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/pyramid/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/pyramid/test.js
new file mode 100644
index 0000000..8ffc318
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/pyramid/test.js
@@ -0,0 +1,37 @@
+const pyramid = require('./index');
+
+beforeEach(() => {
+ jest.spyOn(console, 'log');
+});
+
+afterEach(() => {
+ console.log.mockRestore();
+});
+
+test('pyramid is a function', () => {
+ expect(typeof pyramid).toEqual('function');
+});
+
+test('prints a pryamid for n = 2', () => {
+ pyramid(2);
+ expect(console.log.mock.calls[0][0]).toEqual(' # ');
+ expect(console.log.mock.calls[1][0]).toEqual('###');
+ expect(console.log.mock.calls.length).toEqual(2);
+});
+
+test('prints a pryamid for n = 3', () => {
+ pyramid(3);
+ expect(console.log.mock.calls[0][0]).toEqual(' # ');
+ expect(console.log.mock.calls[1][0]).toEqual(' ### ');
+ expect(console.log.mock.calls[2][0]).toEqual('#####');
+ expect(console.log.mock.calls.length).toEqual(3);
+});
+
+test('prints a pryamid for n = 4', () => {
+ pyramid(4);
+ expect(console.log.mock.calls[0][0]).toEqual(' # ');
+ expect(console.log.mock.calls[1][0]).toEqual(' ### ');
+ expect(console.log.mock.calls[2][0]).toEqual(' ##### ');
+ expect(console.log.mock.calls[3][0]).toEqual('#######');
+ expect(console.log.mock.calls.length).toEqual(4);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/qfroms/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/qfroms/index.js
new file mode 100644
index 0000000..829c30e
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/qfroms/index.js
@@ -0,0 +1,56 @@
+// --- Directions
+// Implement a Queue datastructure using two stacks.
+// *Do not* create an array inside of the 'Queue' class.
+// Queue should implement the methods 'add', 'remove', and 'peek'.
+// For a reminder on what each method does, look back
+// at the Queue exercise.
+// --- Examples
+// const q = new Queue();
+// q.add(1);
+// q.add(2);
+// q.peek(); // returns 1
+// q.remove(); // returns 1
+// q.remove(); // returns 2
+
+const Stack = require('./stack');
+
+class Queue {
+ constructor() {
+ this.first = new Stack();
+ this.second = new Stack();
+ }
+
+ add(record) {
+ this.first.push(record);
+ }
+
+ remove() {
+ while (this.first.peek()) {
+ this.second.push(this.first.pop());
+ }
+
+ const record = this.second.pop();
+
+ while (this.second.peek()) {
+ this.first.push(this.second.pop());
+ }
+
+ return record;
+ }
+
+ peek() {
+ while (this.first.peek()) {
+ this.second.push(this.first.pop());
+ }
+
+ const record = this.second.peek();
+
+ while (this.second.peek()) {
+ this.first.push(this.second.pop());
+ }
+
+ return record;
+ }
+}
+
+module.exports = Queue;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/qfroms/stack.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/qfroms/stack.js
new file mode 100644
index 0000000..2032acb
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/qfroms/stack.js
@@ -0,0 +1,19 @@
+class Stack {
+ constructor() {
+ this.data = [];
+ }
+
+ push(record) {
+ this.data.push(record);
+ }
+
+ pop() {
+ return this.data.pop();
+ }
+
+ peek() {
+ return this.data[this.data.length - 1];
+ }
+}
+
+module.exports = Stack;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/qfroms/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/qfroms/test.js
new file mode 100644
index 0000000..3fc84c7
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/qfroms/test.js
@@ -0,0 +1,41 @@
+const Queue = require('./index');
+
+test('Queue is a class', () => {
+ expect(typeof Queue.prototype.constructor).toEqual('function');
+});
+
+test('can add elements to a queue', () => {
+ const q = new Queue();
+ expect(() => {
+ q.add(1);
+ }).not.toThrow();
+});
+
+test('can remove elements from a queue', () => {
+ const q = new Queue();
+ expect(() => {
+ q.add(1);
+ q.remove();
+ }).not.toThrow();
+});
+
+test('Order of elements is maintained', () => {
+ const q = new Queue();
+ q.add(1);
+ q.add(2);
+ q.add(3);
+ expect(q.remove()).toEqual(1);
+ expect(q.remove()).toEqual(2);
+ expect(q.remove()).toEqual(3);
+ expect(q.remove()).toEqual(undefined);
+});
+
+test('peek returns, but does not remove, the first value', () => {
+ const q = new Queue();
+ q.add(1);
+ q.add(2);
+ expect(q.peek()).toEqual(1);
+ expect(q.peek()).toEqual(1);
+ expect(q.remove()).toEqual(1);
+ expect(q.remove()).toEqual(2);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/queue/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/queue/index.js
new file mode 100644
index 0000000..e475d6e
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/queue/index.js
@@ -0,0 +1,25 @@
+// --- Description
+// Create a queue data structure. The queue
+// should be a class with methods 'add' and 'remove'.
+// Adding to the queue should store an element until
+// it is removed
+// --- Examples
+// const q = new Queue();
+// q.add(1);
+// q.remove(); // returns 1;
+
+class Queue {
+ constructor() {
+ this.data = [];
+ }
+
+ add(record) {
+ this.data.unshift(record);
+ }
+
+ remove() {
+ return this.data.pop();
+ }
+}
+
+module.exports = Queue;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/queue/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/queue/test.js
new file mode 100644
index 0000000..867bd42
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/queue/test.js
@@ -0,0 +1,31 @@
+const Queue = require('./index');
+
+test('Queue is a class', () => {
+ expect(typeof Queue.prototype.constructor).toEqual('function');
+});
+
+test('can add elements to a queue', () => {
+ const q = new Queue();
+ expect(() => {
+ q.add(1);
+ }).not.toThrow();
+});
+
+test('can remove elements from a queue', () => {
+ const q = new Queue();
+ expect(() => {
+ q.add(1);
+ q.remove();
+ }).not.toThrow();
+});
+
+test('Order of elements is maintained', () => {
+ const q = new Queue();
+ q.add(1);
+ q.add(2);
+ q.add(3);
+ expect(q.remove()).toEqual(1);
+ expect(q.remove()).toEqual(2);
+ expect(q.remove()).toEqual(3);
+ expect(q.remove()).toEqual(undefined);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/reverseint/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/reverseint/index.js
new file mode 100644
index 0000000..c2e6a0d
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/reverseint/index.js
@@ -0,0 +1,21 @@
+// --- Directions
+// Given an integer, return an integer that is the reverse
+// ordering of numbers.
+// --- Examples
+// reverseInt(15) === 51
+// reverseInt(981) === 189
+// reverseInt(500) === 5
+// reverseInt(-15) === -51
+// reverseInt(-90) === -9
+
+function reverseInt(n) {
+ const reversed = n
+ .toString()
+ .split('')
+ .reverse()
+ .join('');
+
+ return parseInt(reversed) * Math.sign(n);
+}
+
+module.exports = reverseInt;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/reverseint/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/reverseint/test.js
new file mode 100644
index 0000000..e5092e2
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/reverseint/test.js
@@ -0,0 +1,23 @@
+const reverseInt = require('./index');
+
+test('ReverseInt function exists', () => {
+ expect(reverseInt).toBeDefined();
+});
+
+test('ReverseInt handles 0 as an input', () => {
+ expect(reverseInt(0)).toEqual(0);
+});
+
+test('ReverseInt flips a positive number', () => {
+ expect(reverseInt(5)).toEqual(5);
+ expect(reverseInt(15)).toEqual(51);
+ expect(reverseInt(90)).toEqual(9);
+ expect(reverseInt(2359)).toEqual(9532);
+});
+
+test('ReverseInt flips a negative number', () => {
+ expect(reverseInt(-5)).toEqual(-5);
+ expect(reverseInt(-15)).toEqual(-51);
+ expect(reverseInt(-90)).toEqual(-9);
+ expect(reverseInt(-2359)).toEqual(-9532);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/reversestring/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/reversestring/index.js
new file mode 100644
index 0000000..5f036a9
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/reversestring/index.js
@@ -0,0 +1,30 @@
+// --- Directions
+// Given a string, return a new string with the reversed
+// order of characters
+// --- Examples
+// reverse('apple') === 'leppa'
+// reverse('hello') === 'olleh'
+// reverse('Greetings!') === '!sgniteerG'
+
+function reverse(str) {
+ return str.split('').reduce((rev, char) => char + rev, '');
+}
+
+module.exports = reverse;
+
+// function reverse(str) {
+// return str
+// .split('')
+// .reverse()
+// .join('');
+// }
+
+// function reverse(str) {
+// let reversed = '';
+//
+// for (let character of str) {
+// reversed = character + reversed;
+// }
+//
+// return reversed;
+// }
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/reversestring/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/reversestring/test.js
new file mode 100644
index 0000000..8d264c0
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/reversestring/test.js
@@ -0,0 +1,13 @@
+const reverse = require('./index');
+
+test('Reverse function exists', () => {
+ expect(reverse).toBeDefined();
+});
+
+test('Reverse reverses a string', () => {
+ expect(reverse('abcd')).toEqual('dcba');
+});
+
+test('Reverse reverses a string', () => {
+ expect(reverse(' abcd')).toEqual('dcba ');
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/sorting/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/sorting/index.js
new file mode 100644
index 0000000..5ad4201
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/sorting/index.js
@@ -0,0 +1,66 @@
+// --- Directions
+// Implement bubbleSort, selectionSort, and mergeSort
+
+function bubbleSort(arr) {
+ // Implement bubblesort
+ for (let i = 0; i < arr.length; i++) {
+ for (let j = 0; j < (arr.length - i - 1); j++) {
+ if (arr[j] > arr[j+1]) {
+ const lesser = arr[j+1];
+ arr[j+1] = arr[j];
+ arr[j] = lesser;
+ }
+ }
+ }
+
+ // return the sorted array
+ return arr;
+}
+
+function selectionSort(arr) {
+ for (let i = 0; i < arr.length; i++) {
+ let indexOfMin = i;
+
+ for (let j = i+1; j {
+ test('sorts an array', () => {
+ expect(bubbleSort(getArray())).toEqual(getSortedArray());
+ });
+});
+
+describe('Selection sort', () => {
+ test('sorts an array', () => {
+ expect(selectionSort(getArray())).toEqual(getSortedArray());
+ });
+});
+
+describe('Merge sort', () => {
+ test('merge function can join together two sorted arrays', () => {
+ const left = [1, 10];
+ const right = [2, 8, 12];
+
+ expect(merge(left, right)).toEqual([1,2,8,10,12]);
+ });
+
+ test('sorts an array', () => {
+ expect(mergeSort(getArray())).toEqual(getSortedArray());
+ });
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/stack/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/stack/index.js
new file mode 100644
index 0000000..7e95441
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/stack/index.js
@@ -0,0 +1,31 @@
+// --- Directions
+// Create a stack data structure. The stack
+// should be a class with methods 'push', 'pop', and
+// 'peek'. Adding an element to the stack should
+// store it until it is removed.
+// --- Examples
+// const s = new Stack();
+// s.push(1);
+// s.push(2);
+// s.pop(); // returns 2
+// s.pop(); // returns 1
+
+class Stack {
+ constructor() {
+ this.data = [];
+ }
+
+ push(record) {
+ this.data.push(record);
+ }
+
+ pop() {
+ return this.data.pop();
+ }
+
+ peek() {
+ return this.data[this.data.length - 1];
+ }
+}
+
+module.exports = Stack;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/stack/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/stack/test.js
new file mode 100644
index 0000000..457e5a2
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/stack/test.js
@@ -0,0 +1,36 @@
+const Stack = require('./index');
+
+test('Stack is a class', () => {
+ expect(typeof Stack.prototype.constructor).toEqual('function');
+});
+
+test('stack can add and remove items', () => {
+ const s = new Stack();
+ s.push(1);
+ expect(s.pop()).toEqual(1);
+ s.push(2);
+ expect(s.pop()).toEqual(2);
+});
+
+test('stack can follows first in, last out', () => {
+ const s = new Stack();
+ s.push(1);
+ s.push(2);
+ s.push(3);
+ expect(s.pop()).toEqual(3);
+ expect(s.pop()).toEqual(2);
+ expect(s.pop()).toEqual(1);
+});
+
+test('peek returns the first element but doesnt pop it', () => {
+ const s = new Stack();
+ s.push(1);
+ s.push(2);
+ s.push(3);
+ expect(s.peek()).toEqual(3);
+ expect(s.pop()).toEqual(3);
+ expect(s.peek()).toEqual(2);
+ expect(s.pop()).toEqual(2);
+ expect(s.peek()).toEqual(1);
+ expect(s.pop()).toEqual(1);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/steps/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/steps/index.js
new file mode 100644
index 0000000..fd73326
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/steps/index.js
@@ -0,0 +1,50 @@
+// --- Directions
+// Write a function that accepts a positive number N.
+// The function should console log a step shape
+// with N levels using the # character. Make sure the
+// step has spaces on the right hand side!
+// --- Examples
+// steps(2)
+// '# '
+// '##'
+// steps(3)
+// '# '
+// '## '
+// '###'
+// steps(4)
+// '# '
+// '## '
+// '### '
+// '####'
+
+function steps(n, row = 0, stair = '') {
+ if (n === row) {
+ return;
+ }
+
+ if (n === stair.length) {
+ console.log(stair);
+ return steps(n, row + 1);
+ }
+
+ const add = stair.length <= row ? '#' : ' ';
+ steps(n, row, stair + add);
+}
+
+module.exports = steps;
+
+// function steps(n) {
+// for (let row = 0; row < n; row++) {
+// let stair = '';
+//
+// for (let column = 0; column < n; column++) {
+// if (column <= row) {
+// stair += '#';
+// } else {
+// stair += ' ';
+// }
+// }
+//
+// console.log(stair);
+// }
+// }
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/steps/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/steps/test.js
new file mode 100644
index 0000000..007af11
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/steps/test.js
@@ -0,0 +1,34 @@
+const steps = require('./index');
+
+beforeEach(() => {
+ jest.spyOn(console, 'log');
+});
+
+afterEach(() => {
+ console.log.mockRestore();
+});
+
+test('steps is a function', () => {
+ expect(typeof steps).toEqual('function');
+});
+
+test('steps called with n = 1', () => {
+ steps(1);
+ expect(console.log.mock.calls[0][0]).toEqual('#');
+ expect(console.log.mock.calls.length).toEqual(1);
+});
+
+test('steps called with n = 2', () => {
+ steps(2);
+ expect(console.log.mock.calls[0][0]).toEqual('# ');
+ expect(console.log.mock.calls[1][0]).toEqual('##');
+ expect(console.log.mock.calls.length).toEqual(2);
+});
+
+test('steps called with n = 3', () => {
+ steps(3);
+ expect(console.log.mock.calls[0][0]).toEqual('# ');
+ expect(console.log.mock.calls[1][0]).toEqual('## ');
+ expect(console.log.mock.calls[2][0]).toEqual('###');
+ expect(console.log.mock.calls.length).toEqual(3);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/tree/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/tree/index.js
new file mode 100644
index 0000000..3bfb536
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/tree/index.js
@@ -0,0 +1,56 @@
+// --- Directions
+// 1) Create a node class. The constructor
+// should accept an argument that gets assigned
+// to the data property and initialize an
+// empty array for storing children. The node
+// class should have methods 'add' and 'remove'.
+// 2) Create a tree class. The tree constructor
+// should initialize a 'root' property to null.
+// 3) Implement 'traverseBF' and 'traverseDF'
+// on the tree class. Each method should accept a
+// function that gets called with each element in the tree
+
+class Node {
+ constructor(data) {
+ this.data = data;
+ this.children = [];
+ }
+
+ add(data) {
+ this.children.push(new Node(data));
+ }
+
+ remove(data) {
+ this.children = this.children.filter(node => {
+ return node.data !== data;
+ });
+ }
+}
+
+class Tree {
+ constructor() {
+ this.root = null;
+ }
+
+ traverseBF(fn) {
+ const arr = [this.root];
+ while (arr.length) {
+ const node = arr.shift();
+
+ arr.push(...node.children);
+ fn(node);
+ }
+ }
+
+ traverseDF(fn) {
+ const arr = [this.root];
+ while (arr.length) {
+ const node = arr.shift();
+
+ arr.unshift(...node.children);
+ fn(node);
+ }
+ }
+}
+
+module.exports = { Tree, Node };
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/tree/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/tree/test.js
new file mode 100644
index 0000000..69dab5d
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/tree/test.js
@@ -0,0 +1,67 @@
+const T = require('./index');
+const Node = T.Node;
+const Tree = T.Tree;
+
+describe('Node', () => {
+ test('Node is a constructor', () => {
+ expect(typeof Node.prototype.constructor).toEqual('function');
+ });
+
+ test('Node has a data and children properties', () => {
+ const n = new Node('a');
+ expect(n.data).toEqual('a');
+ expect(n.children.length).toEqual(0);
+ });
+
+ test('Node can add children', () => {
+ const n = new Node('a');
+ n.add('b');
+ expect(n.children.length).toEqual(1);
+ expect(n.children[0].children).toEqual([]);
+ });
+
+ test('Node can remove children', () => {
+ const n = new Node('a');
+ n.add('b');
+ expect(n.children.length).toEqual(1);
+ n.remove('b');
+ expect(n.children.length).toEqual(0);
+ });
+});
+
+describe('Tree', () => {
+ test('starts empty', () => {
+ const t = new Tree();
+ expect(t.root).toEqual(null);
+ });
+
+ test('Can traverse bf', () => {
+ const letters = [];
+ const t = new Tree();
+ t.root = new Node('a');
+ t.root.add('b');
+ t.root.add('c');
+ t.root.children[0].add('d');
+
+ t.traverseBF(node => {
+ letters.push(node.data);
+ });
+
+ expect(letters).toEqual(['a', 'b', 'c', 'd']);
+ });
+
+ test('Can traverse DF', () => {
+ const letters = [];
+ const t = new Tree();
+ t.root = new Node('a');
+ t.root.add('b');
+ t.root.add('d');
+ t.root.children[0].add('c');
+
+ t.traverseDF(node => {
+ letters.push(node.data);
+ });
+
+ expect(letters).toEqual(['a', 'b', 'c', 'd']);
+ });
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/validate/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/validate/index.js
new file mode 100644
index 0000000..9f4da37
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/validate/index.js
@@ -0,0 +1,28 @@
+// --- Directions
+// Given a node, validate the binary search tree,
+// ensuring that every node's left hand child is
+// less than the parent node's value, and that
+// every node's right hand child is greater than
+// the parent
+
+function validate(node, min = null, max = null) {
+ if (max !== null && node.data > max) {
+ return false;
+ }
+
+ if (min !== null && node.data < min) {
+ return false;
+ }
+
+ if (node.left && !validate(node.left, min, node.data)) {
+ return false;
+ }
+
+ if (node.right && !validate(node.right, node.data, max)) {
+ return false;
+ }
+
+ return true;
+}
+
+module.exports = validate;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/validate/node.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/validate/node.js
new file mode 100644
index 0000000..d19e208
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/validate/node.js
@@ -0,0 +1,21 @@
+class Node {
+ constructor(data) {
+ this.data = data;
+ this.left = null;
+ this.right = null;
+ }
+
+ insert(data) {
+ if (data < this.data && this.left) {
+ this.left.insert(data);
+ } else if (data < this.data) {
+ this.left = new Node(data);
+ } else if (data > this.data && this.right) {
+ this.right.insert(data);
+ } else if (data > this.data) {
+ this.right = new Node(data);
+ }
+ }
+}
+
+module.exports = Node;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/validate/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/validate/test.js
new file mode 100644
index 0000000..6ea4dc3
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/validate/test.js
@@ -0,0 +1,23 @@
+const Node = require('./node');
+const validate = require('./index');
+
+test('Validate recognizes a valid BST', () => {
+ const n = new Node(10);
+ n.insert(5);
+ n.insert(15);
+ n.insert(0);
+ n.insert(20);
+
+ expect(validate(n)).toEqual(true);
+});
+
+test('Validate recognizes an invalid BST', () => {
+ const n = new Node(10);
+ n.insert(5);
+ n.insert(15);
+ n.insert(0);
+ n.insert(20);
+ n.left.left.right = new Node(999);
+
+ expect(validate(n)).toEqual(false);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/vowels/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/vowels/index.js
new file mode 100644
index 0000000..379ba6c
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/vowels/index.js
@@ -0,0 +1,28 @@
+// --- Directions
+// Write a function that returns the number of vowels
+// used in a string. Vowels are the characters 'a', 'e'
+// 'i', 'o', and 'u'.
+// --- Examples
+// vowels('Hi There!') --> 3
+// vowels('Why do you ask?') --> 4
+// vowels('Why?') --> 0
+
+function vowels(str) {
+ const matches = str.match(/[aeiou]/gi);
+ return matches ? matches.length : 0;
+}
+
+module.exports = vowels;
+
+// function vowels(str) {
+// let count = 0;
+// const checker = ['a', 'e', 'i', 'o', 'u'];
+//
+// for (let char of str.toLowerCase()) {
+// if (checker.includes(char)) {
+// count++;
+// }
+// }
+//
+// return count;
+// }
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/vowels/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/vowels/test.js
new file mode 100644
index 0000000..0bbf430
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/vowels/test.js
@@ -0,0 +1,17 @@
+const vowels = require('./index');
+
+test('Vowels is a function', () => {
+ expect(typeof vowels).toEqual('function');
+});
+
+test('returns the number of vowels used', () => {
+ expect(vowels('aeiou')).toEqual(5);
+});
+
+test('returns the number of vowels used', () => {
+ expect(vowels('abcdefghijklmnopqrstuvwxyz')).toEqual(5);
+});
+
+test('returns the number of vowels used', () => {
+ expect(vowels('bcdfghjkl')).toEqual(0);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/weave/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/weave/index.js
new file mode 100644
index 0000000..0818cb2
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/weave/index.js
@@ -0,0 +1,43 @@
+// --- Directions
+// 1) Complete the task in weave/queue.js
+// 2) Implement the 'weave' function. Weave
+// receives two queues as arguments and combines the
+// contents of each into a new, third queue.
+// The third queue should contain the *alterating* content
+// of the two queues. The function should handle
+// queues of different lengths without inserting
+// 'undefined' into the new one.
+// *Do not* access the array inside of any queue, only
+// use the 'add', 'remove', and 'peek' functions.
+// --- Example
+// const queueOne = new Queue();
+// queueOne.add(1);
+// queueOne.add(2);
+// const queueTwo = new Queue();
+// queueTwo.add('Hi');
+// queueTwo.add('There');
+// const q = weave(queueOne, queueTwo);
+// q.remove() // 1
+// q.remove() // 'Hi'
+// q.remove() // 2
+// q.remove() // 'There'
+
+const Queue = require('./queue');
+
+function weave(sourceOne, sourceTwo) {
+ const q = new Queue();
+
+ while (sourceOne.peek() || sourceTwo.peek()) {
+ if (sourceOne.peek()) {
+ q.add(sourceOne.remove());
+ }
+
+ if (sourceTwo.peek()) {
+ q.add(sourceTwo.remove());
+ }
+ }
+
+ return q;
+}
+
+module.exports = weave;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/weave/queue.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/weave/queue.js
new file mode 100644
index 0000000..20044c2
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/weave/queue.js
@@ -0,0 +1,25 @@
+// --- Directions
+// Implement a 'peek' method in this Queue class.
+// Peek should return the last element (the next
+// one to be returned) from the queue *without*
+// removing it.
+
+class Queue {
+ constructor() {
+ this.data = [];
+ }
+
+ add(record) {
+ this.data.unshift(record);
+ }
+
+ remove() {
+ return this.data.pop();
+ }
+
+ peek() {
+ return this.data[this.data.length - 1];
+ }
+}
+
+module.exports = Queue;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/weave/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/weave/test.js
new file mode 100644
index 0000000..f173360
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/completed_exercises/weave/test.js
@@ -0,0 +1,45 @@
+const weave = require('./index');
+const Queue = require('./queue');
+
+test('queues have a peek function', () => {
+ const q = new Queue();
+ expect(typeof q.peek).toEqual('function');
+});
+
+test('peek returns, but does not remove, the first value', () => {
+ const q = new Queue();
+ q.add(1);
+ q.add(2);
+ expect(q.peek()).toEqual(1);
+ expect(q.peek()).toEqual(1);
+ expect(q.remove()).toEqual(1);
+ expect(q.remove()).toEqual(2);
+});
+
+test('weave is a function', () => {
+ expect(typeof weave).toEqual('function');
+});
+
+test('weave can combine two queues', () => {
+ const one = new Queue();
+ one.add(1);
+ one.add(2);
+ one.add(3);
+ one.add(4);
+ const two = new Queue();
+ two.add('one');
+ two.add('two');
+ two.add('three');
+ two.add('four');
+
+ const result = weave(one, two);
+ expect(result.remove()).toEqual(1);
+ expect(result.remove()).toEqual('one');
+ expect(result.remove()).toEqual(2);
+ expect(result.remove()).toEqual('two');
+ expect(result.remove()).toEqual(3);
+ expect(result.remove()).toEqual('three');
+ expect(result.remove()).toEqual(4);
+ expect(result.remove()).toEqual('four');
+ expect(result.remove()).toBeUndefined();
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/01/.gitkeep b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/01/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/01/diagrams.xml b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/01/diagrams.xml
new file mode 100644
index 0000000..8b9e993
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/01/diagrams.xml
@@ -0,0 +1 @@
+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
\ No newline at end of file
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/02/.gitkeep b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/02/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/02/diagrams.xml b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/02/diagrams.xml
new file mode 100644
index 0000000..19e74dd
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/02/diagrams.xml
@@ -0,0 +1 @@
+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
\ No newline at end of file
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/03/.gitkeep b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/03/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/03/diagrams.xml b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/03/diagrams.xml
new file mode 100644
index 0000000..d837be7
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/03/diagrams.xml
@@ -0,0 +1 @@
+7ZlBc6MgFMc/jTPdm0LU5LjJdtvLbnemhz1TJcoUwUVskv30CwqJYpq03SZezCHBxwMe/P4gEA+uiu2dQGX+g6eYesBPtx785gEQ+NBXP9qyay2hH7eGTJDUOB0Mj+QvtiWNtSYprnqOknMqSdk3JpwxnMieDQnBN323Naf9VkuU4YHhMUF0aP1NUpkba+D7h4x7TLLcND0PTcYTSp4zwWtm2vMAXDefNrtAti7jX+Uo5ZuOCd56cCU4l22q2K4w1WNrh60t9/2V3H3cAjP5lgKgLfCCaI1txE1ccmfHArP0qx5S9ZRQVFUk8eAylwVVhkAlKyn4M15xykVTAPrNZ59jBxAqy5ozaWiD2DwfKznshukZTnvgTKfuMC+wFDvlsDngskzyDihrE5giSV76uJFRTbavbt/CL05UJMA3CoczU4/R98wKw1ZR8Vok2JTqjr9TURSeqUgikWE5qEglOt0+mBq8x1HDCfWoqN2KwOVQzybUo6IOYwf17GKowwn1uAs46FcE44uhjibUo6KeubM6eBtqRQTtOm6ldqhOBLxwJBX5p+OCjr+753P9nT0HWJzxjxz/fjwq0fbwo7qeT7oeV9f+lXTtzB8YntbdYB4EZ3Tq9iP+XJ0uBjp9uGFfBlqVeCtPqZNxhrXsCKWOCVGSMS1xpTis7MsXLCRRp9KvJqMgaaqbWW5yIvFjiRLd5kadwZWtOXViHWuje3uw1A8UPWG63B9N3UgOEyKIPjIhdJh4652aEq9tjOxc6EyZ2ZEpAxxFdmdH7416Ap9VdY8f5ZliOEF8D8TIfd9cE2JwBCLzQEQ1rqouVTLTSWBtqsaOeSL9HtLumz9YXJH08Grq4QYcIc0m0v9PGs5HJD3dTI18XeHeTF1oA+gePM5t6EJ3Q/fJB49geE+mXibTluAD+zoY9JePeXy95WN4L/KzLp7UQAOfr7WjxEWlY8G6JaG/c8RSSlg2QX4XZGe9CcIB5AAcoQzDT6AcDyjfqyECflEnue6Z4AlW7wXN1C/5psFPqmaV/VMTocZ2Yv121sBhvb9ovgBr9Xj4w7Ndxg//KsPbfw==7ZnRbqM4FIafJhppLkaAgZDLaabdXWlHGm0vdubSwSfgrYOzxjTJPv0egyFQ007aSQbtKqlEze+Dwf7+cyBkRpab/S+KbvPPkoGYBR7bz8inWRAkixi3Rjg0QkTmjZApzhrJPwr3/B+womfVijMoB4FaSqH5diimsigg1QONKiV3w7C1FMOzbmkGjnCfUuGqf3Kmc6v6nnfs+BV4lttTJ5HtWNH0IVOyKuz5ZgFZ15+me0PbsWx8mVMmdz2J3M7IUkmpm9ZmvwRhlrZdtua4u2d6u+tWUOhTDuiuQx/auQPDpbC7UulcZrKg4vao3tTzAzOCh3u53ghs+tiEPddfe+1vJuRDhHulpkp/NGRQKmQBrXbHhbADQcHaiFTQsuRpI9oQM+hfoPXB2oVWWqJ0vMTfpdzauFIr+QBLKaSqJ0W8+tP1tFAJKmtZaDukH9v9sSObhTKr8+xaW6mUlUptVGDdS1UGbVTYgcb8AbkBrQ4Yo0BQzR+Hw1Pr5KyLO9LEhgX6DNxmiEcqKjvoUgHVYKax2epDkyz0UGcXbnKTJphUeVU8lKZBhQCjvKslYO8cswytsMu5hvstrSe/w8owtEdndhMr6ArETZcu7Yp33ngKMDF/DsDAAEN/9CJtvp0OlgqeFagJWOuO8yMoDfuXSbsI2wNCm1a2/Pltmu2OxYQkVst7dST2fpw6cajf4ZQROU1z80/AxkwDDygM+NzY4X1VWMTvj6a4on4L6uQnog4d1H/gEBweoSOLhVS71K8J/UrKyZByEI5QDi9EOXIoz4JYmJmtsJGZxm/rVsLBOnUMP5NgSnsha3nPTTdegVeXCL42G20CBBSZNvWCmz34u6KivU3U3jGuMSiu/nmLf4j3E/0TO/75UpUGLTVGgF0PKS9qwr3ygFdY26CpJmmlVOOjzlFX/ifwx8GH/GOXf7C4EP/59+vHrSgN3rEiQhl7CX9rGRvQ+OjqiTfUhHDsIfFSNWEx4ompqCXBisTxKdRYBAkLJ6UWxU+ohQ40P74QNN993puOWpwmsFqfRI1Csk6npbb4/hey7uVTH1tyDmzuDXg6bCxexdFJyYb1MUinxTb3oiE24jvYLnXX9Mdum1NRW8RzQk+iBj4Wyfmk1GKHmptsF6OWONSW9tm2XgzMeyN6Lkucr34CbEDBoukvt5XaFUxxfQD1G7N6PKXio+3YcMbqF6djDhl66BUmed17yx/Lw2hYPuPIvekFI0SDcxD1HKK+A+//9ITZ2egcqeg/ue+FxCE39ohJojOA8x1wE1bQ/xq4KJoOnPsGmVzBnVoqnYxzvyCcCRzuHn8orPt6P8aS238B7Znfb5swEMf/mihvE2Ag5LFN2+2hkyb1od2jAwd4NTgyTpPsr58NNoSYTmmbH92UVErw12cb7nN3cZ0RmhXrrxwv8u8sATrynGQ9Qjcjz5tGnnxXwqYRfOQ0QsZJ0khuJzyQ36BFY7YkCVQ9Q8EYFWTRF2NWlhCLnoY5Z6u+Wcpof9UFzsASHmJMbfWRJCLXqus4Xcc3IFmul44C3THH8XPG2bLU6408lNavprvAZi5tX+U4YastCd2O0IwzJpqrYj0Dqlxr3NaMu3ult71vDqXYa0Co70NszLNDIl2hm4yLnGWsxPS2U6/r5wM1gyNbuSiovHTlJayJeNq6/qlMvgSqVQq+edIj6kbXVwnMxZWiJqWSlWC0O0JpOyQxFjHFVUXiRtQmasFfIMRGhxJeCial7vbvGVtou0pw9gwzRhmvHxg59avtMcCRVFJWCj2l9FTTHhrZOFF57lUOWqrYksfaSieJfNQMtNW0jQGZWsAKkJ6SJhwoFuSlPzvWQZ61dh1oeaFZD3PXS79gutSTzjhgAeopioVQa47jfFk+QzJucgpvrEjpx8EqJwIeFrh+upUsC/3YaCNd2VI8B3rd5opxaQt/l1Ck/ixCniIiA2DLUifb/uQwJVkpNQqpUAvI+ydldl+3bjq0L8AFrP8O18ZmBvhBM0RXQ8+Nmvaqqy3IVIR8q6yEzsdJo9dJj4nEtx7XUGW6qYXUm3MBfSjQkxOC9i3QjzmhinONWX1W8o1CpT5EjkuT2F8olJm8vwv2w2BH6ITYAwv7j2WVq0kVTEpiFQEsrck3lJ1xJR2n0j7lrFDtOgrGdaTI781e6b+ExPtCYrITElM7JLzpkUIitELiKkm2uTeQTfW/ID4IYj84IeLIQnw+jpE3R2G4D8ckgCjx38/xANT8qE/N9T2Lmhseidr0E1EL4wjm6V7UMERpfFZqgbezsfIGcs0doBYdgJqZ91NgS8J5GOyVbLJievF5sYXm2MdgG9gYHatCuu4nojYNJwjvRQ1cWSQn5002FJyP2sDBhNqLSql2htxFK9GxWcrnFTvAehQ0mm13a8l4MJb+AalfK++RGNMr3VGQJKkPvoYipB9DbwiSt50tfSwPd7YqbojsL72hf1C8QyC1TyBci97/tOls4+gQuejvVNDAtcj5A+BMCn8InH2icMYS+q+Bi3bA+XYRPRo4+0wAXcDtvWcJTgVONrtfeuq+rV/T0O0f7VhLk9owDP41ObaTxyZwXR7bHrYnDt0eTSISd52IOubVX185URKygRlmtgudDjAD1ifJsvVJyoATTPP9Fy3W2TdMQDm+m+ydYOb4/tgP6dMChxoIwnENpFomNeR1wEL+BgZdRjcygbJnaBCVkes+GGNRQGx6mNAad32zFap+1LVIYQAsYqGG6HeZmIxRz3U7xVeQacahxyErliJ+TTVuCo7n+MGqetXqXDR7sX2ZiQR3R1Awd4KpRjT1Kt9PQdnUNmmr/Z7OaNtzayjMJQ4+H8McmqtDQplgEbXJMMVCqHmHTqrrgd3AJSkzuaKlR0vYS/NytP5hTT6HViqMPrywRyV0utIIbR4taQQVWECDPUmlWpeksYiVKEsZ1yCb2IA/wZgDV5LYGCSoO/4z4prtSqPxFaaoUFcXDtzq1WoavgNCVlgY3tJ3WT7lWSfRZq5HQ4kbHTMUcBULnQIzEw3J8toSoM4CzIEyRSYalDBy299dcI2nrV3HMy2Y6tO082m2Qm1404wMcFAMfap3mTSwWIvqTjtq/D79bS1bWyWWoCZtNzRZa/l9S8LYvgck+DbpxPGRJbfT5eQIJdPCFg5lGXTL1ha0gf3ZtjnDBDvQQKtdeL61/bw7mhYNlh0Nish9P3kP9569Ts+Gw54d3a5nw0HPKgXZvWcv7dlwfMOejQbkOSO6VKQoxiSR2x6F0a+Nff5P6K7mE6fikSwUrEynpVXK3yK3tBbLcl3JblbbUz6mTQw6YBWm9fmYyHCzyKq2968fGds7f2DY0ezc9v9x+1e5oAB0flmkz5U087rp/a558PDmGe5FJ+aBe2IeeOO/MBBG94FwHwj3gfAvDYRRdMWBQGL3K7/SHf2TEsz/AA==7VhLk9owDP41ObYTEl49Lo9tD9sTh26P3kQk7joRdRwe/fWVE+W1gQ4zzMK0BWbA+vTZsvVZgonjz5P9Zy028VcMQTmeG+4df+F43tQb0acFDiXgj6YlEGkZltCgAVbyFzDoMprLELIO0SAqIzddMMA0hcB0MKE17rq0Napu1I2IoAesAqH66DcZmpjRges2ji8go5hDT0fseBHBa6QxTzme4/nr4lW6E1GtxfwsFiHuWpC/dPy5RjTlKNnPQdnUVmkr5z2e8Nb71pCacyawTpk5VEeHkDLBJmoTY4SpUMsGnRXHA7uAS1ZsEkXDAQ1hL81za/zdUj6OrJUafXjmGYXR+DIjtHmwohGUYgoV9iiVqqeEFSNQIstkUIJMsQF/gDEHvkkiN0hQs/0nxA3zMqPxFeaoUBcH9t3iVXsqvX1C1pgaXtJz2T42s0yizdxJGRjKMNcBszy+2EJHwKxhfQWosgAToEwRRYMSRm67qwu+41HNa3SmAUt9XHYOvRUq50VjImDvMnSl3sXSwGojigPsqPC78td32XKVeAE1q6uhylqt71sRpvbdE8GzSSeNW0wup/PFEUpGqb04pAXoWq0taAP7P+vVV6KaMOT65f42mLK9a3WLqsbjVqMYu5eLN7nX7M1q1u/X7PhKNesfr9nsXrRnFu3w0w2LdthTz5nQocaKYsxCue1IOP6Z2z8AMzqr+cCpeCCGgrVpvDSK+FskVtb0JdsUthuXfMrHvIpBGyzC1HPeJzLcLLIq+d71I2N95ncMO1mcWv4fLv8iFxSA9i/T6KmwFoOmfV/UD/y3P+LekX7gHukHdeO4pCGM7w3hP2gI146c3VvR39iKxpMrtiIymwcMha/1EMdf/gY=7VdNj5swEP01KLeKjyTNHjfstr30lEo9O3gC7hobGdNAf33HYPOxsNJutMkpREH4zdjG770x4EVxXn9XpMh+SgrcC31ae9GTF4YPDz6eDdB0wDqyQKoY7aBgAA7sH1jQpVWMQjlJ1FJyzYopmEghINETjCglz9O0k+TTWQuSwgw4JITP0d+M6syige8PgR/A0sxOvdvYwJEkL6mSlbDzeWF0ao8unBM3ls0vM0LleQRFz14UKyl1d5XXMXBDraOt6/ftjWh/3wqEfk+HsOvwl/DKLv2RUkMi/lcUjlWaglqZG9VEQ25Gxc4CT42slKG2EolmUtjl6MZR2JIAZhrfi/bnjGk4FCQx0TN6BrFM5xxbAV72NJhcTo7A9z2RseRSYUhIASZVK/kCDkR+/Z359RGnF1K5PzHOR5lWCcSl0NZ0oW/b4xHbA3HCWSoQ43BCNveWK1Aa6jf5DnoVsThA5qBVgym2Q+QcbgsjcEY4DzbbOJdlI4dtLUass9N+6EFdvLACL4sdzcR+sgojetCAxfVaRVypfiXVhH8ryphoCznuEmQGJ4j2hjeGJfZoAzmj1Eyz6I2pez5gj/dK2+bZdQZXEHY31zXYLugafoKu65muMWkTdAaTEsX9R1QYau7Velm1Lqh6tWrdzLdm3WuKJZUzQTAfx/FVZcRdCXwMt9tzWZiHormiUH/5U67uel+kd7i+od7bmd6/ZPeKo5mojLBQQ1LZSpanob4Zqtr6oFBQlsYJyaqLtrZoN+C7BS6zQOTf0AJfly3ACe7gmXsrU1Dw9o0MtW69YJTXTQHj4F37z9B+e0Ptd8vaQ82GXd/JO671GOlR0ozkhXvTvot9kdjrK76JY3P4pGtjo8/m6Pk/7ZfbbqMwEIafBvUWMEnT22TbXa1UaaVotdcuDGDF2MgMS7JPvx4wJ9FKVarkCiJF9j9jG883PuCxQ3H+bniZv+oEpBf6ydlj37wwfAo29p+ESydEzO+EzIikk4JROIp/4MTerRYJVDNH1FqiKOdirJWCGGcaN0Y3c7dUy/moJc9gIRxjLpfqH5Fg7tTA90fDDxBZ7obebZzhjcenzOhaufG8kKXt05kL3vfl/KucJ7qZSOzZYwejNXal4nwASaHtw9a1e/nAOry3AYWfaRB2Df5yWbupH0spkOKdA/mpsqZahUaojCZ4oVrJY4uHoBAsIA+uutjzi5sZXvpotvEAGtH32L7JBcKRerBCY9PHajkW0tYCWxwiQr6Sv4HcDzE9aKmNNSmtgFzR6BP0og21v6PfYOnR2ajuUyHlxNNBsbpW6PIv9F192mP7WJ1LkSmrSUhtYPcubGAQzh+GPhiA2nUCugA0FD3XgEUuB9waCfqcaMaMi3otnyTb1mncJXk2dD2CtgXH+n3ubMH9xU459IHHOb2CNklLf0iElewXyO7uSDZakH3lJ+gXKBQlXkac/gORrh5WsFeB3d6R62bB9XdZgol5BcMiTYWpaC+WgAi0nHU62LolvWL+DObHOeYwWnJmTzfivF1w/qnbfXgBtxFIe7WBVp6g7g/rFfYVsJl/R9iPC9i/6spBrSW2R3B7xxr26fUg/grbdzbsm7HdfbSQR5YOLp9esLlKWv5YG3Kmu/jK+oqzObrhddpWx0+01jb5DGbP/wE=7Zldb9owFIZ/DerdlA+ShsvCYJvUXXGx9Wpyk5PEq4mRYwr01+84sUOC6ZRSVqQpIKH4tZ3Y53lPYoeRP1vtvgiyzr/zBNjIc5LdyP888rzJxMFfJexrYexrIRM0qSX3ICzpC2jRNNvQBMpOQ8k5k3TdFWNeFBDLjkaE4Ntus5Sz7lXXJANLWMaE2eoPmshcq67jHCq+As1yfeko0BWPJH7KBN8U+nojz0+rT129IuZcun2Zk4RvW5I/H/kzwbmsj1a7GTAVWhO2ut/ildpm3AIK2aeDV3d4Jmyjp57rgcm9CUY1HVAdnJE/3eZUwnJNYlW7Rfqo5XLFsOTiYTMh1ZaRR2DTJiQzzrjAqoIXoJpKwZ/AiBgpJ1LfpsZEHoMyTSljrZY6pqjzQmr7eI4ut89YfVAnjGYFajHGBbByqucNQsLu1di5DRE0OvAVSLHHJrpDMJnUXbTJ/TCqy9uDZYwv8pZZjEa0SbPmzAdQeKBZnebmW9zowK0nt3B8PW5ji9uvgVtfblfMt8DiJgduPbndXjHfwuH5dj63K+bbrcUNBm49uUVXzLfI4iYGbn25XTHfJkO+nc1tcsV8c10LEyS4ldVFLmTOM14QNj+o0y7IFjTYUflTyZ8CXXowNQUOrK7yAlN+0GcoJRHyTm2721BRW1A18KoNFIlpETNSljSuRd1EXeM3SLnXEMlGcpQO47/nfG2sZfnF0O36xX+DL+ooqtD93QQYab4R8dHrCpxrBrK14rC9IoARSZ+7p38Xecde2lA1lhyEnbvobnmUoMdRDOMIHlM7xxICURqfyh2VNTQm7E5XrGiSVAY7dW/omu4Nt4e3IXzfise8pjKZ7PhWJrthYKfy+BKpbO/pFzhJdCWJc/WuKyeCxCry2KeoSVeQBS2y//pmzSCVlwHsBkEHsBc5FuCxd+JeHV4CsL2JHHkhU1N7xINMHXxbGAnP1qgN7LYH8AZp5CpAODhlgQry4IZeboi6bvDHthv8yb9yg701nZE1lTjNF8WUVkSLRP0miREq6DcCyg2TNwPmXpibtzfmzwjnBOZTC7SLYLZ3slbSz++X89NpP/A9I43H4Uemsb1zuhvS9ZLpGngfmK6evaqeCSASOhwdZFWtyWjZPINTKkp59IjmaVNNi/VGtpZrTtzc7JPBGOct3k4Y41KLNywe/oSt6lp/dPvzPw==7ZtRb5swEIB/Der2BjikyWOTtdukTZqUhz1OLriAanBmnKXZr58NhoDtNiEBqklOpYScwcb33Z2vh+OAdfbymcJt8p1ECDu+G7044JPj+ws/4O9CcKgEIFhUgpimUSXyjoJN+hdJoSuluzRCRedERghm6bYrDEmeo5B1ZJBSsu+e9kRwd9QtjJEm2IQQ69KfacQSKfVc99jwBaVxIodeBLLhEYbPMSW7XI7n+OCpfFXNGaz7kucXCYzIviUC9w5YU0JYdZS9rBEWqq3VVl338Eprc98U5eycC/zqgj8Q71Bzx/LW2KFWRzkhJC5xHbDaJylDmy0MReue8+eyhGWYf/P4YTMlcS6GjwivGqWsCSaUN+UkR+JURskzqoV8ZHch/pqWWvdcLaunFOPWmVKrXE5yJg3Id+X3do/li8shTuOcy0KuGcQbV3LmiDL08qr2vIYJN3VEMsTogZ8iL/BvJUZp5l5tBvuj0SykKGmZy1zKoDTTuOn5iIofSFpmcsCSG5BcE3kmIDez5IYkdzsducCSu4IcCN7P5+aW3JDkJvS5W0vuCnIz8H7kFhq5X5bbhR43ZWa5tNwG87cpudXLqQU3RKCcMDnxPA1c7ggN8CNXX+v4JJnCqaN8SaStZSnSFCdUloYQ38mGLI0iMYzRMLqm08M2zuU6AEZvrvifq2NcGjD6Q2A0FVMUdiiP7kR9SkDAsCjS8C2SbeV03Qj0ViuKtJLXSaW2lBYYlFbLKMKQpX+63Zs0KUf4QVI+8OtVFKDAKMiOhkhe1S5mKR0F3omOGKQxYlpHJdhm2uex1ssvIcG7LLfe2ifozk5762wsbzWVYay3nvZWlVlwobeqHYERvVUv3Aiq1lV7LKxLJT9aTuiqevXmgZKMS3jnLiP8TeRLH7hmKWRIyBKurjgR1k72xUeN9H+SBfMYdToLxuiJDcM4UBdiQzhuFus2ZNVzL4KsF3rWFFU4ocCLsi07lBhpmseOz3t0bwoGU3pj+Z7Hd/lKftTma1o6BuGrlxXOduIqtbJ+fCnn+YSc64DfyavmWEztkR/E4uDrQy3ivTVS/gkzwSx/LMQHS4QVhDtazru2AjFUIcLB7x3EteVwpfouRkVRmk0ZLtSrywW/O4A1p7PMaa7+W2VY+hvTaZvTbAhz0msjd1EkOhXhn0/8prYBuxb0gqrWu0xrgTdWjDBVSpQYcf9tc2+OEpbvBU7rm9aA0ZxWr44cnbYo4VinHcBpgSlBH81p9YLJmuQFwQImJrGleWWaBqZMxw17WUJXA2crIm88ovWVtCgINHymADtERcSwn4Vaeldt3TQktaPR00sd1LP0rtkEaHjMPho9fV+LjZxXRU7Ts/bR6OllKBs5+9FTtyZNGDnrftu+ZyNnr0eurpq1TEhPr+WEvqXXh95CiZyG7Zyj0dOLNtTSu2aPGRhv3XPEw5X6R2TVE/PjD/XA/T8=7VZNc5swEP01TNpLB5CJfW0cpz20Jx/aHhVYgxLBMmLxR399JVi+QpzJtE1OxjNG+3a1kvbt0+CJdX78YmSZfccEtBf6ydETt14YLpdL+++AUwuIaNUCqVFJCwUDsFW/gUGf0VolUE0CCVGTKqdgjEUBMU0waQwepmE71NNVS5nCDNjGUs/RHyqhjNHA9wfHV1BpxkuvInbcy/gxNVgXvJ4Xil3ztO5cdrk4vspkgocRJDaeWBtEakf5cQ3albYrWzvv7oy337eBgl4zYcHboFN3dEhsJdhEQxmmWEi9GdCb5njgEvjWyijXdhjYIRwV/XTwp4itX+ypSBr67IixQIEFdNid0poTQZF0EbGWVaXiFuQQl+YBiE7cLbImtNCwxW+IZb+cwUdYo0bTHEr4zdN7Ok6FRXZYEKcMfbafm9kWylXnbKkZqrA2MUeF3LzSpMBRoqfZqgcwBzInG2JAS1L7aXbJfZz2cQOXdsB0Pk8tL72XuuakFUFZfVh8nHE+ZfSQKYJtKZszHKy+pyz3LetitbwHfdM3fVe4nuKnPKzcb8ZD6OpuaR5Fsmpez4/UKi1c71g6wPSE7cEQHF+mbE4GT1hcs0z5GgsWbB9Gl0IXk43ugw77F/6uL9J8U2mKuTSjd5KmOCdNL7Rz/aB9XdkzXl3E+rdiDd9TrNHLjIYXRv8Do+INGbXm8NXV+EZftmLzBw==7Zpbb5swFIB/DeqrwSGXxyVLt0rbXjKpzy444NXYmXGWdL9+trEJxLTNIpKoEqkUmWMb8PnOrUcJ4KLYfxFok3/nKaZBBNJ9AD8HUTSZTNS3FrxUAhhPK0EmSFqJwoNgRf5iKwRWuiUpLlsLJedUkk1bmHDGcCJbMiQE37WXrTltP3WDMuwJVgmivvSRpDK30hCAw8RXTLLcPnoa24knlDxngm+ZfV4QwbX5VNMFcvey68scpXzXEMFlABeCc1mNiv0CU61ap7Zq3/0rs/V7C8zkKRuiasMfRLf26My+mHxxyjDHwXoDCOB8lxOJVxuU6Nmdoq9kuSyougrVsD6QXkvRE6bzWiULTrlQU4wzrJdKwZ+xEypNgan+q2ec5pVS5mtCaWOl1amScyat+USxvW7e0XyUHFGSMSVLlF6wmpzbc2Mh8f5V3YU1EWXomBdYihe1xG2YWIjWyCNnHbuGyTjQecNaxlaGrJVm9a0PpNTAwuoGBz1wyuoHdCeig+CG6EYeup9cIr3CBK5jhuqU8ghUS/sWSVPNVuRpTuuMqCj3yU4UJE31Yzoto207/2EcDbDhW2DNOnvOqAeo4SxuQx2PPKiTDqZRD0xjj+liK8yLG6oD1LM9NQTvQq3Tct9Uxx7VUiIihjB7IrwRvGGYnXjwVlIQlpl6UOjicfDQPjx0BI/C7qQDcnghD515kINoTDW4JzXI9ODh3onUzWqpow6IyrgA/96aBCy5+vqwFXAYneDfFK9lP94dz9737s6EC3sA7wyqQf6HhldwgfUrcPHs4JoTR+qO4Ne2NO6O5VYMlE+jPD5OwLCDcnwpyuFp/g26XJxilqk3jABX/32DO5O67waP79Pjx9f0eL9X8YhNv8d8a8eWuR5iljroqA7zyAgZxqmDTnlWbzmUAh+6wLt1aJhdMzT4HZAHlghcNEo6kCid6xrM8VdFGK1iAd6UOhagDJHB+8/DDaNr4va7Jl4mWH5bLbtrvYHvGdEdxteM7n4H5dxMb0J4eaj+ytLEecT0AnGc+48TwAduo946HkyvGQ/83synNLUpX0V2eOcAV4WfifalbQAMeE/Be9S8GYUdeOGl8PrdmyHcX9Z9R6Nruu/0DfctDZzBfft134623OXc1+/LLYbSuz9fjbtabT35qro8/P7AzDV+4wGX/wA=7ZfLbtswEEW/RttCj8R1lrXyaBfd1AW6pqWRRJgPgaJiu1/fGYq0pMgBjATNKjZgi5fDoch7hrKjLJfHJ8Pa5qcuQURpXB6j7D5K07ssxU8SToNwk8WDUBteDlIyClv+F7wYwnpeQjcLtFoLy9u5WGiloLAzjRmjD/OwSov5rC2rYSFsCyaW6h9e2sarSRyPHd+B142fen3rO3as2NdG98rPF6VZ5V5Dt2Qhl4/vGlbqw0TKHqIsN1rb4UoecxC0tWHbhnGPr/Se79uAstcM8D49M9H7pf+Cojcd1wrl37yN0pXATJuuZaisancdRMw71f2S7Clso4Uj6Y2VAoWEhlqj95BroQ0qSiuM3FRciBcSE7xW2CxwHYD65hmM5WjQN98heVnSNJtDwy1sW1bQnAekETVnANASY5oz7DE1BNuB2JxdenknWllPYxr7dghBK2P3CnF+nX7P6Qbh+KoNydlcrBnQEqw5YYgfkAUefL2sffMwgS8g1ky4C8OY570+Zx49xwtv+2UEsgUCj7zuDaCme0uV14Aj20mSKy57SavjUGCNYlRF2VSlDeI9gGM1fhhoDXS0A7gu3RsaY/ROgFyAMjfskqVThq73c44bObim97knFHf6gsKxbK9nIiAroBqL4X1UJHMqkmSJxc3dBSy+rt6Pxc0Ci7yBYj/hoaOvAr++4AHAJLmkdl3r1h7/6IZIBw1TtKqDNjTc7Y9HpNRR9kjRhJDCQy/NHTi2N+oTkjdBkq7Sj4PkdgHJE38GZyHrtGJY7OQyVKwXtguuX32gfCLwtnNivfo4BFYLBO7J4w4z+Zq/dDzkzCXxj4WqV4V/crCacTUcA5Ltuaop1/A0GrBhpu4lbgyB0jAHW9EwVSMVBM04dcW6xuX8ZOgNDGXZ+r8xhM3xF67rm/yLyB7+AQ==7VpNc5swEP01jNsbIOOPY+ymH4fOdCaHHjsyyKCJkFwhB6e/visQGBCp7QQ70xmcGIu30kra91bIShy0Tg9fJN4l30VEmOO70cFBnxzfn8/ncNXAcwmgYFECsaRRCXlH4IH+IQZ0DbqnEclaFZUQTNFdGwwF5yRULQxLKfJ2ta1g7V53OCYW8BBiZqM/aaQSg3quezR8JTROTNeLwBg2OHyMpdhz05/jo23xKs0prnyZ+lmCI5E3IHTvoLUUQpWl9LAmTIe2ClvZ7vML1nrcknB1TgO/bPCE2Z7UIzZDU89VOIoJEd3EddAqT6giDzscamsO/AOWqJTBnQfFekq6LsMbwlZ1UNaCCQkmLjjRVZUUj6QCoWd3oX9qSxV7CMtqSxlr1DRRBVxwZQTku+a+6bF4AY4ZjTlgIUSGgHFlZk6kIocXo+fVnIDUiUiJks9QxTTw54ZGI3OvkkF+FM3CQElDLjODYSPTuPZ8pAoKhq1+5tDI3IDM1SvPDZibjswNydz8dswFI3NvYA4F75dzs5G5IZm7Yc7NR+bewNwUvR9zC4u5XyNvr8y4W+4slyNvg+XbLXmrHqcjcUMslDfcnHieRRx3dASg5NrPOpik6vDUCr5hpBllA1mB0yGjIWZ3xpDSKNLd9AqjLZ0LtHEurwPQ6M06+efaNC57aPSHoLHvMKXDHeHRnT6f0iQwnGU0/BeTzeC00whdHFYSWUdeJ4PaCFrQE7QKk4RhRZ/a7vsiaXr4ISh0/PIpCuqQkYm9DIlp1TzM6jgKvBOOFJYxUZajgth62udxbR+/hILtUz5m6yWL7vR0tk6vla19xzBjtp7O1i5nwSuztesIXTFb7YMbzeqYqhc8WJed/dHyhqlqn95828L9h4LEYp9U/vou/wgXlRC9f8qJHgt+Kj6oKg06t3gEV6E9gFR1FKTYMJJaevhP9sqwkp3eKzOyVcMoIeh+NfVtJaB5jxTmA0gB2c/dQgols5NMYSonBYuS8rjgP9NdwpsRHsP4OnrpyAWioK+9YtFO+paNUSZnyaRnwbieTOyHe0Mmjj9jepYUCrEuVNIoYXBeW+ATp5pCvsn0hzh6KbTWlBrNCpVlWVEFa00JXYH83mM9OCXqtuXCxffphshCepNCd7mQj6UvAa3XtSijyMgPpI0mpUWAJ5nTrF0hK4Q3KvQ1Cq2/y19BoXB7/KN+uYM5/uMEuv8L7Ztdb5swFIZ/Dep2BzikyWWTpdukTZqUi11OLjhg1eDIOF/79bODIYDJklDiqpLbKiLHH8TnOa85PRAHzNP9VwbXyU8aIeL4brR3wBfH9yd+IF6l4VAYQDApDDHDUWHyToYl/ouU0VXWDY5Q3ujIKSUcr5vGkGYZCnnDBhmju2a3FSXNs65hjDTDMoREt/7GEU+U1XPdU8M3hONEnXoSqIYXGL7GjG4ydT7HB6vjT9GcwnIu1T9PYER3NRNYOGDOKOXFUbqfIyJdW7qtGPd8prX63Axl/JoBfjFgC8lGLf2P+mD8UDrjuBwkB7gOmO0SzNFyDUPZuhP0hS3hKRHvPHFYLUj2JfAFkVnlkjkllImmjGZIduWMvqLSKDzlTuRv1VJ6XjhltsKE1Hoqnwo7zbgKH99V7+szHn+EHRIcZ8IWCr8g0ThT60aMo/1Z33kVERHoiKaIs4Poogb4jwqiCnKvDILdKWQmypTUgmWsbFAFaVzNfAIlDhSrbm5A4+aUNkvuIrnAa5Kr9h0D5EaW3ICaq94bIBdYcm8gB4L309zYkhuSnEHNPVpybyA3Au9HbmIzy8EUZzKznFrFDag4k+TKC6pFN8xmaTBB8TwNXeZID4gjV0coFslbnBrOV0TqXlYmzXHSZTiE5Ek1pDiK5Gk6A6MZOjfExrVcB8DojVsKdHWM0w6M/hAY9XKKxg5l0ZOsUEkIBOY5Dv9Hsu6cpozAzW5FkVb0uujUmtOCDqeVNoYI5HjbnL7Lk+oMvygWJz5fSQEtGDndsBCpUfVyVmui9j/22kQcshhxbaIj2GrZ17HWSzAhJZs0s2q9ZdMdXVbr6F5q7SrFWLVeVmubWdBTre2JwB3VqhdvJFUr1RsurNNWfjQ1KFW9gvPMaCosYnKXU/Ei86VPwrMMciRtiXBXnMhop7v8s0b6g2TBYo+6nAUTtOLDMB5PL2/H1cW6Drmt3F6Q9WLPnKECJ5R4UbrmhyNGhrPY8cWM7gNBW0QeLN+r+D6ey4/qfLsuHYPw1UtCbRE74Fn9CTEX6ZTVbl+2Y5Nsu8pGYyKX9iIOYnnwXVItrWLCqoEnUuJl9uzmCd2QSH5IuD1q/zjswxYyTIdBuwLVcZmukNfDYDRAGJTX+loYPEWRYig2afBQKt3u2zdBbd+C6dq3vTtp29eLU5q2Fz+Wiy5pW769ROt37d13E61etTqJNj/CsaIdQLSgK5m+m2j18tScZjklEiahsaSZc4iZpdkvvQImU2egS9TeTe37tJfR5/R0GVpwV4NrVyNMgtMLhhZc76f0DN5KBXqp0ILrqzij4OyzXoM+02zwWS+gV/Ysujeo7n7oHFlyLb9cUtxHO32BByz+AQ==7Z3Pl5owEMf/Go59j19B9li32/bSXvbQYx9CVN5G4mNj1f71DRpQCPuqMA6XcQ+LkyAyn0wy+RLQCZ43h29lsl3/kBkXju9mByf44vi+5wex/ldZjmcLC2Znw6rMM1PpYnjN/3JjdI11l2f8vVVRSSlUvm0bU1kUPFUtW1KWct+utpSifdRtsuKW4TVNhG39lWdqbaye614KvvN8tTaHjpkpWCTp26qUu8Icz/GD5el1Lt4k9WeZ+u/rJJP7K1Pw4gTPpZTqvLU5PHNR+bZ223m/rx+UNt+75IW6ZQf/vMOfROzMqf82X0wda2ecTodXO7hOMN+vc8Vft0lale41fm1bq43Q7zy92ZxQVVckCy7mjUuepZClLipkwauqqpRvvDZqT8X+IoiipqT2vHbKfJkLcVUzYzzOwsouC2Waj++a91f13NNL2xORrwptS7VfuC6cm/PmpeKHD33nNUR0S+dyw1V51FXMDsHMQDSNPKhbx/7SZGJjWl81lsjYEtNIV80nX0DpDcOqn1tgcXNq2xTkojTmi+VN5BIeL9OJyUVeh1yERy4kcoAxF/p45BiRG0EuZNPFXETkAMlhxtyMyI0gx4LpyMWUWcL1lYiZ5RNFHGDEYZKrk1pCB4MOMUHxPOot4WZzmDFHAsoIcE8TgrMVFAI3WPnC7CptAYXADY44THCkn0COcphzOY8EFMioQ0Vnz8MJ3fCo8zw8dHUrIXSD0HVFFFR0lF3CgWOI3OjqHKSEgkmOsktIcqidpZ1dUmc5NEFBDLmAtK8REkrc4RYjgqPVQ6NCzm+ji0JEdJSgQEbdDHPJHmUoo2YF0YRRR/oXJDrUqKMVRKPmBeGE6GgJEVzMoeaXtIYIMuYw0dWHJnQg6DCTlJDWEMHN6VBjjnSU4eCahGQKcHSVB24qjtpV0hoiuIhDBUcaCuQohzmbC0lDgYw6VHSkoYwa6broMO82puVfoNcLMNGRigIqOiOiqy/CE7pB6CzRGROdraIQuhEZJiY6W0chdCMyTEx0tCJlFLoJ0xRGWgocOEz1ktlaCoEbCg5TBGO0Xhawq0TUUZitoxC4oSoKaldJK1HgwKF2lbaGQuAG65aIXWX9GVfgfjqVB/SW61sI9UmqDqeW8w2Ray8bk+W4ymV5mojPpmCTZ1l1mN6G0W46d7SNW7lCYOzeB9mDcdaD0YfAaKspF4z2/I4wfozR7yQuzTM4MDDaysoFY0gY78HYuV+reTYABsY+laXDTnttW22mu1Ic56X2GFf/HxUvnh87Rrpx9XfLGGmeq33/GCn4Up2+s0pULivLpycguqyeVNdDJrPgBn1wQwi6thBDPex998C24fk998A+LDT7FrZQaD4wNPseNtYXm6ELgdeWbBjF5ojYZJ7dsz4sNvsuxFNsQsZm1KHbk9v2xSYDecS0PdWcUWzedbm+TS9+3MxEv738Nsqp7OoHaIKXfw==7ZlNl5sgFIZ/jXsFtc6ySaftpqssumaUKGdQchhSk/76gl6/gunpjMZuSM7JkfdeRN7nqmg8vC8v3yQ5FT9ERrmH/Ozi4S8eQgmK9K8Rrq2Ao6QVcsmyVgoG4cB+UxB9UM8so2+TRCUEV+w0FVNRVTRVE41IKepp2lHw6agnklNLOKSE2+pPlqkC1MD3h8B3yvIChk4iCLyQ9DWX4lzBeB7Cx+bThkvS7Qvy3wqSiXok4WcP76UQqt0qL3vKjbWdbW2/r3ei/XFLWql/6RC2HX4RfqbdETfHpa6dF81sqMn3PbyrC6bo4URSE601fK0VquS6FejNfj4ml5MXyne9I3vBhdShSlTUpCopXmknaqP8xHz7SGe89mR3ZJyPMsFSrYtKQfUgH9rjPTYfrRPO8kprqbaF6uAOpk2lope71gU9EF3nVJRUyatOgQ44AYZQ40EI7XqoGNwVTDEqFhSDSKBK837fAym9AbDmwSEH7qPgQv8GXGyD6xmNwa3BLXLc1uKGZk64h3GLHbe1uGG0IbfE4hZY4PTU1A2dieXAYewtSJZdxiim1xGfIVCyLDPDzJbDtGDeUREjmvhvNNeAh24ulokNL5y7ya3A7sliZ590jt19dlHw/9h1Q4/gYQfvHfDi21XKlvACC17o4C2Ah2aWmA+DZz8aRA7eAnh4Zp35MHjYghc7eAvueZvCs9+mfHLwFiw2N4VnP5knDt4CeJve8+zH8ycHb8Fl84HwdHN4v93ERv8h4Oc/7ZtZj6M4EIB/DZqdlxZgyPGYo+eQZler7Yd9HDngBDQGR8aZdO+vX9vYBDDpHBBGu3IiJVA2Zaivyi6KxAGr7PUzhfvkdxIj7Phu/OqAteP787nLP4XgrRQEQAl2NI1LkXcSvKT/ICXU3Q5pjIpGR0YIZum+KYxInqOINWSQUnJsdtsS3Bx1D3fIELxEEJvSv9OYJUrque6p4QtKd4kaehaqhg2MfuwoOeRqPMcHW/kqmzOodan+RQJjcqyJwLMDVpQQVm5lryuEhWm12crjPp1prc6bopxdc4BfHvAT4gPSZyzPi71pW8irQaK/64DlMUkZetnDSLQeOXwuS1iG+Z7HN6vrEX0x3CC8rCyyIphQ3pSTHImujJIfSAu5odyZeFct2vDcJsttinGtpzIpl5OcKe/xXbVf1yhfXA5xusu5LOJmQbxxqS4bUYZez5rOq4BwP0ckQ4y+8S76AO3kyse9qdo/njwGaIdJas7iT5QQKi/dVbpPpPiGgtUNDlhw94KrZpm3FsgauIpRHdwQ3ALLbShufkfAPYxbaLkNxQ2EI3KbGNw8Axy/NNai0zC54lC3rRIZ5hKGSnkesVANWRrHYphOd2g6zA0eUaMJ3qM5BDzQCjrPhBd0LXIDsJsa7Mygs+zOswP+r2M3M9gBy+4GdkF7sRuR3dxgF1h2fdh1JJiPYqeHrsELLbwe8EBHlvkweJ4Bb2Lh9VjxRoVn1lKmFl6PVHNUeGY9ZWbh9blPGHPNM4sqcwuvz43CmPCuqKygPF6Iqv7JODEsEmlU7z2m3ExLV7yNWgloGph70CUDo9h4ZHDRvDXzhR3m0zKKMGTpz6b6LpuqEf4kKR/4RK8VekHYwlKQA42QOsqvPQy4oMgLWooYpDvEDEUScXXZ11E36zKW+m3Uwxb1ILyTekuRB8KHUTcrOpb6TdSDyZmZ+lbqXnhB0YDUzVqQpX4b9RYsoAsyN1MPLigakLpZRXrh2sXJcASHLHfEg4j1/6saf4WX9cuyZ01+czVVj5CnaR01ns95bGn2Sbvb+ZY7Xtrtm6UmHZ5/cUtJmvzTAr0FaOsXIVW0jsHTrD6V4VnRtChvQTltL5QjojRrUYuC72OS70rVvvtboYI1qmZffwIzYV0smJbRi6QHlF0+Vh3yTbGXRprIrhu+sRMbiz/WpZ5Sg/+paqlGo6UznR2Kt3803Ow/8ruIdz1KOzxGWzaMg4XtXyFNO9byLhcDQ7iYWTH7RsieS7aUZBJfy70YafmTxXwd5nZd1O3A7D8Ks1lbW1EEGRJ6JcmDnL9FD5rCDUfprzT9tJxtWGcWYGFfFdPBmDFtltQWcs5GxQGzwgmXEut3MYeHa76bii8xZiHs0O0NFvs12NtFGWBiB/NHYTdralWMo2zPxHlCSqH4Jlu9I3IInq5hJCb0D8pFPlje94W5N2aYm9W0r3lEUYZyVg9iS/KeyJ2MGblmhaw7CSuz7loGJgUW8B3pF/BHTL+0jvMrclquxJzqd5VV2yX5IYENwhEDG5i1NTtFD0ZyNiZJs6r29PRE0R7J+6ItEaFJWCJDlB3FDF3Ify5atvfMzkHX/dLDZmezBlKP0sbia2neU+roejr1MJpmqWONTjRt5ap/cHbd5QyEk++e/vNcPmw+/a8cPP8L
\ No newline at end of file
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/04/.gitkeep b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/04/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/04/diagrams.xml b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/04/diagrams.xml
new file mode 100644
index 0000000..2224edd
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/04/diagrams.xml
@@ -0,0 +1 @@
+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
\ No newline at end of file
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/05/.gitkeep b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/05/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/05/diagrams.xml b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/05/diagrams.xml
new file mode 100644
index 0000000..ce1f41b
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/05/diagrams.xml
@@ -0,0 +1 @@
+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
\ No newline at end of file
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/06/.gitkeep b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/06/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/06/diagrams.xml b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/06/diagrams.xml
new file mode 100644
index 0000000..d593c22
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/06/diagrams.xml
@@ -0,0 +1 @@
+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
\ No newline at end of file
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/07/.gitkeep b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/07/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/07/diagrams.xml b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/07/diagrams.xml
new file mode 100644
index 0000000..15b0902
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/07/diagrams.xml
@@ -0,0 +1 @@
+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
\ No newline at end of file
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/08/.gitkeep b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/08/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/08/diagrams.xml b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/08/diagrams.xml
new file mode 100644
index 0000000..c461e6e
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/08/diagrams.xml
@@ -0,0 +1 @@
+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
\ No newline at end of file
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/09/.gitkeep b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/09/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/09/diagrams.xml b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/09/diagrams.xml
new file mode 100644
index 0000000..657f03c
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/09/diagrams.xml
@@ -0,0 +1 @@
+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
\ No newline at end of file
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/10/.gitkeep b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/10/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/10/diagrams.xml b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/10/diagrams.xml
new file mode 100644
index 0000000..0273620
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/diagrams/10/diagrams.xml
@@ -0,0 +1 @@
+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
\ No newline at end of file
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/anagrams/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/anagrams/index.js
new file mode 100644
index 0000000..f57259d
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/anagrams/index.js
@@ -0,0 +1,48 @@
+// --- Directions
+// Check to see if two provided strings are anagrams of eachother.
+// One string is an anagram of another if it uses the same characters
+// in the same quantity. Only consider characters, not spaces
+// or punctuation. Consider capital letters to be the same as lower case
+// --- Examples
+// anagrams('rail safety', 'fairy tales') --> True
+// anagrams('RAIL! SAFETY!', 'fairy tales') --> True
+// anagrams('Hi there', 'Bye there') --> False
+
+// function anagrams(stringA, stringB) {
+// const aCharMap = buildCharMap(stringA);
+// const bCharMap = buildCharMap(stringB);
+
+// if(Object.keys(aCharMap).length !== Object.keys(bCharMap).length) {
+// return false;
+// }
+
+// for (let char in aCharMap) {
+// if (aCharMap[char] !== bCharMap[char]){
+// return false;
+// }
+// }
+
+// return true;
+// }
+
+
+// function buildCharMap(str){
+// const charMap = {};
+
+// for (let char of str.replace(/[^\w]/g, "").toLowerCase()) {
+// charMap[char] = charMap[char] + 1 || 1;
+// }
+// return charMap;
+// }
+
+function anagrams(stringA, stringB){
+ return cleanString(stringA) === cleanString(stringB);
+}
+
+function cleanString(str){
+ return str.replace(/[^\w]/g, "").toLowerCase().split("").sort().join("");
+}
+
+
+
+module.exports = anagrams;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/anagrams/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/anagrams/test.js
new file mode 100644
index 0000000..60f117b
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/anagrams/test.js
@@ -0,0 +1,27 @@
+const anagrams = require('./index.js');
+
+test('anagrams function exists', () => {
+ expect(typeof anagrams).toEqual('function');
+});
+
+test('"hello" is an anagram of "llohe"', () => {
+ expect(anagrams('hello', 'llohe')).toBeTruthy();
+});
+
+test('"Whoa! Hi!" is an anagram of "Hi! Whoa!"', () => {
+ expect(anagrams('Whoa! Hi!', 'Hi! Whoa!')).toBeTruthy();
+});
+
+test('"One One" is not an anagram of "Two two two"', () => {
+ expect(anagrams('One One', 'Two two two')).toBeFalsy();
+});
+
+test('"One one" is not an anagram of "One one c"', () => {
+ expect(anagrams('One one', 'One one c')).toBeFalsy();
+});
+
+test('"A tree, a life, a bench" is not an anagram of "A tree, a fence, a yard"', () => {
+ expect(
+ anagrams('A tree, a life, a bench', 'A tree, a fence, a yard')
+ ).toBeFalsy();
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/bst/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/bst/index.js
new file mode 100644
index 0000000..ceec26c
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/bst/index.js
@@ -0,0 +1,52 @@
+// --- Directions
+// 1) Implement the Node class to create
+// a binary search tree. The constructor
+// should initialize values 'data', 'left',
+// and 'right'.
+// 2) Implement the 'insert' method for the
+// Node class. Insert should accept an argument
+// 'data', then create an insert a new node
+// at the appropriate location in the tree.
+// 3) Implement the 'contains' method for the Node
+// class. Contains should accept a 'data' argument
+// and return the Node in the tree with the same value.
+
+class Node {
+ constructor(data) {
+ this.data = data;
+ this.left = null;
+ this.right = null;
+ }
+
+ insert(data){
+ // handle less than current node w. left child
+ if(data < this.data && this.left){
+ this.left.insert(data)
+ // handle less than current node w/o left
+ } else if (data < this.data) {
+ this.left = new Node(data)
+
+ // handle greater than current node w. right child
+ }else if(data > this.data && this.right) {
+ this.right.insert(data);
+ // handle greater than current node w/o right
+ } else if(data > this.data){
+ this.right = new Node(data)
+ }
+ }
+
+ contains(data){
+ if(this.data === data){
+ return this;
+ }
+
+ if (this.data < data && this.right){
+ return this.right.contains(data);
+ } else if (this.data > data && this.left){
+ return this.left.contains(data)
+ }
+ return null;
+ }
+}
+
+module.exports = Node;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/bst/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/bst/test.js
new file mode 100644
index 0000000..331ae22
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/bst/test.js
@@ -0,0 +1,41 @@
+const Node = require('./index');
+
+test('Node is a constructor', () => {
+ expect(typeof Node.prototype.constructor).toEqual('function');
+});
+
+test('Node can insert correctly', () => {
+ const node = new Node(10);
+ node.insert(5);
+ node.insert(15);
+ node.insert(17);
+
+ expect(node.left.data).toEqual(5);
+ expect(node.right.data).toEqual(15);
+ expect(node.right.right.data).toEqual(17);
+});
+
+test('Contains returns node with the same data', () => {
+ const node = new Node(10);
+ node.insert(5);
+ node.insert(15);
+ node.insert(20);
+ node.insert(0);
+ node.insert(-5);
+ node.insert(3);
+
+ const three = node.left.left.right;
+ expect(node.contains(3)).toEqual(three);
+});
+
+test('Contains returns null if value not found', () => {
+ const node = new Node(10);
+ node.insert(5);
+ node.insert(15);
+ node.insert(20);
+ node.insert(0);
+ node.insert(-5);
+ node.insert(3);
+
+ expect(node.contains(9999)).toEqual(null);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/capitalize/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/capitalize/index.js
new file mode 100644
index 0000000..c3b36b6
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/capitalize/index.js
@@ -0,0 +1,39 @@
+// --- Directions
+// Write a function that accepts a string. The function should
+// capitalize the first letter of each word in the string then
+// return the capitalized string.
+// --- Examples
+// capitalize('a short sentence') --> 'A Short Sentence'
+// capitalize('a lazy fox') --> 'A Lazy Fox'
+// capitalize('look, it is working!') --> 'Look, It Is Working!'
+
+// function capitalize(str) {
+// const words = [];
+
+// for (let word of str.split(' ')) {
+// words.push(word[0].toUpperCase() + word.slice(1));
+// }
+
+// return words.join(' ');
+// }
+
+
+function capitalize(str){
+
+ let result = str[0].toUpperCase();
+
+ for (let i = 1; i < str.length; i++) {
+ if(str[i - 1] === ' '){
+ result += str[i].toUpperCase();
+ } else {
+ result += str[i]
+ }
+ }
+ return result;
+}
+
+
+
+
+
+module.exports = capitalize;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/capitalize/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/capitalize/test.js
new file mode 100644
index 0000000..21a2423
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/capitalize/test.js
@@ -0,0 +1,17 @@
+const capitalize = require('./index');
+
+test('Capitalize is a function', () => {
+ expect(typeof capitalize).toEqual('function');
+});
+
+test('capitalizes the first letter of every word in a sentence', () => {
+ expect(capitalize('hi there, how is it going?')).toEqual(
+ 'Hi There, How Is It Going?'
+ );
+});
+
+test('capitalizes the first letter', () => {
+ expect(capitalize('i love breakfast at bill miller bbq')).toEqual(
+ 'I Love Breakfast At Bill Miller Bbq'
+ );
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/chunk/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/chunk/index.js
new file mode 100644
index 0000000..e98891b
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/chunk/index.js
@@ -0,0 +1,39 @@
+// --- Directions
+// Given an array and chunk size, divide the array into many subarrays
+// where each subarray is of length size
+// --- Examples
+// chunk([1, 2, 3, 4], 2) --> [[ 1, 2], [3, 4]]
+// chunk([1, 2, 3, 4, 5], 2) --> [[ 1, 2], [3, 4], [5]]
+// chunk([1, 2, 3, 4, 5, 6, 7, 8], 3) --> [[ 1, 2, 3], [4, 5, 6], [7, 8]]
+// chunk([1, 2, 3, 4, 5], 4) --> [[ 1, 2, 3, 4], [5]]
+// chunk([1, 2, 3, 4, 5], 10) --> [[ 1, 2, 3, 4, 5]]
+
+// function chunk(array, size) {
+// const chunked = [];
+
+// for(let element of array) {
+// const last = chunked[chunked.length - 1];
+
+// if(!last || last.length === size) {
+// chunked.push([element]);
+// } else {
+// last.push(element);
+// }
+// }
+
+// return chunked;
+// }
+
+
+function chunk(array, size) {
+ const chunked = [];
+ let index = 0;
+
+ while (index < array.length) {
+ chunked.push(array.slice(index, index + size));
+ index += size;
+ }
+ return chunked;
+}
+
+module.exports = chunk;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/chunk/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/chunk/test.js
new file mode 100644
index 0000000..ef3d645
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/chunk/test.js
@@ -0,0 +1,33 @@
+const chunk = require('./index');
+
+test('function chunk exists', () => {
+ expect(typeof chunk).toEqual('function');
+});
+
+test('chunk divides an array of 10 elements with chunk size 2', () => {
+ const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ const chunked = chunk(arr, 2);
+
+ expect(chunked).toEqual([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]);
+});
+
+test('chunk divides an array of 3 elements with chunk size 1', () => {
+ const arr = [1, 2, 3];
+ const chunked = chunk(arr, 1);
+
+ expect(chunked).toEqual([[1], [2], [3]]);
+});
+
+test('chunk divides an array of 5 elements with chunk size 3', () => {
+ const arr = [1, 2, 3, 4, 5];
+ const chunked = chunk(arr, 3);
+
+ expect(chunked).toEqual([[1, 2, 3], [4, 5]]);
+});
+
+test('chunk divides an array of 13 elements with chunk size 5', () => {
+ const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
+ const chunked = chunk(arr, 5);
+
+ expect(chunked).toEqual([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13]]);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/circular/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/circular/index.js
new file mode 100644
index 0000000..15e4cb7
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/circular/index.js
@@ -0,0 +1,31 @@
+// --- Directions
+// Given a linked list, return true if the list
+// is circular, false if it is not.
+// --- Examples
+// const l = new List();
+// const a = new Node('a');
+// const b = new Node('b');
+// const c = new Node('c');
+// l.head = a;
+// a.next = b;
+// b.next = c;
+// c.next = b;
+// circular(l) // true
+
+function circular(list) {
+ let slow = list.getFirst();
+ let fast = list.getFirst();
+
+ while(fast && fast.next && fast.next.next){
+ slow = slow.next;
+ fast = fast.next.next;
+
+ if(slow === fast){
+ return true;
+ }
+ }
+
+ return false;
+}
+
+module.exports = circular;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/circular/linkedlist.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/circular/linkedlist.js
new file mode 100644
index 0000000..b7da56b
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/circular/linkedlist.js
@@ -0,0 +1,178 @@
+class Node {
+ constructor(data, next = null) {
+ this.data = data;
+ this.next = next;
+ }
+}
+
+class LinkedList {
+ constructor(values = []) {
+ this.head = null;
+
+ for (let value of values) {
+ this.insertLast(value);
+ }
+ }
+
+ clear() {
+ this.head = null;
+ }
+
+ size() {
+ let counter = 0;
+ let node = this.head;
+
+ while (node) {
+ counter++;
+ node = node.next;
+ }
+
+ return counter;
+ }
+
+ getAt(index) {
+ if (!this.head) {
+ return null;
+ }
+
+ let counter = 0;
+ let node = this.head;
+ while (node) {
+ if (counter === index) {
+ return node;
+ }
+ node = node.next;
+ counter++;
+ }
+ return null;
+ }
+
+ insertAt(data, index) {
+ if (!this.head) {
+ this.head = new Node(data);
+ return;
+ }
+
+ if (index === 0) {
+ this.head = new Node(data, this.head);
+ return;
+ }
+
+ let counter = 1;
+ let previous = this.head;
+ let node = this.head.next;
+ while (node) {
+ if (counter === index) {
+ previous.next = new Node(data, node);
+ return;
+ }
+ previous = node;
+ node = node.next;
+ counter++;
+ }
+
+ previous.next = new Node(data, node);
+ }
+
+ removeFirst() {
+ if (!this.head) {
+ return;
+ }
+
+ this.head = this.head.next;
+ }
+
+ removeLast() {
+ if (!this.head) {
+ return;
+ }
+
+ if (!this.head.next) {
+ this.head = null;
+ return;
+ }
+
+ let previous = this.head;
+ let node = this.head.next;
+ while (node.next) {
+ previous = node;
+ node = node.next;
+ }
+ previous.next = null;
+ }
+
+ removeAt(index) {
+ if (!this.head) {
+ return;
+ }
+
+ let counter = 0;
+ let node = this.head;
+ while (node) {
+ if (counter === index - 1) {
+ if (node.next) {
+ return (node.next = node.next.next);
+ } else {
+ return (node.next = null);
+ }
+ }
+ node = node.next;
+ counter++;
+ }
+ }
+
+ getFirst() {
+ return this.head;
+ }
+
+ insertFirst(data) {
+ this.head = new Node(data, this.getFirst());
+ }
+
+ getLast() {
+ if (!this.head) {
+ return null;
+ }
+
+ let node = this.head;
+ while (node.next) {
+ node = node.next;
+ }
+
+ return node;
+ }
+
+ insertLast(data) {
+ const last = this.getLast();
+
+ if (last) {
+ last.next = new Node(data);
+ return last.next;
+ } else {
+ this.head = new Node(data);
+ return this.head;
+ }
+ }
+
+ forEach(fn) {
+ if (!this.head) {
+ return null;
+ }
+
+ let node = this.head;
+ while (node) {
+ fn(node);
+ node = node.next;
+ }
+ }
+
+ *[Symbol.iterator]() {
+ let node = this.head;
+ while (node) {
+ yield node;
+ node = node.next;
+ }
+ }
+}
+
+module.exports = { Node, LinkedList };
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/circular/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/circular/test.js
new file mode 100644
index 0000000..7cb50b2
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/circular/test.js
@@ -0,0 +1,50 @@
+const circular = require('./index');
+const L = require('./linkedlist');
+const List = L.LinkedList;
+const Node = L.Node;
+
+test('circular', () => {
+ expect(typeof circular).toEqual('function');
+});
+
+test('circular detects circular linked lists', () => {
+ const l = new List();
+ const a = new Node('a');
+ const b = new Node('b');
+ const c = new Node('c');
+
+ l.head = a;
+ a.next = b;
+ b.next = c;
+ c.next = b;
+
+ expect(circular(l)).toEqual(true);
+});
+
+test('circular detects circular linked lists linked at the head', () => {
+ const l = new List();
+ const a = new Node('a');
+ const b = new Node('b');
+ const c = new Node('c');
+
+ l.head = a;
+ a.next = b;
+ b.next = c;
+ c.next = a;
+
+ expect(circular(l)).toEqual(true);
+});
+
+test('circular detects non-circular linked lists', () => {
+ const l = new List();
+ const a = new Node('a');
+ const b = new Node('b');
+ const c = new Node('c');
+
+ l.head = a;
+ a.next = b;
+ b.next = c;
+ c.next = null;
+
+ expect(circular(l)).toEqual(false);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/events/example.html b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/events/example.html
new file mode 100644
index 0000000..f87a916
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/events/example.html
@@ -0,0 +1,15 @@
+
+
+
+
+
Click the button
+
+
+
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/events/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/events/index.js
new file mode 100644
index 0000000..23352db
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/events/index.js
@@ -0,0 +1,37 @@
+// --- Directions
+// Create an 'eventing' library out of the
+// Events class. The Events class should
+// have methods 'on', 'trigger', and 'off'.
+
+class Events {
+ // Register an event handler
+ constructor() {
+ this.events = {};
+ }
+ // Register an event handler
+ on(eventName, callback) {
+ if (this.events[eventName]) {
+ this.events[eventName].push(callback);
+ } else {
+ this.events[eventName] = [callback];
+ }
+ }
+
+ // Trigger all callbacks associated
+ // with a given eventName
+ trigger(eventName) {
+ if (this.events[eventName]){
+ for (let callback of this.events[eventName]){
+ callback();
+ }
+ }
+ }
+
+ // Remove all event handlers associated
+ // with the given eventName
+ off(eventName) {
+ delete this.events[eventName];
+ }
+}
+
+module.exports = Events;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/events/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/events/test.js
new file mode 100644
index 0000000..e015819
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/events/test.js
@@ -0,0 +1,77 @@
+const Events = require('./index');
+
+test('Events can be registered then triggered', () => {
+ const events = new Events();
+
+ const cb1 = jest.fn();
+
+ events.on('click', cb1);
+ events.trigger('click');
+
+ expect(cb1.mock.calls.length).toBe(1);
+});
+
+test('Multiple events can be registered then triggered', () => {
+ const events = new Events();
+
+ const cb1 = jest.fn();
+ const cb2 = jest.fn();
+
+ events.on('click', cb1);
+ events.on('click', cb2);
+ events.trigger('click');
+
+ expect(cb1.mock.calls.length).toBe(1);
+ expect(cb2.mock.calls.length).toBe(1);
+});
+
+test('Events can be triggered multiple times', () => {
+ const events = new Events();
+
+ const cb1 = jest.fn();
+ const cb2 = jest.fn();
+
+ events.on('click', cb1);
+ events.trigger('click');
+ events.on('click', cb2);
+ events.trigger('click');
+ events.trigger('click');
+
+ expect(cb1.mock.calls.length).toBe(3);
+ expect(cb2.mock.calls.length).toBe(2);
+});
+
+test('Events can have different names', () => {
+ const events = new Events();
+
+ const cb1 = jest.fn();
+ const cb2 = jest.fn();
+
+ events.on('click', cb1);
+ events.trigger('click');
+ events.on('hover', cb2);
+ events.trigger('click');
+ events.trigger('hover');
+
+ expect(cb1.mock.calls.length).toBe(2);
+ expect(cb2.mock.calls.length).toBe(1);
+});
+
+test('Events can be toggled off', () => {
+ const events = new Events();
+
+ const cb1 = jest.fn();
+ const cb2 = jest.fn();
+
+ events.on('hover', cb2);
+
+ events.on('click', cb1);
+ events.trigger('click');
+ events.off('click');
+ events.trigger('click');
+
+ events.trigger('hover');
+
+ expect(cb1.mock.calls.length).toBe(1);
+ expect(cb2.mock.calls.length).toBe(1);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/fib/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/fib/index.js
new file mode 100644
index 0000000..16b1451
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/fib/index.js
@@ -0,0 +1,56 @@
+// --- Directions
+// Print out the n-th entry in the fibonacci series.
+// The fibonacci series is an ordering of numbers where
+// each number is the sum of the preceeding two.
+// For example, the sequence
+// [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
+// forms the first ten entries of the fibonacci series.
+// Example:
+// fib(4) === 3
+
+// recursive solution: exponential runtime
+function slowFib(n) {
+ if(n < 2) return n;
+ return fib(n -1) + fib(n-2);
+}
+
+// memoize: constant time
+function memoize(fn) {
+ const cache = {};
+
+ return function(...args) {
+ if(cache[args]){
+ return cache[args];
+ }
+
+ const result = fn.apply(this, args);
+ cache[args] = result;
+
+ return result;
+ }
+}
+
+// // iterative solution: linear runtime
+// function fib(n) {
+// const result = [0, 1];
+
+// for(let i = 2; i <= n; i++) {
+// const a = result[i - 1];
+// const b = result[i - 2];
+
+// result.push(a + b);
+// }
+// return result[n];
+// }
+
+
+
+const fib = memoize(slowFib);
+
+
+
+
+
+
+
+module.exports = fib;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/fib/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/fib/test.js
new file mode 100644
index 0000000..02a385d
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/fib/test.js
@@ -0,0 +1,25 @@
+const fib = require('./index');
+
+test('Fib function is defined', () => {
+ expect(typeof fib).toEqual('function');
+});
+
+test('calculates correct fib value for 1', () => {
+ expect(fib(1)).toEqual(1);
+});
+
+test('calculates correct fib value for 2', () => {
+ expect(fib(2)).toEqual(1);
+});
+
+test('calculates correct fib value for 3', () => {
+ expect(fib(3)).toEqual(2);
+});
+
+test('calculates correct fib value for 4', () => {
+ expect(fib(4)).toEqual(3);
+});
+
+test('calculates correct fib value for 15', () => {
+ expect(fib(39)).toEqual(63245986);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/fizzbuzz/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/fizzbuzz/index.js
new file mode 100644
index 0000000..f7e12d9
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/fizzbuzz/index.js
@@ -0,0 +1,26 @@
+// --- Directions
+// Write a program that console logs the numbers
+// from 1 to n. But for multiples of three print
+// “fizz” instead of the number and for the multiples
+// of five print “buzz”. For numbers which are multiples
+// of both three and five print “fizzbuzz”.
+// --- Example
+// fizzBuzz(5);
+// 1
+// 2
+// fizz
+// 4
+// buzz
+
+function fizzBuzz(n) {
+ for(let i = 1; i <= n; i++){
+ if (i % 15 === 0){
+ console.log("fizzbuzz");
+ } else if (i % 3 === 0) {
+ console.log("fizz");
+ } else if (i % 5 === 0) {
+ console.log("buzz");
+ } else console.log(i);
+ }
+}
+module.exports = fizzBuzz;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/fizzbuzz/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/fizzbuzz/test.js
new file mode 100644
index 0000000..b25dc82
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/fizzbuzz/test.js
@@ -0,0 +1,39 @@
+const fizzBuzz = require('./index');
+
+test('fizzBuzz function is defined', () => {
+ expect(fizzBuzz).toBeDefined();
+});
+
+test('Calling fizzbuzz with `5` prints out 5 statements', () => {
+ fizzBuzz(5);
+
+ expect(console.log.mock.calls.length).toEqual(5);
+});
+
+test('Calling fizzbuzz with 15 prints out the correct values', () => {
+ fizzBuzz(15);
+
+ expect(console.log.mock.calls[0][0]).toEqual(1);
+ expect(console.log.mock.calls[1][0]).toEqual(2);
+ expect(console.log.mock.calls[2][0]).toEqual('fizz');
+ expect(console.log.mock.calls[3][0]).toEqual(4);
+ expect(console.log.mock.calls[4][0]).toEqual('buzz');
+ expect(console.log.mock.calls[5][0]).toEqual('fizz');
+ expect(console.log.mock.calls[6][0]).toEqual(7);
+ expect(console.log.mock.calls[7][0]).toEqual(8);
+ expect(console.log.mock.calls[8][0]).toEqual('fizz');
+ expect(console.log.mock.calls[9][0]).toEqual('buzz');
+ expect(console.log.mock.calls[10][0]).toEqual(11);
+ expect(console.log.mock.calls[11][0]).toEqual('fizz');
+ expect(console.log.mock.calls[12][0]).toEqual(13);
+ expect(console.log.mock.calls[13][0]).toEqual(14);
+ expect(console.log.mock.calls[14][0]).toEqual('fizzbuzz');
+});
+
+beforeEach(() => {
+ jest.spyOn(console, 'log');
+});
+
+afterEach(() => {
+ console.log.mockRestore();
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/fromlast/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/fromlast/index.js
new file mode 100644
index 0000000..b62c92b
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/fromlast/index.js
@@ -0,0 +1,30 @@
+// --- Directions
+// Given a linked list, return the element n spaces
+// from the last node in the list. Do not call the 'size'
+// method of the linked list. Assume that n will always
+// be less than the length of the list.
+// --- Examples
+// const list = new List();
+// list.insertLast('a');
+// list.insertLast('b');
+// list.insertLast('c');
+// list.insertLast('d');
+// fromLast(list, 2).data // 'b'
+
+function fromLast(list, n) {
+ let fast = list.getFirst();
+ let slow = list.getFirst();
+
+ while(n > 0){
+ fast = fast.next;
+ n--;
+ }
+
+ while(fast.next){
+ slow = slow.next;
+ fast = fast.next;
+ }
+ return slow;
+}
+
+module.exports = fromLast;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/fromlast/linkedlist.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/fromlast/linkedlist.js
new file mode 100644
index 0000000..2029b3b
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/fromlast/linkedlist.js
@@ -0,0 +1,156 @@
+class Node {
+ constructor(data, next = null) {
+ this.data = data;
+ this.next = next;
+ }
+}
+
+class LinkedList {
+ constructor() {
+ this.head = null;
+ }
+
+ insertFirst(data) {
+ this.head = new Node(data, this.head);
+ }
+
+ size() {
+ let counter = 0;
+ let node = this.head;
+
+ while (node) {
+ counter++;
+ node = node.next;
+ }
+
+ return counter;
+ }
+
+ getFirst() {
+ return this.head;
+ }
+
+ getLast() {
+ if (!this.head) {
+ return null;
+ }
+
+ let node = this.head;
+ while (node) {
+ if (!node.next) {
+ return node;
+ }
+ node = node.next;
+ }
+ }
+
+ clear() {
+ this.head = null;
+ }
+
+ removeFirst() {
+ if (!this.head) {
+ return;
+ }
+
+ this.head = this.head.next;
+ }
+
+ removeLast() {
+ if (!this.head) {
+ return;
+ }
+
+ if (!this.head.next) {
+ this.head = null;
+ return;
+ }
+
+ let previous = this.head;
+ let node = this.head.next;
+ while (node.next) {
+ previous = node;
+ node = node.next;
+ }
+ previous.next = null;
+ }
+
+ insertLast(data) {
+ const last = this.getLast();
+
+ if (last) {
+ // There are some existing nodes in our chain
+ last.next = new Node(data);
+ } else {
+ // The chain is empty!
+ this.head = new Node(data);
+ }
+ }
+
+ getAt(index) {
+ let counter = 0;
+ let node = this.head;
+ while (node) {
+ if (counter === index) {
+ return node;
+ }
+
+ counter++;
+ node = node.next;
+ }
+ return null;
+ }
+
+ removeAt(index) {
+ if (!this.head) {
+ return;
+ }
+
+ if (index === 0) {
+ this.head = this.head.next;
+ return;
+ }
+
+ const previous = this.getAt(index - 1);
+ if (!previous || !previous.next) {
+ return;
+ }
+ previous.next = previous.next.next;
+ }
+
+ insertAt(data, index) {
+ if (!this.head) {
+ this.head = new Node(data);
+ return;
+ }
+
+ if (index === 0) {
+ this.head = new Node(data, this.head);
+ return;
+ }
+
+ const previous = this.getAt(index - 1) || this.getLast();
+ const node = new Node(data, previous.next);
+ previous.next = node;
+ }
+
+ forEach(fn) {
+ let node = this.head;
+ let counter = 0;
+ while (node) {
+ fn(node, counter);
+ node = node.next;
+ counter++;
+ }
+ }
+
+ *[Symbol.iterator]() {
+ let node = this.head;
+ while (node) {
+ yield node;
+ node = node.next;
+ }
+ }
+}
+
+module.exports = { Node, LinkedList };
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/fromlast/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/fromlast/test.js
new file mode 100644
index 0000000..e4684d5
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/fromlast/test.js
@@ -0,0 +1,20 @@
+const fromLast = require('./index');
+const L = require('./linkedlist');
+const List = L.LinkedList;
+const Node = L.Node;
+
+test('fromLast is a function', () => {
+ expect(typeof fromLast).toEqual('function');
+});
+
+test('fromLast returns the node n elements from the end', () => {
+ const l = new List();
+
+ l.insertLast('a');
+ l.insertLast('b');
+ l.insertLast('c');
+ l.insertLast('d');
+ l.insertLast('e');
+
+ expect(fromLast(l, 3).data).toEqual('b');
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/levelwidth/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/levelwidth/index.js
new file mode 100644
index 0000000..5bc0c06
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/levelwidth/index.js
@@ -0,0 +1,34 @@
+// --- Directions
+// Given the root node of a tree, return
+// an array where each element is the width
+// of the tree at each level.
+// --- Example
+// Given:
+// 0
+// / | \
+// 1 2 3
+// | |
+// 4 5
+// Answer: [1, 3, 2]
+
+function levelWidth(root) {
+ const arr = [root, 's']
+ const counters = [0]
+
+ while(arr.length > 1) {
+ const node = arr.shift();
+
+ if(node === 's'){
+ counters.push(0);
+ arr.push('s');
+
+ } else {
+ arr.push(...node.children);
+ counters[counters.length - 1]++;
+ }
+
+ }
+ return counters;
+}
+
+module.exports = levelWidth;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/levelwidth/node.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/levelwidth/node.js
new file mode 100644
index 0000000..5238e8f
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/levelwidth/node.js
@@ -0,0 +1,10 @@
+module.exports = class Node {
+ constructor(data) {
+ this.data = data;
+ this.children = [];
+ }
+
+ add(data) {
+ this.children.push(new Node(data));
+ }
+};
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/levelwidth/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/levelwidth/test.js
new file mode 100644
index 0000000..35d20c2
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/levelwidth/test.js
@@ -0,0 +1,27 @@
+const Node = require('./node');
+const levelWidth = require('./index');
+
+test('levelWidth is a function', () => {
+ expect(typeof levelWidth).toEqual('function');
+});
+
+test('levelWidth returns number of nodes at widest point', () => {
+ const root = new Node(0);
+ root.add(1);
+ root.add(2);
+ root.add(3);
+ root.children[0].add(4);
+ root.children[2].add(5);
+
+ expect(levelWidth(root)).toEqual([1, 3, 2]);
+});
+
+test('levelWidth returns number of nodes at widest point', () => {
+ const root = new Node(0);
+ root.add(1);
+ root.children[0].add(2);
+ root.children[0].add(3);
+ root.children[0].children[0].add(4);
+
+ expect(levelWidth(root)).toEqual([1, 1, 2, 1]);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/linkedlist/directions.html b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/linkedlist/directions.html
new file mode 100644
index 0000000..ecb118d
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/linkedlist/directions.html
@@ -0,0 +1,377 @@
+
+
+
+
+
+
Node Class API
+
+
+
+
Function
+
Arguments
+
Returns
+
Directions
+
Example
+
+
+
+
+
Node.constructor
+
(Data, Node)
+
Node
+
+ Creates a class instance to represent a node. The node should
+ have two properties, 'data' and 'next'. Accept both
+ of these as arguments to the 'Node' constructor, then
+ assign them to the instance as properties 'data' and 'next'.
+ If 'next' is not provided to the constructor, then default its
+ value to be 'null'.
+
+
+
+ const n = new Node('There');
+ n.data // 'Hi'
+ n.next // null
+ const n2 = new Node('Hi', n);
+ n.next // returns n
+
+
+
+
+
+
+
LinkedList Class API
+
+
+
+
Function
+
Arguments
+
Returns
+
Directions
+
Example
+
+
+
+
+
constructor
+
-
+
(LinkedList)
+
+ Create a class to represent a linked list. When created,
+ a linked list should have *no* head node associated with it.
+ The LinkedList instance will have one property, 'head', which
+ is a reference to the first node of the linked list. By default
+ 'head' should be 'null'.
+
+
+
+ const list = new LinkedList();
+ list.head // null
+
+
+
+
+
insertFirst
+
(data)
+
-
+
+ Creates a new Node from argument 'data' and assigns the resulting
+ node to the 'head' property. Make sure to handle the case in which
+ the linked list already has a node assigned to the 'head' property.
+
+
+
+ const list = new LinkedList();
+ list.insertFirst('Hi There'); // List has one node
+
+
+
+
+
size
+
-
+
(integer)
+
+ Returns the number of nodes in the linked list.
+
+
+
+ const list = new LinkedList();
+ list.insertFirst('a');
+ list.insertFirst('b');
+ list.insertFirst('c');
+ list.size(); // returns 3
+
+
+
+
+
getFirst
+
-
+
(Node)
+
+ Returns the first node of the linked list.
+
+
+
+ const list = new LinkedList();
+ list.insertFirst('a');
+ list.insertFirst('b');
+ list.getFirst(); // returns Node instance with data 'a'
+
+
+
+
+
+ getLast
+
+
+ -
+
+
+ (Node)
+
+
+ Returns the last node of the linked list
+
+
+
+ const list = new LinkedList();
+ list.insertFirst('a');
+ list.insertFirst('b');
+ list.getLast(); // returns node with data 'a'
+
+
+
+
+
+ clear
+
+
+ -
+
+
+ -
+
+
+ Empties the linked list of any nodes.
+
+
+
+ const list = new LinkedList();
+ list.insertFirst('a');
+ list.insertFirst('b');
+ list.clear();
+ list.size(); // returns 0
+
+
+
+
+
+ removeFirst
+
+
+ -
+
+
+ -
+
+
+ Removes only the first node of the linked list. The list's head should
+ now be the second element.
+
+
+
+ const list = new LinkedList();
+ list.insertFirst('a');
+ list.insertFirst('b');
+ list.removeFirst();
+ list.getFirst(); // returns node with data 'a'
+
+
+
+
+
+ removeLast
+
+
+ -
+
+
+ -
+
+
+ Removes the last node of the chain
+
+
+
+ const list = new LinkedList();
+ list.insertFirst('a');
+ list.insertFirst('b');
+ list.removeLast();
+ list.size(); // returns 1
+ list.getLast(); // returns node with data of 'b'
+
+
+
+
+
+ insertLast
+
+
+ (Data)
+
+
+ -
+
+
+ Inserts a new node with provided data at the end of the chain
+
+
+
+ const list = new LinkedList();
+ list.insertFirst('a');
+ list.insertFirst('b');
+ list.insertLast('c');
+ list.getLast(); // returns node with data 'C'
+
+
+
+
+
+ getAt
+
+
+ (integer)
+
+
+ (Node)
+
+
+ Returns the node at the provided index
+
+
+
+ const list = new List();
+ list.insertFirst('a');
+ list.insertFirst('b');
+ list.insertFirst('c');
+ list.getAt(1); // returns node with data 'b'
+
+
+
+
+
+ removeAt
+
+
+ (integer)
+
+
+ -
+
+
+ Removes node at the provided index
+
+
+
+ const list = new List();
+ list.insertFirst('a');
+ list.insertFirst('b');
+ list.insertFirst('c');
+ list.removeAt(1);
+ list.getAt(1); // returns node with data 'a'
+
+
+
+
+
+ insertAt
+
+
+ (Data, integer)
+
+
+ -
+
+
+ Create an insert a new node at provided index.
+ If index is out of bounds, add the node to the end
+ of the list.
+
+
+
+ const list = new List();
+ list.insertFirst('a');
+ list.insertFirst('b');
+ list.insertFirst('c');
+ list.insertAt('Hi', 1)
+ list.getAt(1); // returns node with data 'Hi'
+
+
+
+
+
+ forEach
+
+
+ (function)
+
+
+ -
+
+
+ Calls the provided function with every node of the chain
+
+
+
+ const list = new List();
+
+ list.insertLast(1);
+ list.insertLast(2);
+ list.insertLast(3);
+ list.insertLast(4);
+
+ list.forEach(node => {
+ node.data += 10;
+ });
+ list.getAt(0); // Returns node with data '11'
+
+
+
+
+
+ for...of Loop
+
+
+ -
+
+
+ -
+
+
+ Linked list should be compatible as the subject of a 'for...of' loop
+
+
+
+ const list = new List();
+
+ list.insertLast(1);
+ list.insertLast(2);
+ list.insertLast(3);
+ list.insertLast(4);
+
+ for (let node of list) {
+ node.data += 10;
+ }
+
+ node.getAt(1); // returns node with data 11
+
+
+
+
+
+
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/linkedlist/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/linkedlist/index.js
new file mode 100644
index 0000000..6edd76c
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/linkedlist/index.js
@@ -0,0 +1,175 @@
+// --- Directions
+// Implement classes Node and Linked Lists
+// See 'directions' document
+
+class Node {
+ constructor(data, next){
+ this.data = data;
+ this.next = next;
+ }
+}
+
+class LinkedList {
+ constructor() {
+ this.head = null;
+ }
+
+ insertAt(data, index) {
+ // if list is empty
+ if (!this.head) {
+ this.head = new Node(data);
+ return;
+ }
+
+ // if inserting at first node
+ if (index === 0) {
+ this.head = new Node(data, this.head);
+ return;
+ }
+
+ // if inserting later in list
+ const previous = this.getAt(index - 1) || this.getLast();
+ const node = new Node(data, previous.next);
+ previous.next = node;
+ }
+
+
+
+ insertFirst(data) {
+ this.head = new Node(data, this.head);
+ }
+
+ insertLast(data) {
+ const last = this.getLast();
+
+ if(last) {
+ // last.next = new Node(data);
+ this.insertAt(data, last.next)
+ } else {
+ //this.head = new Node(data);
+ this.insertFirst(data);
+ }
+ }
+
+ size(){
+ let counter = 0;
+ let node = this.head;
+ while(node) {
+ counter++;
+ node = node.next;
+ }
+ return counter;
+ }
+
+ getAt(index){
+ if (!this.head){
+ return null;
+ }
+
+ let counter = 0;
+ let node = this.head;
+ while(node) {
+ if (counter === index) {
+ return node;
+ }
+
+ counter++;
+ node = node.next;
+ }
+ return null;
+ }
+
+ getFirst() {
+ // return this.head;
+ return this.getAt(0);
+ }
+
+ getLast() {
+ // if(!this.head){
+ // return null;
+ // }
+
+ // let node = this.head;
+ // while(node){
+ // if (!node.next){
+ // return node;
+ // }
+ // node = node.next;
+
+ // }
+ return this.getAt(this.size()- 1);
+ }
+
+ clear() {
+ this.head = null;
+ }
+
+ removeAt(index){
+ if (!this.head){
+ return;
+ }
+
+ if (index === 0) {
+ this.head = this.head.next;
+ return;
+ }
+
+ const previous = this.getAt(index - 1);
+ if(!previous || !previous.next) {
+ return;
+ }
+ previous.next = previous.next.next;
+ }
+
+ removeFirst() {
+ // if(!this.head){
+ // return null;
+ // }
+
+ // this.head = this.head.next;
+ this.removeAt(0);
+ }
+
+ removeLast(){
+ // // for empty list
+ // if(!this.head){
+ // return;
+ // }
+
+ // // for list length one
+ // if(!this.head.next){
+ // this.head = null;
+ // return;
+ // }
+
+ // // for list longer than one
+ // let previous = this.head;
+ // let node = this.head.next;
+ // while(node.next){
+ // previous = node;
+ // node = node.next
+ // }
+ // previous.next = null;
+ this.removeAt(this.size() - 1);
+ }
+
+ forEach(fn) {
+ let node = this.head;
+ while(node){
+ fn(node);
+ node = node.next;
+ }
+ }
+
+
+ *[Symbol.iterator]() {
+ let node = this.head;
+ while (node) {
+ yield node;
+ node = node.next;
+ }
+ }
+}
+
+
+module.exports = { Node, LinkedList };
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/linkedlist/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/linkedlist/test.js
new file mode 100644
index 0000000..f4de046
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/linkedlist/test.js
@@ -0,0 +1,321 @@
+const L = require('./index');
+const List = L.LinkedList;
+const Node = L.Node;
+
+test('List is a class', () => {
+ expect(typeof List.prototype.constructor).toEqual('function');
+});
+
+test('Node is a class', () => {
+ expect(typeof Node.prototype.constructor).toEqual('function');
+});
+
+describe('A Node', () => {
+ test('has properties "data" and "next"', () => {
+ const node = new Node('a', 'b');
+ expect(node.data).toEqual('a');
+ expect(node.next).toEqual('b');
+ });
+});
+
+describe('Insert First', () => {
+ test('appends a node to the start of the list', () => {
+ const l = new List();
+ l.insertFirst(1);
+ expect(l.head.data).toEqual(1);
+ l.insertFirst(2);
+ expect(l.head.data).toEqual(2);
+ });
+});
+
+describe('Size', () => {
+ test('returns the number of items in the linked list', () => {
+ const l = new List();
+ expect(l.size()).toEqual(0);
+ l.insertFirst(1);
+ l.insertFirst(1);
+ l.insertFirst(1);
+ l.insertFirst(1);
+ expect(l.size()).toEqual(4);
+ });
+});
+
+describe('GetFirst', () => {
+ test('returns the first element', () => {
+ const l = new List();
+ l.insertFirst(1);
+ expect(l.getFirst().data).toEqual(1);
+ l.insertFirst(2);
+ expect(l.getFirst().data).toEqual(2);
+ });
+});
+
+describe('GetLast', () => {
+ test('returns the last element', () => {
+ const l = new List();
+ l.insertFirst(2);
+ expect(l.getLast()).toEqual({ data: 2, next: null });
+ l.insertFirst(1);
+ expect(l.getLast()).toEqual({ data: 2, next: null });
+ });
+});
+
+describe('Clear', () => {
+ test('empties out the list', () => {
+ const l = new List();
+ expect(l.size()).toEqual(0);
+ l.insertFirst(1);
+ l.insertFirst(1);
+ l.insertFirst(1);
+ l.insertFirst(1);
+ expect(l.size()).toEqual(4);
+ l.clear();
+ expect(l.size()).toEqual(0);
+ });
+});
+
+describe('RemoveFirst', () => {
+ test('removes the first node when the list has a size of one', () => {
+ const l = new List();
+ l.insertFirst('a');
+ l.removeFirst();
+ expect(l.size()).toEqual(0);
+ expect(l.getFirst()).toEqual(null);
+ });
+
+ test('removes the first node when the list has a size of three', () => {
+ const l = new List();
+ l.insertFirst('c');
+ l.insertFirst('b');
+ l.insertFirst('a');
+ l.removeFirst();
+ expect(l.size()).toEqual(2);
+ expect(l.getFirst().data).toEqual('b');
+ l.removeFirst();
+ expect(l.size()).toEqual(1);
+ expect(l.getFirst().data).toEqual('c');
+ });
+});
+
+describe('RemoveLast', () => {
+ test('RemoveLast removes the last node when list is empty', () => {
+ const l = new List();
+ expect(() => {
+ l.removeLast();
+ }).not.toThrow();
+ });
+
+ test('RemoveLast removes the last node when list is length 1', () => {
+ const l = new List();
+ l.insertFirst('a');
+ l.removeLast();
+ expect(l.head).toEqual(null);
+ });
+
+ test('RemoveLast removes the last node when list is length 2', () => {
+ const l = new List();
+ l.insertFirst('b');
+ l.insertFirst('a');
+
+ l.removeLast();
+
+ expect(l.size()).toEqual(1);
+ expect(l.head.data).toEqual('a');
+ });
+
+ test('RemoveLast removes the last node when list is length 3', () => {
+ const l = new List();
+ l.insertFirst('c');
+ l.insertFirst('b');
+ l.insertFirst('a');
+ l.removeLast();
+
+ expect(l.size()).toEqual(2);
+ expect(l.getLast().data).toEqual('b');
+ });
+});
+
+describe('InsertLast', () => {
+ test('adds to the end of the list', () => {
+ const l = new List();
+ l.insertFirst('a');
+
+ l.insertLast('b');
+
+ expect(l.size()).toEqual(2);
+ expect(l.getLast().data).toEqual('b');
+ });
+});
+
+describe('GetAt', () => {
+ test('returns the node at given index', () => {
+ const l = new List();
+ expect(l.getAt(10)).toEqual(null);
+
+ l.insertLast(1);
+ l.insertLast(2);
+ l.insertLast(3);
+ l.insertLast(4);
+
+ expect(l.getAt(0).data).toEqual(1);
+ expect(l.getAt(1).data).toEqual(2);
+ expect(l.getAt(2).data).toEqual(3);
+ expect(l.getAt(3).data).toEqual(4);
+ });
+});
+
+describe('RemoveAt', () => {
+ test('removeAt doesnt crash on an empty list', () => {
+ const l = new List();
+ expect(() => {
+ l.removeAt(0);
+ l.removeAt(1);
+ l.removeAt(2);
+ }).not.toThrow();
+ });
+
+ test('removeAt doesnt crash on an index out of bounds', () => {
+ const l = new List();
+ expect(() => {
+ const l = new List();
+ l.insertFirst('a');
+ l.removeAt(1);
+ }).not.toThrow();
+ });
+
+ test('removeAt deletes the first node', () => {
+ const l = new List();
+ l.insertLast(1);
+ l.insertLast(2);
+ l.insertLast(3);
+ l.insertLast(4);
+ expect(l.getAt(0).data).toEqual(1);
+ l.removeAt(0);
+ expect(l.getAt(0).data).toEqual(2);
+ });
+
+ test('removeAt deletes the node at the given index', () => {
+ const l = new List();
+ l.insertLast(1);
+ l.insertLast(2);
+ l.insertLast(3);
+ l.insertLast(4);
+ expect(l.getAt(1).data).toEqual(2);
+ l.removeAt(1);
+ expect(l.getAt(1).data).toEqual(3);
+ });
+
+ test('removeAt works on the last node', () => {
+ const l = new List();
+ l.insertLast(1);
+ l.insertLast(2);
+ l.insertLast(3);
+ l.insertLast(4);
+ expect(l.getAt(3).data).toEqual(4);
+ l.removeAt(3);
+ expect(l.getAt(3)).toEqual(null);
+ });
+});
+
+describe('InsertAt', () => {
+ test('inserts a new node with data at the 0 index when the list is empty', () => {
+ const l = new List();
+ l.insertAt('hi', 0);
+ expect(l.getFirst().data).toEqual('hi');
+ });
+
+ test('inserts a new node with data at the 0 index when the list has elements', () => {
+ const l = new List();
+ l.insertLast('a');
+ l.insertLast('b');
+ l.insertLast('c');
+ l.insertAt('hi', 0);
+ expect(l.getAt(0).data).toEqual('hi');
+ expect(l.getAt(1).data).toEqual('a');
+ expect(l.getAt(2).data).toEqual('b');
+ expect(l.getAt(3).data).toEqual('c');
+ });
+
+ test('inserts a new node with data at a middle index', () => {
+ const l = new List();
+ l.insertLast('a');
+ l.insertLast('b');
+ l.insertLast('c');
+ l.insertLast('d');
+ l.insertAt('hi', 2);
+ expect(l.getAt(0).data).toEqual('a');
+ expect(l.getAt(1).data).toEqual('b');
+ expect(l.getAt(2).data).toEqual('hi');
+ expect(l.getAt(3).data).toEqual('c');
+ expect(l.getAt(4).data).toEqual('d');
+ });
+
+ test('inserts a new node with data at a last index', () => {
+ const l = new List();
+ l.insertLast('a');
+ l.insertLast('b');
+ l.insertAt('hi', 2);
+ expect(l.getAt(0).data).toEqual('a');
+ expect(l.getAt(1).data).toEqual('b');
+ expect(l.getAt(2).data).toEqual('hi');
+ });
+
+ test('insert a new node when index is out of bounds', () => {
+ const l = new List();
+ l.insertLast('a');
+ l.insertLast('b');
+ l.insertAt('hi', 30);
+
+ expect(l.getAt(0).data).toEqual('a');
+ expect(l.getAt(1).data).toEqual('b');
+ expect(l.getAt(2).data).toEqual('hi');
+ });
+});
+
+describe('ForEach', () => {
+ test('applies a transform to each node', () => {
+ const l = new List();
+
+ l.insertLast(1);
+ l.insertLast(2);
+ l.insertLast(3);
+ l.insertLast(4);
+
+ l.forEach(node => {
+ node.data += 10;
+ });
+
+ expect(l.getAt(0).data).toEqual(11);
+ expect(l.getAt(1).data).toEqual(12);
+ expect(l.getAt(2).data).toEqual(13);
+ expect(l.getAt(3).data).toEqual(14);
+ });
+});
+
+describe('for...of loops', () => {
+ test('works with the linked list', () => {
+ const l = new List();
+
+ l.insertLast(1);
+ l.insertLast(2);
+ l.insertLast(3);
+ l.insertLast(4);
+
+ for (let node of l) {
+ node.data += 10;
+ }
+
+ expect(l.getAt(0).data).toEqual(11);
+ expect(l.getAt(1).data).toEqual(12);
+ expect(l.getAt(2).data).toEqual(13);
+ expect(l.getAt(3).data).toEqual(14);
+ });
+
+ test('for...of works on an empty list', () => {
+ const l = new List();
+ expect(() => {
+ for (let node of l) {
+ }
+ }).not.toThrow();
+ });
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/matrix/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/matrix/index.js
new file mode 100644
index 0000000..257b5f5
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/matrix/index.js
@@ -0,0 +1,64 @@
+// --- Directions
+// Write a function that accepts an integer N
+// and returns a NxN spiral matrix.
+// --- Examples
+// matrix(2)
+// [[1, 2],
+// [4, 3]]
+// matrix(3)
+// [[1, 2, 3],
+// [8, 9, 4],
+// [7, 6, 5]]
+// matrix(4)
+// [[1, 2, 3, 4],
+// [12, 13, 14, 5],
+// [11, 16, 15, 6],
+// [10, 9, 8, 7]]
+
+function matrix(n) {
+ const results = [];
+ let counter = 1;
+
+ for (let i = 0; i < n; i++) {
+ results.push([]);
+ }
+
+ let start_col = 0;
+ let start_row = 0;
+ let end_col = n - 1;
+ let end_row = n - 1;
+
+ while(start_col <= end_col && start_row <= end_row) {
+
+ // Top Row
+ for(let i = start_col; i <= end_col; i++){
+ results[start_row][i] = counter;
+ counter++;
+ }
+ start_row++;
+
+ // Right Column
+ for(let i = start_row; i <= end_row; i++){
+ results[i][end_col] = counter;
+ counter++;
+ }
+ end_col--;
+
+ // Bottom Row
+ for(let i = end_col; i >= start_col; i--){
+ results[end_row][i] = counter;
+ counter++;
+ }
+ end_row--;
+
+ // Start Column
+ for(let i = end_row; i >= start_row; i--) {
+ results[i][start_col] = counter;
+ counter++;
+ }
+ start_col++;
+ }
+ return results;
+}
+
+module.exports = matrix;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/matrix/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/matrix/test.js
new file mode 100644
index 0000000..4476dda
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/matrix/test.js
@@ -0,0 +1,29 @@
+const matrix = require('./index');
+
+test('matrix is a function', () => {
+ expect(typeof matrix).toEqual('function');
+});
+
+test('matrix produces a 2x2 array', () => {
+ const m = matrix(2);
+ expect(m.length).toEqual(2);
+ expect(m[0]).toEqual([1, 2]);
+ expect(m[1]).toEqual([4, 3]);
+});
+
+test('matrix produces a 3x3 array', () => {
+ const m = matrix(3);
+ expect(m.length).toEqual(3);
+ expect(m[0]).toEqual([1, 2, 3]);
+ expect(m[1]).toEqual([8, 9, 4]);
+ expect(m[2]).toEqual([7, 6, 5]);
+});
+
+test('matrix produces a 4x4 array', () => {
+ const m = matrix(4);
+ expect(m.length).toEqual(4);
+ expect(m[0]).toEqual([1, 2, 3, 4]);
+ expect(m[1]).toEqual([12, 13, 14, 5]);
+ expect(m[2]).toEqual([11, 16, 15, 6]);
+ expect(m[3]).toEqual([10, 9, 8, 7]);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/maxchar/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/maxchar/index.js
new file mode 100644
index 0000000..0db5089
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/maxchar/index.js
@@ -0,0 +1,27 @@
+// --- Directions
+// Given a string, return the character that is most
+// commonly used in the string.
+// --- Examples
+// maxChar("abcccccccd") === "c"
+// maxChar("apple 1231111") === "1"
+
+function maxChar(str) {
+ let max = 0;
+ let maxChar = "";
+ let charMap = {};
+
+ for (let char of str){
+ charMap[char] = charMap[char] + 1 || 1;
+ }
+
+ for(let char in charMap){
+ if(charMap[char] > max){
+ max = charMap[char];
+ maxChar = char;
+ }
+ }
+ return maxChar;
+
+}
+
+module.exports = maxChar;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/maxchar/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/maxchar/test.js
new file mode 100644
index 0000000..14918ee
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/maxchar/test.js
@@ -0,0 +1,14 @@
+const maxChar = require('./index');
+
+test('maxChar function exists', () => {
+ expect(typeof maxChar).toEqual('function');
+});
+
+test('Finds the most frequently used char', () => {
+ expect(maxChar('a')).toEqual('a');
+ expect(maxChar('abcdefghijklmnaaaaa')).toEqual('a');
+});
+
+test('Works with numbers in the string', () => {
+ expect(maxChar('ab1c1d1e1f1g1')).toEqual('1');
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/midpoint/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/midpoint/index.js
new file mode 100644
index 0000000..8aa4683
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/midpoint/index.js
@@ -0,0 +1,26 @@
+// --- Directions
+// Return the 'middle' node of a linked list.
+// If the list has an even number of elements, return
+// the node at the end of the first half of the list.
+// *Do not* use a counter variable, *do not* retrieve
+// the size of the list, and only iterate
+// through the list one time.
+// --- Example
+// const l = new LinkedList();
+// l.insertLast('a')
+// l.insertLast('b')
+// l.insertLast('c')
+// midpoint(l); // returns { data: 'b' }
+
+function midpoint(list) {
+ let slow = list.getFirst();
+ let fast = list.getFirst();
+
+ while(fast.next && fast.next.next){
+ slow = slow.next;
+ fast = fast.next.next;
+ }
+ return slow;
+}
+
+module.exports = midpoint;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/midpoint/linkedlist.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/midpoint/linkedlist.js
new file mode 100644
index 0000000..b7da56b
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/midpoint/linkedlist.js
@@ -0,0 +1,178 @@
+class Node {
+ constructor(data, next = null) {
+ this.data = data;
+ this.next = next;
+ }
+}
+
+class LinkedList {
+ constructor(values = []) {
+ this.head = null;
+
+ for (let value of values) {
+ this.insertLast(value);
+ }
+ }
+
+ clear() {
+ this.head = null;
+ }
+
+ size() {
+ let counter = 0;
+ let node = this.head;
+
+ while (node) {
+ counter++;
+ node = node.next;
+ }
+
+ return counter;
+ }
+
+ getAt(index) {
+ if (!this.head) {
+ return null;
+ }
+
+ let counter = 0;
+ let node = this.head;
+ while (node) {
+ if (counter === index) {
+ return node;
+ }
+ node = node.next;
+ counter++;
+ }
+ return null;
+ }
+
+ insertAt(data, index) {
+ if (!this.head) {
+ this.head = new Node(data);
+ return;
+ }
+
+ if (index === 0) {
+ this.head = new Node(data, this.head);
+ return;
+ }
+
+ let counter = 1;
+ let previous = this.head;
+ let node = this.head.next;
+ while (node) {
+ if (counter === index) {
+ previous.next = new Node(data, node);
+ return;
+ }
+ previous = node;
+ node = node.next;
+ counter++;
+ }
+
+ previous.next = new Node(data, node);
+ }
+
+ removeFirst() {
+ if (!this.head) {
+ return;
+ }
+
+ this.head = this.head.next;
+ }
+
+ removeLast() {
+ if (!this.head) {
+ return;
+ }
+
+ if (!this.head.next) {
+ this.head = null;
+ return;
+ }
+
+ let previous = this.head;
+ let node = this.head.next;
+ while (node.next) {
+ previous = node;
+ node = node.next;
+ }
+ previous.next = null;
+ }
+
+ removeAt(index) {
+ if (!this.head) {
+ return;
+ }
+
+ let counter = 0;
+ let node = this.head;
+ while (node) {
+ if (counter === index - 1) {
+ if (node.next) {
+ return (node.next = node.next.next);
+ } else {
+ return (node.next = null);
+ }
+ }
+ node = node.next;
+ counter++;
+ }
+ }
+
+ getFirst() {
+ return this.head;
+ }
+
+ insertFirst(data) {
+ this.head = new Node(data, this.getFirst());
+ }
+
+ getLast() {
+ if (!this.head) {
+ return null;
+ }
+
+ let node = this.head;
+ while (node.next) {
+ node = node.next;
+ }
+
+ return node;
+ }
+
+ insertLast(data) {
+ const last = this.getLast();
+
+ if (last) {
+ last.next = new Node(data);
+ return last.next;
+ } else {
+ this.head = new Node(data);
+ return this.head;
+ }
+ }
+
+ forEach(fn) {
+ if (!this.head) {
+ return null;
+ }
+
+ let node = this.head;
+ while (node) {
+ fn(node);
+ node = node.next;
+ }
+ }
+
+ *[Symbol.iterator]() {
+ let node = this.head;
+ while (node) {
+ yield node;
+ node = node.next;
+ }
+ }
+}
+
+module.exports = { Node, LinkedList };
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/midpoint/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/midpoint/test.js
new file mode 100644
index 0000000..277597e
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/midpoint/test.js
@@ -0,0 +1,46 @@
+const midpoint = require('./index');
+const L = require('./linkedlist');
+const Node = L.Node;
+const LinkedList = L.LinkedList;
+
+test('Midpoint is a function', () => {
+ expect(typeof midpoint).toEqual('function');
+});
+
+describe('Midpoint returns the middle node of an odd numbered list', () => {
+ test('when the list has 3 elements', () => {
+ const l = new LinkedList();
+ l.insertLast('a');
+ l.insertLast('b');
+ l.insertLast('c');
+ expect(midpoint(l).data).toEqual('b');
+ });
+
+ test('when the list has 5 elements', () => {
+ const l = new LinkedList();
+ l.insertLast('a');
+ l.insertLast('b');
+ l.insertLast('c');
+ l.insertLast('d');
+ l.insertLast('e');
+ expect(midpoint(l).data).toEqual('c');
+ });
+});
+
+describe('Midpoint returns the middle node of an even numbered list', () => {
+ test('when the list has 2 elements', () => {
+ const l = new LinkedList();
+ l.insertLast('a');
+ l.insertLast('b');
+ expect(midpoint(l).data).toEqual('a');
+ });
+
+ test('when the list has 4 elements', () => {
+ const l = new LinkedList();
+ l.insertLast('a');
+ l.insertLast('b');
+ l.insertLast('c');
+ l.insertLast('d');
+ expect(midpoint(l).data).toEqual('b');
+ });
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/package.json b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/package.json
new file mode 100644
index 0000000..b978e88
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "dev",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "jest": {
+ "testEnvironment": "node"
+ },
+ "author": "stephen grider",
+ "license": "ISC"
+}
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/palindrome/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/palindrome/index.js
new file mode 100644
index 0000000..c8ed075
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/palindrome/index.js
@@ -0,0 +1,42 @@
+// --- Directions
+// Given a string, return true if the string is a palindrome
+// or false if it is not. Palindromes are strings that
+// form the same word if it is reversed. *Do* include spaces
+// and punctuation in determining if the string is a palindrome.
+// --- Examples:
+// palindrome("abba") === true
+// palindrome("abcdefg") === false
+
+// function palindrome(str) {
+// reversed = "";
+// for (let char of str){
+// reversed = char + reversed;
+// }
+// return reversed === str;
+// }
+
+// function palindrome(str) {
+// left = 0;
+// right = str.length-1;
+
+// while (left < right) {
+// if (str[left] === str[right]){
+// left += 1;
+// right -= 1;
+// } else {
+// return false;
+// }
+// }
+// return true;
+// }
+
+function palindrome(str) {
+ return str.split('').every((char, i) => {
+ return char === str[str.length -i -1];
+ })
+}
+
+
+
+
+module.exports = palindrome;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/palindrome/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/palindrome/test.js
new file mode 100644
index 0000000..abdbcb1
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/palindrome/test.js
@@ -0,0 +1,33 @@
+const palindrome = require('./index');
+
+test('palindrome function is defined', () => {
+ expect(typeof palindrome).toEqual('function');
+});
+
+test('"aba" is a palindrome', () => {
+ expect(palindrome('aba')).toBeTruthy();
+});
+
+test('" aba" is not a palindrome', () => {
+ expect(palindrome(' aba')).toBeFalsy();
+});
+
+test('"aba " is not a palindrome', () => {
+ expect(palindrome('aba ')).toBeFalsy();
+});
+
+test('"greetings" is not a palindrome', () => {
+ expect(palindrome('greetings')).toBeFalsy();
+});
+
+test('"1000000001" a palindrome', () => {
+ expect(palindrome('1000000001')).toBeTruthy();
+});
+
+test('"Fish hsif" is not a palindrome', () => {
+ expect(palindrome('Fish hsif')).toBeFalsy();
+});
+
+test('"pennep" a palindrome', () => {
+ expect(palindrome('pennep')).toBeTruthy();
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/pyramid/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/pyramid/index.js
new file mode 100644
index 0000000..cc55237
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/pyramid/index.js
@@ -0,0 +1,64 @@
+// --- Directions
+// Write a function that accepts a positive number N.
+// The function should console log a pyramid shape
+// with N levels using the # character. Make sure the
+// pyramid has spaces on both the left *and* right hand sides
+// --- Examples
+// pyramid(1)
+// '#'
+// pyramid(2)
+// ' # '
+// '###'
+// pyramid(3)
+// ' # '
+// ' ### '
+// '#####'
+
+// function pyramid(n) {
+// const midpoint = Math.floor((2 * n - 1) / 2);
+
+// for (let row = 0; row < n; row++) {
+// let level = '';
+
+// for (let column = 0; column < 2 * n - 1; column++) {
+
+// const condition = ((midpoint - row <= level.length) && (midpoint + row >= level.length));
+// condition ? level += "#" : level += " ";
+
+// // if((midpoint - row <= column) && (midpoint + row >= column)) {
+// // level += '#';
+// // } else {
+// // level += ' ';
+// // }
+// }
+// console.log(level);
+// }
+// }
+
+function pyramid(n, row =0, level = '') {
+ if(row === n) {
+ return;
+ }
+ if(level.length === 2 * n - 1) {
+ console.log(level);
+ return pyramid(n, row + 1);
+ }
+
+ const midpoint = Math.floor((2 * n - 1) / 2);
+ let add;
+
+ const condition = ((midpoint - row <= level.length) && (midpoint + row >= level.length));
+ condition ? add = "#" : add = " ";
+
+ // if((midpoint - row <= level.length) && (midpoint + row >= level.length)) {
+ // add = '#';
+ // } else {
+ // add = ' ';
+ // }
+
+ pyramid(n, row, level + add);
+}
+
+
+
+module.exports = pyramid;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/pyramid/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/pyramid/test.js
new file mode 100644
index 0000000..8ffc318
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/pyramid/test.js
@@ -0,0 +1,37 @@
+const pyramid = require('./index');
+
+beforeEach(() => {
+ jest.spyOn(console, 'log');
+});
+
+afterEach(() => {
+ console.log.mockRestore();
+});
+
+test('pyramid is a function', () => {
+ expect(typeof pyramid).toEqual('function');
+});
+
+test('prints a pryamid for n = 2', () => {
+ pyramid(2);
+ expect(console.log.mock.calls[0][0]).toEqual(' # ');
+ expect(console.log.mock.calls[1][0]).toEqual('###');
+ expect(console.log.mock.calls.length).toEqual(2);
+});
+
+test('prints a pryamid for n = 3', () => {
+ pyramid(3);
+ expect(console.log.mock.calls[0][0]).toEqual(' # ');
+ expect(console.log.mock.calls[1][0]).toEqual(' ### ');
+ expect(console.log.mock.calls[2][0]).toEqual('#####');
+ expect(console.log.mock.calls.length).toEqual(3);
+});
+
+test('prints a pryamid for n = 4', () => {
+ pyramid(4);
+ expect(console.log.mock.calls[0][0]).toEqual(' # ');
+ expect(console.log.mock.calls[1][0]).toEqual(' ### ');
+ expect(console.log.mock.calls[2][0]).toEqual(' ##### ');
+ expect(console.log.mock.calls[3][0]).toEqual('#######');
+ expect(console.log.mock.calls.length).toEqual(4);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/qfroms/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/qfroms/index.js
new file mode 100644
index 0000000..c575ca1
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/qfroms/index.js
@@ -0,0 +1,58 @@
+// --- Directions
+// Implement a Queue datastructure using two stacks.
+// *Do not* create an array inside of the 'Queue' class.
+// Queue should implement the methods 'add', 'remove', and 'peek'.
+// For a reminder on what each method does, look back
+// at the Queue exercise.
+// --- Examples
+// const q = new Queue();
+// q.add(1);
+// q.add(2);
+// q.peek(); // returns 1
+// q.remove(); // returns 1
+// q.remove(); // returns 2
+
+const Stack = require('./stack');
+
+class Queue {
+ constructor() {
+ this.first = new Stack();
+ this.second = new Stack();
+ }
+
+ add(record) {
+ this.first.push(record);
+ }
+
+ remove() {
+ while(this.first.peek()){
+ // let record = this.first.pop();
+ this.second.push(this.first.pop());
+
+ }
+
+ const record = this.second.pop();
+
+ while(this.second.peek()) {
+ this.first.push(this.second.pop());
+ }
+
+ return record;
+ }
+
+ peek() {
+ while(this.first.peek()) {
+ this.second.push(this.first.pop());
+ }
+
+ const record = this.second.peek();
+
+ while(this.second.peek()){
+ this.first.push(this.second.pop());
+ }
+
+ return record;
+ }
+}
+
+module.exports = Queue;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/qfroms/stack.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/qfroms/stack.js
new file mode 100644
index 0000000..2032acb
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/qfroms/stack.js
@@ -0,0 +1,19 @@
+class Stack {
+ constructor() {
+ this.data = [];
+ }
+
+ push(record) {
+ this.data.push(record);
+ }
+
+ pop() {
+ return this.data.pop();
+ }
+
+ peek() {
+ return this.data[this.data.length - 1];
+ }
+}
+
+module.exports = Stack;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/qfroms/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/qfroms/test.js
new file mode 100644
index 0000000..3fc84c7
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/qfroms/test.js
@@ -0,0 +1,41 @@
+const Queue = require('./index');
+
+test('Queue is a class', () => {
+ expect(typeof Queue.prototype.constructor).toEqual('function');
+});
+
+test('can add elements to a queue', () => {
+ const q = new Queue();
+ expect(() => {
+ q.add(1);
+ }).not.toThrow();
+});
+
+test('can remove elements from a queue', () => {
+ const q = new Queue();
+ expect(() => {
+ q.add(1);
+ q.remove();
+ }).not.toThrow();
+});
+
+test('Order of elements is maintained', () => {
+ const q = new Queue();
+ q.add(1);
+ q.add(2);
+ q.add(3);
+ expect(q.remove()).toEqual(1);
+ expect(q.remove()).toEqual(2);
+ expect(q.remove()).toEqual(3);
+ expect(q.remove()).toEqual(undefined);
+});
+
+test('peek returns, but does not remove, the first value', () => {
+ const q = new Queue();
+ q.add(1);
+ q.add(2);
+ expect(q.peek()).toEqual(1);
+ expect(q.peek()).toEqual(1);
+ expect(q.remove()).toEqual(1);
+ expect(q.remove()).toEqual(2);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/queue/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/queue/index.js
new file mode 100644
index 0000000..ca98ee9
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/queue/index.js
@@ -0,0 +1,30 @@
+// --- Description
+// Create a queue data structure. The queue
+// should be a class with methods 'add' and 'remove'.
+// Adding to the queue should store an element until
+// it is removed
+// --- Examples
+// const q = new Queue();
+// q.add(1);
+// q.remove(); // returns 1;
+
+class Queue {
+
+ constructor() {
+ this.data = [];
+ }
+
+ add(record) {
+ this.data.unshift(record);
+ }
+
+ remove() {
+ return this.data.pop();
+ }
+
+ peek() {
+ return this.data[this.data.length - 1];
+ }
+}
+
+module.exports = Queue;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/queue/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/queue/test.js
new file mode 100644
index 0000000..867bd42
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/queue/test.js
@@ -0,0 +1,31 @@
+const Queue = require('./index');
+
+test('Queue is a class', () => {
+ expect(typeof Queue.prototype.constructor).toEqual('function');
+});
+
+test('can add elements to a queue', () => {
+ const q = new Queue();
+ expect(() => {
+ q.add(1);
+ }).not.toThrow();
+});
+
+test('can remove elements from a queue', () => {
+ const q = new Queue();
+ expect(() => {
+ q.add(1);
+ q.remove();
+ }).not.toThrow();
+});
+
+test('Order of elements is maintained', () => {
+ const q = new Queue();
+ q.add(1);
+ q.add(2);
+ q.add(3);
+ expect(q.remove()).toEqual(1);
+ expect(q.remove()).toEqual(2);
+ expect(q.remove()).toEqual(3);
+ expect(q.remove()).toEqual(undefined);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/reverseint/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/reverseint/index.js
new file mode 100644
index 0000000..822e9d3
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/reverseint/index.js
@@ -0,0 +1,17 @@
+// --- Directions
+// Given an integer, return an integer that is the reverse
+// ordering of numbers.
+// --- Examples
+// reverseInt(15) === 51
+// reverseInt(981) === 189
+// reverseInt(500) === 5
+// reverseInt(-15) === -51
+// reverseInt(-90) === -9
+
+function reverseInt(n) {
+ const reversed = n.toString().split('').reverse().join('');
+
+ return Math.sign(n) * parseInt(reversed);
+}
+
+module.exports = reverseInt;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/reverseint/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/reverseint/test.js
new file mode 100644
index 0000000..e5092e2
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/reverseint/test.js
@@ -0,0 +1,23 @@
+const reverseInt = require('./index');
+
+test('ReverseInt function exists', () => {
+ expect(reverseInt).toBeDefined();
+});
+
+test('ReverseInt handles 0 as an input', () => {
+ expect(reverseInt(0)).toEqual(0);
+});
+
+test('ReverseInt flips a positive number', () => {
+ expect(reverseInt(5)).toEqual(5);
+ expect(reverseInt(15)).toEqual(51);
+ expect(reverseInt(90)).toEqual(9);
+ expect(reverseInt(2359)).toEqual(9532);
+});
+
+test('ReverseInt flips a negative number', () => {
+ expect(reverseInt(-5)).toEqual(-5);
+ expect(reverseInt(-15)).toEqual(-51);
+ expect(reverseInt(-90)).toEqual(-9);
+ expect(reverseInt(-2359)).toEqual(-9532);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/reversestring/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/reversestring/index.js
new file mode 100644
index 0000000..bc4cc56
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/reversestring/index.js
@@ -0,0 +1,68 @@
+// --- Directions
+// Given a string, return a new string with the reversed
+// order of characters
+// --- Examples
+// reverse('apple') === 'leppa'
+// reverse('hello') === 'olleh'
+// reverse('Greetings!') === '!sgniteerG'
+
+// function reverse(str) {
+// // recursive soltuion
+// if (str.length <= 1) {return str};
+// return reverse(str.slice(1)) +str[0];
+// }
+
+
+// function reverse(str) {
+// // reverse loop through string
+// res = ""
+// for (let i = str.length-1; i >= 0; i--){
+// res += str[i];
+// }
+// return res;
+// }
+
+// function reverse(str) {
+// // split reverse join solution
+
+// return str.split("").reverse().join("");
+// }
+
+
+// function reverse(str){
+// let reversed = '';
+
+// for (let character of str) {
+// reversed = character + reversed;
+// }
+// return reversed;
+// }
+
+
+function reverse(str) {
+ return str.split('').reduce((reversed, character) => {
+ return character + reversed;
+ }, "")
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+module.exports = reverse;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/reversestring/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/reversestring/test.js
new file mode 100644
index 0000000..8d264c0
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/reversestring/test.js
@@ -0,0 +1,13 @@
+const reverse = require('./index');
+
+test('Reverse function exists', () => {
+ expect(reverse).toBeDefined();
+});
+
+test('Reverse reverses a string', () => {
+ expect(reverse('abcd')).toEqual('dcba');
+});
+
+test('Reverse reverses a string', () => {
+ expect(reverse(' abcd')).toEqual('dcba ');
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/sorting/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/sorting/index.js
new file mode 100644
index 0000000..efd32e0
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/sorting/index.js
@@ -0,0 +1,68 @@
+// --- Directions
+// Implement bubbleSort, selectionSort, and mergeSort
+
+function bubbleSort(arr) {
+
+ for (let i = 0; i < arr.length; i++) {
+ for(let j =0; j < arr.length - i - 1; j++){
+
+ if(arr[j] > arr[j+1]){
+ const temp = arr[j+1];
+ arr[j + 1] = arr[j];
+ arr[j] = temp;
+ }
+ }
+ }
+ return arr;
+}
+
+function selectionSort(arr) {
+
+ for (let i = 0; i < arr.length; i++){
+ let indexOfMin = i;
+
+ for(let j = i + 1; j < arr.length; j++){
+ if(arr[j] < arr[indexOfMin]){
+ indexOfMin = j;
+ }
+ }
+
+ if(indexOfMin !== i) {
+ let temp = arr[indexOfMin];
+ arr[indexOfMin] = arr[i];
+ arr[i] = temp;
+ }
+ }
+ return arr;
+}
+
+function mergeSort(arr) {
+ if(arr.length === 1){
+ return arr;
+ }
+
+ const center = Math.floor(arr.length / 2);
+ const left = arr.slice(0, center);
+ const right = arr.slice(center);
+
+ return merge(mergeSort(left), mergeSort(right));
+
+
+
+}
+
+function merge(left, right) {
+ const results = [];
+
+ while(left.length && right.length) {
+ if(left[0] < right[0]){
+ results.push(left.shift());
+ }else {
+ results.push(right.shift());
+ }
+ }
+
+ return [...results, ...left, ...right];
+}
+
+module.exports = { bubbleSort, selectionSort, mergeSort, merge };
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/sorting/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/sorting/test.js
new file mode 100644
index 0000000..0ff475b
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/sorting/test.js
@@ -0,0 +1,38 @@
+const S = require('./index');
+const bubbleSort = S.bubbleSort;
+const selectionSort = S.selectionSort;
+const mergeSort = S.mergeSort;
+const merge = S.merge;
+
+function getArray() {
+ return [100, -40, 500, -124, 0, 21, 7];
+}
+
+function getSortedArray() {
+ return [-124, -40, 0, 7, 21, 100, 500];
+}
+
+describe('Bubble sort', () => {
+ test('sorts an array', () => {
+ expect(bubbleSort(getArray())).toEqual(getSortedArray());
+ });
+});
+
+describe('Selection sort', () => {
+ test('sorts an array', () => {
+ expect(selectionSort(getArray())).toEqual(getSortedArray());
+ });
+});
+
+describe('Merge sort', () => {
+ test('merge function can join together two sorted arrays', () => {
+ const left = [1, 10];
+ const right = [2, 8, 12];
+
+ expect(merge(left, right)).toEqual([1,2,8,10,12]);
+ });
+
+ test('sorts an array', () => {
+ expect(mergeSort(getArray())).toEqual(getSortedArray());
+ });
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/stack/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/stack/index.js
new file mode 100644
index 0000000..efc8fa5
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/stack/index.js
@@ -0,0 +1,32 @@
+// --- Directions
+// Create a stack data structure. The stack
+// should be a class with methods 'push', 'pop', and
+// 'peek'. Adding an element to the stack should
+// store it until it is removed.
+// --- Examples
+// const s = new Stack();
+// s.push(1);
+// s.push(2);
+// s.pop(); // returns 2
+// s.pop(); // returns 1
+
+class Stack {
+
+ constructor() {
+ this.data = [];
+ }
+
+ push(record) {
+ this.data.push(record);
+ }
+
+ pop() {
+ return this.data.pop();
+ }
+
+ peek() {
+ return this.data[this.data.length - 1];
+ }
+}
+
+module.exports = Stack;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/stack/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/stack/test.js
new file mode 100644
index 0000000..457e5a2
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/stack/test.js
@@ -0,0 +1,36 @@
+const Stack = require('./index');
+
+test('Stack is a class', () => {
+ expect(typeof Stack.prototype.constructor).toEqual('function');
+});
+
+test('stack can add and remove items', () => {
+ const s = new Stack();
+ s.push(1);
+ expect(s.pop()).toEqual(1);
+ s.push(2);
+ expect(s.pop()).toEqual(2);
+});
+
+test('stack can follows first in, last out', () => {
+ const s = new Stack();
+ s.push(1);
+ s.push(2);
+ s.push(3);
+ expect(s.pop()).toEqual(3);
+ expect(s.pop()).toEqual(2);
+ expect(s.pop()).toEqual(1);
+});
+
+test('peek returns the first element but doesnt pop it', () => {
+ const s = new Stack();
+ s.push(1);
+ s.push(2);
+ s.push(3);
+ expect(s.peek()).toEqual(3);
+ expect(s.pop()).toEqual(3);
+ expect(s.peek()).toEqual(2);
+ expect(s.pop()).toEqual(2);
+ expect(s.peek()).toEqual(1);
+ expect(s.pop()).toEqual(1);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/steps/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/steps/index.js
new file mode 100644
index 0000000..7e9e9ed
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/steps/index.js
@@ -0,0 +1,52 @@
+// --- Directions
+// Write a function that accepts a positive number N.
+// The function should console log a step shape
+// with N levels using the # character. Make sure the
+// step has spaces on the right hand side!
+// --- Examples
+// steps(2)
+// '# '
+// '##'
+// steps(3)
+// '# '
+// '## '
+// '###'
+// steps(4)
+// '# '
+// '## '
+// '### '
+// '####'
+
+// function steps(n) {
+// for(let row = 0; row < n; row++) {
+// let stair = "";
+
+// for(let column = 0; column < n; column++){
+// if(column <= row) {
+// stair += '#';
+// } else {
+// stair += ' ';
+// }
+// }
+// console.log(stair);
+// }
+// }
+
+function steps(n, row=0, stair = '') {
+ if (n === row) {
+ return;
+ }
+
+ if(n === stair.length) {
+ console.log(stair);
+ return steps(n, row + 1);
+ }
+
+ const add = stair.length <= row ? '#' : ' ';
+ steps(n, row, stair + add);
+}
+
+
+
+
+module.exports = steps;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/steps/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/steps/test.js
new file mode 100644
index 0000000..007af11
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/steps/test.js
@@ -0,0 +1,34 @@
+const steps = require('./index');
+
+beforeEach(() => {
+ jest.spyOn(console, 'log');
+});
+
+afterEach(() => {
+ console.log.mockRestore();
+});
+
+test('steps is a function', () => {
+ expect(typeof steps).toEqual('function');
+});
+
+test('steps called with n = 1', () => {
+ steps(1);
+ expect(console.log.mock.calls[0][0]).toEqual('#');
+ expect(console.log.mock.calls.length).toEqual(1);
+});
+
+test('steps called with n = 2', () => {
+ steps(2);
+ expect(console.log.mock.calls[0][0]).toEqual('# ');
+ expect(console.log.mock.calls[1][0]).toEqual('##');
+ expect(console.log.mock.calls.length).toEqual(2);
+});
+
+test('steps called with n = 3', () => {
+ steps(3);
+ expect(console.log.mock.calls[0][0]).toEqual('# ');
+ expect(console.log.mock.calls[1][0]).toEqual('## ');
+ expect(console.log.mock.calls[2][0]).toEqual('###');
+ expect(console.log.mock.calls.length).toEqual(3);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/tree/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/tree/index.js
new file mode 100644
index 0000000..f69a05d
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/tree/index.js
@@ -0,0 +1,61 @@
+// --- Directions
+// 1) Create a node class. The constructor
+// should accept an argument that gets assigned
+// to the data property and initialize an
+// empty array for storing children. The node
+// class should have methods 'add' and 'remove'.
+// 2) Create a tree class. The tree constructor
+// should initialize a 'root' property to null.
+// 3) Implement 'traverseBF' and 'traverseDF'
+// on the tree class. Each method should accept a
+// function that gets called with each element in the tree
+
+class Node {
+ constructor(data){
+ this.data = data;
+ this.children = [];
+ }
+
+ add(data){
+ // const node = new Node(data);
+ this.children.push(new Node(data));
+ }
+
+ remove(data){
+ this.children = this.children.filter(node => {
+ return node.data != data;
+ });
+ }
+
+}
+
+class Tree {
+ constructor(){
+ this.root = null;
+ }
+
+ traverseBF(fn){
+ const arr = [this.root];
+ while(arr.length){
+ const node = arr.shift();
+
+ arr.push(...node.children);
+ fn(node);
+ // for(let child of node.children){
+ // arr.push(child);
+ // }
+ }
+ }
+
+ traverseDF(fn){
+ const arr = [this.root];
+ while(arr.length){
+ const node = arr.shift();
+
+ arr.unshift(...node.children);
+ fn(node);
+ }
+ }
+}
+
+module.exports = { Tree, Node };
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/tree/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/tree/test.js
new file mode 100644
index 0000000..69dab5d
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/tree/test.js
@@ -0,0 +1,67 @@
+const T = require('./index');
+const Node = T.Node;
+const Tree = T.Tree;
+
+describe('Node', () => {
+ test('Node is a constructor', () => {
+ expect(typeof Node.prototype.constructor).toEqual('function');
+ });
+
+ test('Node has a data and children properties', () => {
+ const n = new Node('a');
+ expect(n.data).toEqual('a');
+ expect(n.children.length).toEqual(0);
+ });
+
+ test('Node can add children', () => {
+ const n = new Node('a');
+ n.add('b');
+ expect(n.children.length).toEqual(1);
+ expect(n.children[0].children).toEqual([]);
+ });
+
+ test('Node can remove children', () => {
+ const n = new Node('a');
+ n.add('b');
+ expect(n.children.length).toEqual(1);
+ n.remove('b');
+ expect(n.children.length).toEqual(0);
+ });
+});
+
+describe('Tree', () => {
+ test('starts empty', () => {
+ const t = new Tree();
+ expect(t.root).toEqual(null);
+ });
+
+ test('Can traverse bf', () => {
+ const letters = [];
+ const t = new Tree();
+ t.root = new Node('a');
+ t.root.add('b');
+ t.root.add('c');
+ t.root.children[0].add('d');
+
+ t.traverseBF(node => {
+ letters.push(node.data);
+ });
+
+ expect(letters).toEqual(['a', 'b', 'c', 'd']);
+ });
+
+ test('Can traverse DF', () => {
+ const letters = [];
+ const t = new Tree();
+ t.root = new Node('a');
+ t.root.add('b');
+ t.root.add('d');
+ t.root.children[0].add('c');
+
+ t.traverseDF(node => {
+ letters.push(node.data);
+ });
+
+ expect(letters).toEqual(['a', 'b', 'c', 'd']);
+ });
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/validate/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/validate/index.js
new file mode 100644
index 0000000..e9c3fc9
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/validate/index.js
@@ -0,0 +1,29 @@
+// --- Directions
+// Given a node, validate the binary search tree,
+// ensuring that every node's left hand child is
+// less than the parent node's value, and that
+// every node's right hand child is greater than
+// the parent
+
+function validate(node, min = null, max = null) {
+
+ if(max !== null && node.data > max){
+ return false;
+ }
+
+ if(min !== null && node.data < min){
+ return false;
+ }
+
+ if(node.left && !validate(node.left, min, node.data)){
+ return false;
+ }
+
+ if(node.right && !validate(node.right, node.data, max)){
+ return false;
+ }
+
+ return true;
+}
+
+module.exports = validate;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/validate/node.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/validate/node.js
new file mode 100644
index 0000000..d19e208
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/validate/node.js
@@ -0,0 +1,21 @@
+class Node {
+ constructor(data) {
+ this.data = data;
+ this.left = null;
+ this.right = null;
+ }
+
+ insert(data) {
+ if (data < this.data && this.left) {
+ this.left.insert(data);
+ } else if (data < this.data) {
+ this.left = new Node(data);
+ } else if (data > this.data && this.right) {
+ this.right.insert(data);
+ } else if (data > this.data) {
+ this.right = new Node(data);
+ }
+ }
+}
+
+module.exports = Node;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/validate/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/validate/test.js
new file mode 100644
index 0000000..6ea4dc3
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/validate/test.js
@@ -0,0 +1,23 @@
+const Node = require('./node');
+const validate = require('./index');
+
+test('Validate recognizes a valid BST', () => {
+ const n = new Node(10);
+ n.insert(5);
+ n.insert(15);
+ n.insert(0);
+ n.insert(20);
+
+ expect(validate(n)).toEqual(true);
+});
+
+test('Validate recognizes an invalid BST', () => {
+ const n = new Node(10);
+ n.insert(5);
+ n.insert(15);
+ n.insert(0);
+ n.insert(20);
+ n.left.left.right = new Node(999);
+
+ expect(validate(n)).toEqual(false);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/vowels/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/vowels/index.js
new file mode 100644
index 0000000..a274eac
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/vowels/index.js
@@ -0,0 +1,29 @@
+// --- Directions
+// Write a function that returns the number of vowels
+// used in a string. Vowels are the characters 'a', 'e'
+// 'i', 'o', and 'u'.
+// --- Examples
+// vowels('Hi There!') --> 3
+// vowels('Why do you ask?') --> 4
+// vowels('Why?') --> 0
+
+// function vowels(str) {
+// let count = 0;
+
+// const checker = ['a', 'e', 'i', 'o', 'u']
+
+// for (let char of str.toLowerCase()) {
+// if(checker.includes(char)){
+// count++;
+// }
+// }
+// return count;
+// }
+
+function vowels(str) {
+ const matches = str.match(/[aeiou]/gi);
+ return matches ? matches.length : 0;
+}
+
+
+module.exports = vowels;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/vowels/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/vowels/test.js
new file mode 100644
index 0000000..6283592
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/vowels/test.js
@@ -0,0 +1,21 @@
+const vowels = require('./index');
+
+test('Vowels is a function', () => {
+ expect(typeof vowels).toEqual('function');
+});
+
+test('returns the number of vowels used', () => {
+ expect(vowels('aeiou')).toEqual(5);
+});
+
+test('returns the number of vowels used when they are capitalized', () => {
+ expect(vowels('AEIOU')).toEqual(5);
+});
+
+test('returns the number of vowels used', () => {
+ expect(vowels('abcdefghijklmnopqrstuvwxyz')).toEqual(5);
+});
+
+test('returns the number of vowels used', () => {
+ expect(vowels('bcdfghjkl')).toEqual(0);
+});
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/weave/index.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/weave/index.js
new file mode 100644
index 0000000..480c108
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/weave/index.js
@@ -0,0 +1,45 @@
+// --- Directions
+// 1) Complete the task in weave/queue.js
+// 2) Implement the 'weave' function. Weave
+// receives two queues as arguments and combines the
+// contents of each into a new, third queue.
+// The third queue should contain the *alterating* content
+// of the two queues. The function should handle
+// queues of different lengths without inserting
+// 'undefined' into the new one.
+// *Do not* access the array inside of any queue, only
+// use the 'add', 'remove', and 'peek' functions.
+// --- Example
+// const queueOne = new Queue();
+// queueOne.add(1);
+// queueOne.add(2);
+// const queueTwo = new Queue();
+// queueTwo.add('Hi');
+// queueTwo.add('There');
+// const q = weave(queueOne, queueTwo);
+// q.remove() // 1
+// q.remove() // 'Hi'
+// q.remove() // 2
+// q.remove() // 'There'
+
+const Queue = require('./queue');
+
+function weave(sourceOne, sourceTwo) {
+
+ const q = new Queue();
+
+ while(sourceOne.peek() || sourceTwo.peek()) {
+
+ if(sourceOne.peek()) {
+ q.add(sourceOne.remove());
+ }
+ if(sourceTwo.peek()) {
+ q.add(sourceTwo.remove());
+ }
+ }
+
+ return q;
+
+}
+
+module.exports = weave;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/weave/queue.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/weave/queue.js
new file mode 100644
index 0000000..fe93359
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/weave/queue.js
@@ -0,0 +1,26 @@
+// --- Directions
+// Implement a 'peek' method in this Queue class.
+// Peek should return the last element (the next
+// one to be returned) from the queue *without*
+// removing it.
+
+class Queue {
+ constructor() {
+ this.data = [];
+ }
+
+ add(record) {
+ this.data.unshift(record);
+ }
+
+ remove() {
+ return this.data.pop();
+ }
+
+ peek() {
+ return this.data[this.data.length - 1];
+ }
+
+}
+
+module.exports = Queue;
diff --git a/Grider-Stephen-AlgoCasts-JS-Practice/exercises/weave/test.js b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/weave/test.js
new file mode 100644
index 0000000..f173360
--- /dev/null
+++ b/Grider-Stephen-AlgoCasts-JS-Practice/exercises/weave/test.js
@@ -0,0 +1,45 @@
+const weave = require('./index');
+const Queue = require('./queue');
+
+test('queues have a peek function', () => {
+ const q = new Queue();
+ expect(typeof q.peek).toEqual('function');
+});
+
+test('peek returns, but does not remove, the first value', () => {
+ const q = new Queue();
+ q.add(1);
+ q.add(2);
+ expect(q.peek()).toEqual(1);
+ expect(q.peek()).toEqual(1);
+ expect(q.remove()).toEqual(1);
+ expect(q.remove()).toEqual(2);
+});
+
+test('weave is a function', () => {
+ expect(typeof weave).toEqual('function');
+});
+
+test('weave can combine two queues', () => {
+ const one = new Queue();
+ one.add(1);
+ one.add(2);
+ one.add(3);
+ one.add(4);
+ const two = new Queue();
+ two.add('one');
+ two.add('two');
+ two.add('three');
+ two.add('four');
+
+ const result = weave(one, two);
+ expect(result.remove()).toEqual(1);
+ expect(result.remove()).toEqual('one');
+ expect(result.remove()).toEqual(2);
+ expect(result.remove()).toEqual('two');
+ expect(result.remove()).toEqual(3);
+ expect(result.remove()).toEqual('three');
+ expect(result.remove()).toEqual(4);
+ expect(result.remove()).toEqual('four');
+ expect(result.remove()).toBeUndefined();
+});
diff --git a/Nguyen-Kevin-JS-Leet-Practice/longestSubstring.js b/Nguyen-Kevin-JS-Leet-Practice/longestSubstring.js
new file mode 100644
index 0000000..25e1840
--- /dev/null
+++ b/Nguyen-Kevin-JS-Leet-Practice/longestSubstring.js
@@ -0,0 +1,17 @@
+function lengthOfLongestSubstring(s) {
+ let windowCharsMap = {};
+ let windowStart = 0;
+ let maxLength = 0;
+
+ for (let i =0; i < s.length; i++) {
+ const endChar = s[i];
+
+ if(windowCharsMap[endChar] >= windowStart) {
+ windowStart = windowCharsMap[endChar] + 1;
+ }
+
+ windowCharsMap[endChar] = i;
+ maxLength = Math.max(maxLength, i - windowStart + 1);
+ }
+ return maxLength;
+}
\ No newline at end of file
diff --git a/Nguyen-Kevin-JS-Leet-Practice/palindrome.js b/Nguyen-Kevin-JS-Leet-Practice/palindrome.js
new file mode 100644
index 0000000..a0f1fb3
--- /dev/null
+++ b/Nguyen-Kevin-JS-Leet-Practice/palindrome.js
@@ -0,0 +1,17 @@
+
+function isParlindrome(s){
+ s =s.toLowerCase().replace(/[^\w]/g, "");
+
+ let left = 0;
+ let right = s.length -1;
+
+ while(left < right) {
+ if (s[left] !== s[right]){
+ return false;
+ }
+ left++;
+ right--;
+ }
+ return true;
+}
+
diff --git a/Traub-Eric-JS-Practice/6_hoisting.js b/Traub-Eric-JS-Practice/6_hoisting.js
index e69de29..465f1b0 100644
--- a/Traub-Eric-JS-Practice/6_hoisting.js
+++ b/Traub-Eric-JS-Practice/6_hoisting.js
@@ -0,0 +1,101 @@
+/* ex 1
+first console log fails
+due to variable hoisting
+before variable assignment
+*/
+
+console.log(color);
+var color = "red";
+console.log(color);
+
+
+
+//ex 2
+var color;
+console.log(color);
+color = "orange";
+console.log(color);
+
+
+
+// ex 3
+/*
+function expression vs
+function declaration
+*/
+
+console.log(getProduct(2, 3));
+var getProduct = function(num1, num2) {
+ return num1 * num2;
+};
+console.log(getProduct(2, 3));
+
+
+
+// ex 4
+
+console.log(getProduct(2, 3));
+function getProduct(num1, num2) {
+ return num1 * num2;
+}
+
+
+
+// ex 5
+/*
+hoisting of varibles only
+occur within encompassing function
+*/
+
+var globalVar = 'global';
+(function() {
+ var name = 'Jen';
+ var getAge = function() {
+ return '30';
+ };
+ function getState() {
+ return 'Delaware';
+ }
+})();
+
+
+// ex 6
+
+function getTotal() {
+ console.log(multiplier);
+ console.log(total);
+
+ let total = 0;
+ for(var i = 0; i < 10; i++) {
+ let valueToAdd = i;
+ var multiplier = 2;
+ total += valueToAdd * multiplier;
+ }
+ return total;
+ }
+ getTotal();
+
+
+
+ // ex 7
+ /*
+ keywords with let, const are not initialized
+ until they are declared
+ */
+
+ function getTotal() {
+ let total;
+ var multiplier;
+
+ total = 0;
+
+ for(var i = 0; i < 10; i++) {
+ let valueToAdd;
+ valueToAdd = i;
+ multiplier = 2;
+ total += valueToAdd * multiplier;
+ }
+ return total;
+ }
+
+ getTotal();
\ No newline at end of file
diff --git a/Traversy_Brad_Modern_JS/index.html b/Traversy_Brad_Modern_JS/index.html
new file mode 100644
index 0000000..f15b337
--- /dev/null
+++ b/Traversy_Brad_Modern_JS/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+ Document
+
+
+