├── .rspec ├── problems ├── transpose.js ├── my_each.js ├── my_flatten.js ├── my_rotate.js ├── my_some.js ├── my_every.js ├── my_filter.js ├── my_join.js ├── my_reject.js ├── my_reverse.js ├── bubble_sort.js ├── my_curry.js ├── my_call.js ├── subsets.js ├── my_bind.js ├── doubler.js ├── inherits.js ├── factors.js ├── rec_sum.js ├── quicksort.js ├── exponent.js ├── permutations.js ├── first_even_numbers_sum.js ├── fibs_sum.js ├── primes.js ├── my_slice.js ├── binary_search.js ├── deep_dup.js ├── titleize.js ├── median.js ├── my_find.js ├── merge_sort.js ├── prime_factorization.js ├── pig_latinify.js ├── real_words_in_string.js ├── my_inject.js ├── factorials_rec.js ├── symmetric_substrings.js ├── base_converter.js ├── dups.js ├── string_include_key.js ├── jumble_sort.js ├── digital_root.js ├── two_sum.js └── caesar_cipher.js ├── solutions ├── doubler_solution.js ├── my_apply_solution.js ├── my_call_solution.js ├── deep_dup_solution.js ├── rec_sum_solution.js ├── first_even_numbers_sum_solution.js ├── fibs_sum_solution.js ├── my_each_solution.js ├── factors_solution.js ├── my_bind_solution.js ├── my_every_solution.js ├── my_find_solution.js ├── my_some_solution.js ├── factorials_rec_solution.js ├── my_filter_solution.js ├── exponent_solution.js ├── my_reverse_solution.js ├── inherits_solution.js ├── my_reject_solution.js ├── my_inject_solution.js ├── my_join_solution.js ├── two_sum_solution.js ├── base_converter_solution.js ├── my_slice_solution.js ├── my_flatten_solution.js ├── string_include_key_solution.js ├── subsets_solution.js ├── median_solution.js ├── my_curry_solution.js ├── digital_root_solution.js ├── my_rotate_solution.js ├── prime_factorization_solution.js ├── transpose_solution.js ├── primes_solution.js ├── dups_solution.js ├── caesar_cipher_solution.js ├── symmetric_substrings_solution.js ├── titleize_solution.js ├── permutations_solution.js ├── binary_search_solution.js ├── quicksort_solution.js ├── jumble_sort_solution.js ├── bubble_sort_solution.js ├── pig_latinify_solution.js ├── real_words_in_string_solution.js └── merge_sort_solution.js ├── lib └── jasmine-2.5.2 │ ├── jasmine_favicon.png │ ├── boot.js │ ├── console.js │ ├── jasmine-html.js │ └── jasmine.css ├── Gemfile ├── specs ├── my_flatten_spec.js ├── my_reverse_spec.js ├── support │ └── jasmine.json ├── subsets_spec.js ├── factors_spec.js ├── primes_spec.js ├── rec_sum_spec.js ├── base_converter_spec.js ├── first_even_numbers_sum_spec.js ├── permutations_spec.js ├── my_join_spec.js ├── exponent_spec.js ├── caesar_cipher_spec.js ├── doubler_spec.js ├── prime_factorization_spec.js ├── my_each_spec.js ├── my_some_spec.js ├── fibs_sum_spec.js ├── symmetric_substrings_spec.js ├── my_every_spec.js ├── my_filter_spec.js ├── my_find_spec.js ├── my_reject_spec.js ├── digital_root_spec.js ├── dups_spec.js ├── deep_dup_spec.js ├── jumble_sort_spec.js ├── median_spec.js ├── real_words_in_string_spec.js ├── titleize_spec.js ├── factorials_rec_spec.js ├── my_rotate_spec.js ├── quicksort_spec.js ├── two_sum_spec.js ├── string_include_key_spec.js ├── my_curry_spec.js ├── bubble_sort_spec.js ├── merge_sort_spec.js ├── binary_search_spec.js ├── my_slice_spec.js ├── my_inject_spec.js ├── transpose_spec.js ├── pig_latinify_spec.js ├── my_call_spec.js ├── my_bind_spec.js └── inherits_spec.js ├── SpecRunner.html ├── MIT.LICENSE ├── README.md ├── generator.rb └── list.csv /.rspec: -------------------------------------------------------------------------------- 1 | --format=documentation 2 | --color 3 | -------------------------------------------------------------------------------- /problems/transpose.js: -------------------------------------------------------------------------------- 1 | function transpose(arr) { 2 | 3 | }; 4 | -------------------------------------------------------------------------------- /problems/my_each.js: -------------------------------------------------------------------------------- 1 | Array.prototype.myEach = function (func) { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /problems/my_flatten.js: -------------------------------------------------------------------------------- 1 | Array.prototype.flatten = function () { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /problems/my_rotate.js: -------------------------------------------------------------------------------- 1 | Array.prototype.rotate = function (num) { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /problems/my_some.js: -------------------------------------------------------------------------------- 1 | Array.prototype.mySome = function (func) { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /problems/my_every.js: -------------------------------------------------------------------------------- 1 | Array.prototype.myEvery = function (func) { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /problems/my_filter.js: -------------------------------------------------------------------------------- 1 | Array.prototype.myFilter = function (func) { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /problems/my_join.js: -------------------------------------------------------------------------------- 1 | Array.prototype.myJoin = function (separator) { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /problems/my_reject.js: -------------------------------------------------------------------------------- 1 | Array.prototype.reject = function (func) { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /problems/my_reverse.js: -------------------------------------------------------------------------------- 1 | Array.prototype.myReverse = function () { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /problems/bubble_sort.js: -------------------------------------------------------------------------------- 1 | Array.prototype.bubbleSort = function (func) { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /problems/my_curry.js: -------------------------------------------------------------------------------- 1 | Function.prototype.myCurry = function (numArgs) { 2 | 3 | }; 4 | -------------------------------------------------------------------------------- /problems/my_call.js: -------------------------------------------------------------------------------- 1 | Function.prototype.myCall = function (ctx, ...args) { 2 | 3 | }; 4 | -------------------------------------------------------------------------------- /problems/subsets.js: -------------------------------------------------------------------------------- 1 | // returns all subsets of an array 2 | 3 | function subsets(array) { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /solutions/doubler_solution.js: -------------------------------------------------------------------------------- 1 | function doubler(array) { 2 | return array.map( el => el * 2 ); 3 | } 4 | -------------------------------------------------------------------------------- /problems/my_bind.js: -------------------------------------------------------------------------------- 1 | // write Function.prototype.myBind. 2 | Function.prototype.myBind = function () { 3 | 4 | } 5 | -------------------------------------------------------------------------------- /problems/doubler.js: -------------------------------------------------------------------------------- 1 | // Write a method that doubles each element in an array 2 | 3 | function doubler(array) { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /problems/inherits.js: -------------------------------------------------------------------------------- 1 | // write Function.prototype.inherits. 2 | 3 | Function.prototype.inherits = function () { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /solutions/my_apply_solution.js: -------------------------------------------------------------------------------- 1 | Function.prototype.myApply = function (ctx, ...args) { 2 | return this.bind(ctx, ...args)(); 3 | }; 4 | -------------------------------------------------------------------------------- /solutions/my_call_solution.js: -------------------------------------------------------------------------------- 1 | Function.prototype.myCall = function (ctx, ...args) { 2 | return this.bind(ctx, ...args)(); 3 | }; 4 | -------------------------------------------------------------------------------- /lib/jasmine-2.5.2/jasmine_favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souiukoto/javascript-test-generator/HEAD/lib/jasmine-2.5.2/jasmine_favicon.png -------------------------------------------------------------------------------- /problems/factors.js: -------------------------------------------------------------------------------- 1 | // Write a method that returns the factors of a number in ascending order. 2 | 3 | function factors(num) { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /problems/rec_sum.js: -------------------------------------------------------------------------------- 1 | // Write a recursive method that returns the sum of all elements in an array 2 | 3 | function recSum(nums) { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /solutions/deep_dup_solution.js: -------------------------------------------------------------------------------- 1 | function deepDup(arr) { 2 | return arr.map( (el) => el.constructor.name === 'Array' ? deepDup(el) : el); 3 | } 4 | -------------------------------------------------------------------------------- /solutions/rec_sum_solution.js: -------------------------------------------------------------------------------- 1 | function recSum(nums) { 2 | if (!nums.length) return 0; 3 | return nums[0] + recSum(nums.splice(1)); 4 | } 5 | -------------------------------------------------------------------------------- /problems/quicksort.js: -------------------------------------------------------------------------------- 1 | // Write a monkey patch of quick sort that accepts a callback 2 | 3 | Array.prototype.quickSort = function (func) { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # A sample Gemfile 3 | source "https://rubygems.org" 4 | 5 | gem 'jasmine' 6 | gem 'byebug' 7 | gem 'colorize' 8 | -------------------------------------------------------------------------------- /problems/exponent.js: -------------------------------------------------------------------------------- 1 | // return b^n recursively. Your solution should accept negative values 2 | // for n 3 | 4 | function exponent(b, n) { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /problems/permutations.js: -------------------------------------------------------------------------------- 1 | // Write a recursive method that returns all of the permutations of an array 2 | 3 | function permutations(array) { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /problems/first_even_numbers_sum.js: -------------------------------------------------------------------------------- 1 | // return the sum of the first n even numbers recursively. Assume n > 0 2 | 3 | function firstEvenNumbersSum(n) { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /solutions/first_even_numbers_sum_solution.js: -------------------------------------------------------------------------------- 1 | function firstEvenNumbersSum(n) { 2 | if (n === 1) return 2; 3 | return 2 * n + firstEvenNumbersSum(n - 1); 4 | } 5 | -------------------------------------------------------------------------------- /problems/fibs_sum.js: -------------------------------------------------------------------------------- 1 | // Implement a method that finds the sum of the first n 2 | // fibonacci numbers recursively. Assume n > 0 3 | 4 | function fibsSum(n) { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /problems/primes.js: -------------------------------------------------------------------------------- 1 | // primes(num) returns an array of the first "num" primes. 2 | // You may wish to use an is_prime helper method. 3 | 4 | function primes(num) { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /solutions/fibs_sum_solution.js: -------------------------------------------------------------------------------- 1 | function fibsSum(n) { 2 | if (n === 0) return 0; 3 | if (n === 1) return 1; 4 | 5 | return fibsSum(n - 1) + fibsSum(n - 2) + 1; 6 | } 7 | -------------------------------------------------------------------------------- /solutions/my_each_solution.js: -------------------------------------------------------------------------------- 1 | Array.prototype.myEach = function (func) { 2 | for (let i = 0; i < this.length; i++) { 3 | func(this[i]); 4 | } 5 | 6 | return this; 7 | } 8 | -------------------------------------------------------------------------------- /problems/my_slice.js: -------------------------------------------------------------------------------- 1 | // write String.prototype.mySlice. It should take a start index and an 2 | // (optional) end index. 3 | 4 | String.prototype.mySlice = function () { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /solutions/factors_solution.js: -------------------------------------------------------------------------------- 1 | function factors(num) { 2 | let factors = Array.from(Array(num)).map( (el, idx) => idx + 1) 3 | return factors.filter( el => num % el === 0); 4 | } 5 | -------------------------------------------------------------------------------- /solutions/my_bind_solution.js: -------------------------------------------------------------------------------- 1 | Function.prototype.myBind = function (ctx, ...bindArgs) { 2 | return (...callArgs) => { 3 | return this.apply(ctx, bindArgs.concat(callArgs)); 4 | }; 5 | }; 6 | -------------------------------------------------------------------------------- /problems/binary_search.js: -------------------------------------------------------------------------------- 1 | // # Write a monkey patch of binary search: 2 | // # E.g. [1, 2, 3, 4, 5, 7].my_bsearch(5) => 4 3 | 4 | Array.prototype.myBsearch = function (target, func) { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /solutions/my_every_solution.js: -------------------------------------------------------------------------------- 1 | Array.prototype.myEvery = function (func) { 2 | for (let i = 0; i < this.length; i++) { 3 | if (!func(this[i])) return false; 4 | } 5 | 6 | return true 7 | } 8 | -------------------------------------------------------------------------------- /solutions/my_find_solution.js: -------------------------------------------------------------------------------- 1 | function myFind (array, callback) { 2 | for (let i = 0; i < array.length; i++) { 3 | if (callback(array[i])) { 4 | return array[i]; 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /solutions/my_some_solution.js: -------------------------------------------------------------------------------- 1 | Array.prototype.mySome = function (func) { 2 | for (let i = 0; i < this.length; i++) { 3 | if (func(this[i])) return true; 4 | } 5 | 6 | return false; 7 | } 8 | -------------------------------------------------------------------------------- /problems/deep_dup.js: -------------------------------------------------------------------------------- 1 | // Using recursion and the is_a? method, 2 | // write an Array#deep_dup method that will perform a "deep" duplication of the interior arrays. 3 | 4 | function deepDup(arr) { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /problems/titleize.js: -------------------------------------------------------------------------------- 1 | // Write a method that capitalizes each word in a string like a book title 2 | // Do not capitalize words like 'a', 'and', 'of', 'over' or 'the' 3 | 4 | function titleize(title) { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /problems/median.js: -------------------------------------------------------------------------------- 1 | // Write a method that returns the median of elements in an array 2 | // If the length is even, return the average of the middle two elements 3 | 4 | Array.prototype.median = function () { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /solutions/factorials_rec_solution.js: -------------------------------------------------------------------------------- 1 | function factorialsRec(num) { 2 | if (num === 1) return [1]; 3 | 4 | const facs = factorialsRec(num - 1); 5 | facs.push(facs[facs.length - 1] * (num - 1)); 6 | return facs; 7 | } 8 | -------------------------------------------------------------------------------- /solutions/my_filter_solution.js: -------------------------------------------------------------------------------- 1 | Array.prototype.myFilter = function (func) { 2 | const selection = []; 3 | this.forEach( (el) => { 4 | if (func(el)) selection.push(el); 5 | }); 6 | 7 | return selection; 8 | } 9 | -------------------------------------------------------------------------------- /solutions/exponent_solution.js: -------------------------------------------------------------------------------- 1 | function exponent(b, n) { 2 | if (n === 0) return 1; 3 | 4 | if (n > 0) { 5 | return b * exponent(b, n - 1); 6 | } else { 7 | return 1/b * exponent(b, n + 1); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /problems/my_find.js: -------------------------------------------------------------------------------- 1 | // write myFind(array, callback). It should return the first element for which 2 | // callback returns true, or undefined if none is found. 3 | 4 | Array.prototype.myFind = function (array, callback) { 5 | 6 | }; 7 | -------------------------------------------------------------------------------- /solutions/my_reverse_solution.js: -------------------------------------------------------------------------------- 1 | Array.prototype.myReverse = function () { 2 | const dup = this.slice(0) 3 | for (let i = 1; i < this.length + 1; i++) { 4 | this[i - 1] = dup[this.length - i]; 5 | } 6 | 7 | return this; 8 | } 9 | -------------------------------------------------------------------------------- /problems/merge_sort.js: -------------------------------------------------------------------------------- 1 | // Write an Array#merge_sort method; it should not modify the original array. 2 | 3 | Array.prototype.mergeSort = function (func) { 4 | 5 | } 6 | 7 | Array.prototype.merge = function (arr, func) { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /problems/prime_factorization.js: -------------------------------------------------------------------------------- 1 | // Write a recursive function that returns the prime factorization of 2 | // a given number. Assume num > 1 3 | // 4 | // prime_factorization(12) => [2,2,3] 5 | 6 | function primeFactorization(num) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /solutions/inherits_solution.js: -------------------------------------------------------------------------------- 1 | Function.prototype.inherits = function(Parent) { 2 | function Surrogate() {} 3 | Surrogate.prototype = Parent.prototype; 4 | this.prototype = new Surrogate(); 5 | this.prototype.constructor = this; 6 | }; 7 | -------------------------------------------------------------------------------- /specs/my_flatten_spec.js: -------------------------------------------------------------------------------- 1 | describe("flatten", () => { 2 | it('Flattens arrays correctly', () => { 3 | const array = [1, 2, 3, [4, [5, 6]], [[[7]], 8]]; 4 | expect(array.flatten()).toEqual([1, 2, 3, 4, 5, 6, 7, 8]); 5 | }); 6 | }); 7 | -------------------------------------------------------------------------------- /specs/my_reverse_spec.js: -------------------------------------------------------------------------------- 1 | describe("myReverse", () => { 2 | beforeEach( () => { 3 | a = [ "a", "b", "c", "d" ]; 4 | }); 5 | 6 | it("Reverses an array", () => { 7 | expect(a.myReverse()).toEqual(a.reverse()) 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /specs/support/jasmine.json: -------------------------------------------------------------------------------- 1 | { 2 | "spec_dir": "spec", 3 | "spec_files": [ 4 | "**/*[sS]pec.js" 5 | ], 6 | "helpers": [ 7 | "helpers/**/*.js" 8 | ], 9 | "stopSpecOnExpectationFailure": false, 10 | "random": false 11 | } 12 | -------------------------------------------------------------------------------- /problems/pig_latinify.js: -------------------------------------------------------------------------------- 1 | // Write a method that translates a sentence into pig latin. You may want a helper method. 2 | // 'apple' => 'appleay' 3 | // 'pearl' => 'earlpay' 4 | // 'quick' => 'ickquay' 5 | 6 | function piglatinify(sentence) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /problems/real_words_in_string.js: -------------------------------------------------------------------------------- 1 | // Returns an array of all the subwords of the string that appear in the 2 | // dictionary argument. The method does NOT return any duplicates. 3 | 4 | String.prototype.realWordsInString = function (dictionary) { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /solutions/my_reject_solution.js: -------------------------------------------------------------------------------- 1 | Array.prototype.reject = function (func) { 2 | const selection = []; 3 | 4 | for (let i = 0; i < this.length; i++) { 5 | if (!func(this[i])) selection.push(this[i]); 6 | } 7 | 8 | return selection; 9 | } 10 | -------------------------------------------------------------------------------- /problems/my_inject.js: -------------------------------------------------------------------------------- 1 | // Monkey patch the Array class and add a my_inject method. If my_inject receives 2 | // no argument, then use the first element of the array as the default accumulator. 3 | 4 | Array.prototype.myReduce = function (func, acc) { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /problems/factorials_rec.js: -------------------------------------------------------------------------------- 1 | // Write a recursive method that returns the first "num" factorial numbers. 2 | // Note that the 1st factorial number is 0!, which equals 1. The 2nd factorial 3 | // is 1!, the 3rd factorial is 2!, etc. 4 | 5 | function factorialsRec(num) { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /solutions/my_inject_solution.js: -------------------------------------------------------------------------------- 1 | Array.prototype.myReduce = function (callback, acc) { 2 | const array = this.slice(0); 3 | if (!acc) acc = array.shift(); 4 | 5 | for (let i = 0; i < array.length; i++) { 6 | acc = callback(acc, array[i]) 7 | } 8 | 9 | return acc 10 | } 11 | -------------------------------------------------------------------------------- /solutions/my_join_solution.js: -------------------------------------------------------------------------------- 1 | Array.prototype.myJoin = function (separator = '') { 2 | let newString = '' 3 | 4 | this.forEach( (el, idx) => { 5 | newString += `${el}`; 6 | if (idx < this.length - 1) newString += separator; 7 | }) 8 | 9 | return newString; 10 | } 11 | -------------------------------------------------------------------------------- /specs/subsets_spec.js: -------------------------------------------------------------------------------- 1 | describe('subsets', () => { 2 | it("Correctly returns all subsets of an array", () => { 3 | const subs = [ 4 | [], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3] 5 | ]; 6 | 7 | expect(subsets([1, 2, 3])).toEqual(subs); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /specs/factors_spec.js: -------------------------------------------------------------------------------- 1 | describe("#factors", () => { 2 | it("returns the factors of 10 in order", () => { 3 | expect(factors(10)).toEqual([1, 2, 5, 10]); 4 | }); 5 | 6 | it("returns just two factors for primes", () => { 7 | expect(factors(13)).toEqual([1, 13]); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /problems/symmetric_substrings.js: -------------------------------------------------------------------------------- 1 | // Write a String#symmetric_substrings method that returns an array of substrings 2 | // that are palindromes, e.g. "cool".symmetric_substrings => ["oo"] 3 | // Only include substrings of length > 1. 4 | 5 | String.prototype.symmetricSubstrings = function () { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /specs/primes_spec.js: -------------------------------------------------------------------------------- 1 | describe("#primes", () => { 2 | it("returns first five primes in order", () => { 3 | expect(primes(5)).toEqual([2, 3, 5, 7, 11]); 4 | }); 5 | 6 | it("returns an empty array when asked for zero primes", () => { 7 | expect(primes(0)).toEqual([]); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /problems/base_converter.js: -------------------------------------------------------------------------------- 1 | // Write a recursive method that takes in a base 10 number n and 2 | // converts it to a base b number. Return the new number as a string 3 | // 4 | // E.g. base_converter(5, 2) == "101" 5 | // base_converter(31, 16) == "1f" 6 | 7 | function baseConverter(num, b) { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /solutions/two_sum_solution.js: -------------------------------------------------------------------------------- 1 | Array.prototype.twoSum = function () { 2 | const pairs = []; 3 | for (var i = 0; i < this.length - 1; i++) { 4 | for (var j = i + 1; j < this.length; j++) { 5 | if (this[i] + this[j] === 0) pairs.push([i, j]); 6 | } 7 | } 8 | 9 | return pairs; 10 | } 11 | -------------------------------------------------------------------------------- /specs/rec_sum_spec.js: -------------------------------------------------------------------------------- 1 | describe("#recSum", () => { 2 | it("returns the sums of all elements in an array", () => { 3 | arr = [1,2,3,4]; 4 | expect(recSum(arr)).toEqual(10); 5 | }); 6 | 7 | it("returns 0 if the array is empty", () => { 8 | expect(recSum([])).toEqual(0); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /solutions/base_converter_solution.js: -------------------------------------------------------------------------------- 1 | function baseConverter(num, b) { 2 | if (num === 0) return ""; 3 | 4 | const digits = [ 5 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 6 | 'a', 'b', 'c', 'd', 'e', 'f' 7 | ]; 8 | 9 | return baseConverter(Math.floor(num/b), b) + digits[num % b]; 10 | }; 11 | -------------------------------------------------------------------------------- /solutions/my_slice_solution.js: -------------------------------------------------------------------------------- 1 | String.prototype.mySlice = function(start, end) { 2 | let slice = ""; 3 | 4 | if (typeof end === 'undefined') { 5 | end = this.length; 6 | } 7 | 8 | for (let i = start; i < end && i < this.length; i++) { 9 | slice += this[i]; 10 | } 11 | return slice; 12 | }; 13 | -------------------------------------------------------------------------------- /solutions/my_flatten_solution.js: -------------------------------------------------------------------------------- 1 | Array.prototype.flatten = function () { 2 | let flattened = []; 3 | 4 | this.forEach( (el) => { 5 | if (el instanceof Array) { 6 | flattened = flattened.concat(el.flatten()); 7 | } else { 8 | flattened.push(el); 9 | } 10 | }); 11 | 12 | return flattened; 13 | } 14 | -------------------------------------------------------------------------------- /solutions/string_include_key_solution.js: -------------------------------------------------------------------------------- 1 | function stringIncludeKey(string, key) { 2 | if (!key.length) return true; 3 | 4 | let nextKeyChar = key[0]; 5 | let keyIndex = string.indexOf(nextKeyChar); 6 | 7 | if (keyIndex < 0) return false; 8 | return stringIncludeKey(string.slice(keyIndex + 1), key.slice(1)) 9 | } 10 | -------------------------------------------------------------------------------- /solutions/subsets_solution.js: -------------------------------------------------------------------------------- 1 | function subsets(arr) { 2 | if (!arr.length) return [[]]; 3 | const last = arr[arr.length - 1]; 4 | const subs = subsets(arr.slice(0, arr.length - 1)); 5 | return subs.concat(subs.map( (el) => { 6 | let newArr = el.slice(0) 7 | newArr.push(last); 8 | return newArr; 9 | })); 10 | } 11 | -------------------------------------------------------------------------------- /specs/base_converter_spec.js: -------------------------------------------------------------------------------- 1 | describe('baseConverter', () => { 2 | it('converts a small number in binary', () => { 3 | expect(baseConverter(5, 2)).toEqual('101'); 4 | }); 5 | 6 | it('converts a large number into base 15', () => { 7 | expect(baseConverter(1239449, 16)).toEqual('12e999' || '12E999'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /solutions/median_solution.js: -------------------------------------------------------------------------------- 1 | Array.prototype.median = function () { 2 | if (!this.length) return null; 3 | const sorted = this.sort(); 4 | const mid = Math.floor(this.length / 2); 5 | 6 | if (this.length % 2 != 0) { 7 | return sorted[mid]; 8 | } else { 9 | return (sorted[mid] + sorted[mid - 1]) / 2; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /solutions/my_curry_solution.js: -------------------------------------------------------------------------------- 1 | Function.prototype.myCurry = function (numArgs) { 2 | let argBalls = []; 3 | let fcn = this; 4 | return function _myCurry (el) { 5 | argBalls.push(el); 6 | if (argBalls.length < numArgs) { 7 | return _myCurry; 8 | } else { 9 | return fcn(...argBalls); 10 | } 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /specs/first_even_numbers_sum_spec.js: -------------------------------------------------------------------------------- 1 | describe('firstEvenNumbersSum', () => { 2 | it("Correctly returns the sum of the first even number", () => { 3 | expect(firstEvenNumbersSum(1)).toEqual(2); 4 | }); 5 | 6 | it("Returns the sum of the first n even numbers", () => { 7 | expect(firstEvenNumbersSum(6)).toEqual(42); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /problems/dups.js: -------------------------------------------------------------------------------- 1 | // Write an Array#dups method that will return a hash containing the indices of all 2 | // duplicate elements. The keys are the duplicate elements; the values are 3 | // arrays of their indices in ascending order, e.g. 4 | // [1, 3, 4, 3, 0, 3, 0].dups => { 3 => [1, 3, 5], 0 => [4, 6] } 5 | 6 | Array.prototype.dups = function() { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /solutions/digital_root_solution.js: -------------------------------------------------------------------------------- 1 | function digitalRoot(num) { 2 | while (num > 10) { 3 | num = digitalRootStep(num); 4 | } 5 | 6 | return num; 7 | } 8 | 9 | function digitalRootStep(num) { 10 | let root = 0; 11 | 12 | while (num > 0) { 13 | root += num % 10; 14 | num = Math.floor(num/10); 15 | } 16 | 17 | return root; 18 | } 19 | -------------------------------------------------------------------------------- /specs/permutations_spec.js: -------------------------------------------------------------------------------- 1 | describe("#permutations", () => { 2 | it("returns all permutations of an array", () => { 3 | const array = [1, 2, 3]; 4 | const allPermutations = [ 5 | [1, 2, 3], [1, 3, 2], [2, 1, 3], 6 | [2, 3, 1], [3, 1, 2], [3, 2, 1] 7 | ]; 8 | 9 | expect(permutations([1, 2, 3])).toEqual(allPermutations); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /specs/my_join_spec.js: -------------------------------------------------------------------------------- 1 | describe("myJoin", () => { 2 | beforeEach( () => { 3 | const a = ['a', 'b', 'c', 'd']; 4 | }); 5 | 6 | it("joins an array if no argument is passed", () => { 7 | expect(a.myJoin()).toEqual("abcd") 8 | }); 9 | 10 | it("joins an array if an argument is passed", () => { 11 | expect(a.myJoin("$")).toEqual("a$b$c$d") 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /specs/exponent_spec.js: -------------------------------------------------------------------------------- 1 | describe("exponent", () => { 2 | it("correctly handles positive powers", () => { 3 | expect(exponent(5, 3)).toEqual(125); 4 | }); 5 | 6 | it("correctly handles negative powers", () => { 7 | expect(exponent(2, -3)).toEqual(1/8.0); 8 | }); 9 | 10 | it("correctly handles 0", () => { 11 | expect(exponent(2, 0)).toEqual(1); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /solutions/my_rotate_solution.js: -------------------------------------------------------------------------------- 1 | Array.prototype.rotate = function (times = 1) { 2 | let rotations; 3 | const rotated = this.slice(0); 4 | 5 | if (times < 0) rotations = this.length % (Math.abs(times) / this.length); 6 | else rotations = times % this.length; 7 | 8 | for (let i = 0; i < rotations; i++) { 9 | rotated.push(rotated.shift()) 10 | } 11 | 12 | return rotated; 13 | } 14 | -------------------------------------------------------------------------------- /solutions/prime_factorization_solution.js: -------------------------------------------------------------------------------- 1 | function primeFactorization(num) { 2 | if (num === 1) return []; 3 | const upperRange = Math.ceil(Math.sqrt(num)); 4 | 5 | for (let i = 2; i <= upperRange; i++) { 6 | if (num % i == 0) { 7 | let factors = [i].concat(primeFactorization(Math.floor(num / i))); 8 | return factors; 9 | } 10 | } 11 | 12 | return [num]; 13 | } 14 | -------------------------------------------------------------------------------- /solutions/transpose_solution.js: -------------------------------------------------------------------------------- 1 | const transpose = function (arr) { 2 | let transposedArr = []; 3 | let currRow; 4 | 5 | for (var col = 0; col < arr[0].length; col++) { 6 | transposedRow = []; 7 | for (var row = 0; row < arr.length; row++) { 8 | transposedRow.push(arr[row][col]); 9 | } 10 | transposedArr.push(transposedRow); 11 | } 12 | return transposedArr; 13 | }; 14 | -------------------------------------------------------------------------------- /problems/string_include_key.js: -------------------------------------------------------------------------------- 1 | // Write a recursive method that takes in a string to search and a key string. 2 | // Return true if the string contains all of the characters in the key 3 | // in the same order that they appear in the key. 4 | // 5 | // string_include_key?("cadbpc", "abc") => true 6 | // string_include_key("cba", "abc") => false 7 | 8 | function stringIncludeKey(string, key) { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /solutions/primes_solution.js: -------------------------------------------------------------------------------- 1 | function primes(count) { 2 | const primes = []; 3 | let i = 2; 4 | 5 | const isPrime = (num) => { 6 | for (var i = 2; i < num; i++) { 7 | if (num % i === 0) return false; 8 | } 9 | 10 | return true; 11 | } 12 | 13 | while (primes.length < count) { 14 | if (isPrime(i)) primes.push(i); 15 | i += 1; 16 | } 17 | 18 | return primes; 19 | } 20 | -------------------------------------------------------------------------------- /solutions/dups_solution.js: -------------------------------------------------------------------------------- 1 | Array.prototype.dups = function() { 2 | const count = {}; 3 | const dups = {}; 4 | 5 | this.forEach( (el, idx) => { 6 | count[el] = count[el] || []; 7 | count[el].push(idx); 8 | }); 9 | 10 | const keys = Object.keys(count).filter( el => count[el].length > 1) 11 | keys.forEach( (key) => { 12 | dups[key] = count[key]; 13 | }); 14 | 15 | return dups; 16 | } 17 | -------------------------------------------------------------------------------- /specs/caesar_cipher_spec.js: -------------------------------------------------------------------------------- 1 | describe("#caesarCipher", () => { 2 | it("encodes a simple word", () => { 3 | expect(caesarCipher("aaa", 11)).toEqual("lll"); 4 | }); 5 | 6 | it("wraps around the alphabet", () => { 7 | expect(caesarCipher("zzz", 1)).toEqual("aaa"); 8 | }); 9 | 10 | it("encodes multiple words", () => { 11 | expect(caesarCipher("catz hatz", 2)).toEqual("ecvb jcvb"); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /specs/doubler_spec.js: -------------------------------------------------------------------------------- 1 | describe("#doubler", () => { 2 | beforeEach(() => { 3 | array = [1, 2, 3]; 4 | }); 5 | 6 | it("doubles the elements of the array", () => { 7 | expect(doubler(array)).toEqual([2, 4, 6]); 8 | }); 9 | 10 | it("does not modify the original array", () => { 11 | const dupArray = array.slice(0); 12 | 13 | doubler(array); 14 | 15 | expect(array).toEqual(dupArray); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /specs/prime_factorization_spec.js: -------------------------------------------------------------------------------- 1 | describe("primeFactorization", () => { 2 | it("handles an input of 2", () => { 3 | expect(primeFactorization(2)).toEqual([2]); 4 | }); 5 | 6 | it("Test case: 12", () => { 7 | expect(primeFactorization(12)).toEqual([2,2,3]); 8 | }); 9 | 10 | it("Test case: 600851475143", () => { 11 | expect(primeFactorization(600851475143)).toEqual([71,839,1471,6857]); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /solutions/caesar_cipher_solution.js: -------------------------------------------------------------------------------- 1 | function caesarCipher(str, shift) { 2 | const alphabet = 'abcdefghijklmnopqrstuvwxyz'.split('') 3 | let encoded = "" 4 | 5 | for (let i = 0; i < str.length; i++) { 6 | if (str[i] === ' ') { 7 | encoded += ' '; 8 | continue 9 | } 10 | 11 | const offset = (alphabet.indexOf(str[i]) + shift) % 26 12 | encoded += alphabet[offset] 13 | } 14 | 15 | return encoded 16 | } 17 | -------------------------------------------------------------------------------- /specs/my_each_spec.js: -------------------------------------------------------------------------------- 1 | describe("myEach", () => { 2 | beforeEach( () => { 3 | callback = x => res.push(2 * x); 4 | array = [1, 2, 3]; 5 | }); 6 | 7 | it("it passes each element into a callback", () => { 8 | res = []; 9 | array.myEach(callback); 10 | expect(res).toEqual([2,4,6]); 11 | }); 12 | 13 | it("returns the original array", () => { 14 | expect(array.myEach(callback)).toEqual([1, 2, 3]); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /specs/my_some_spec.js: -------------------------------------------------------------------------------- 1 | describe('mySome', () => { 2 | beforeEach( () => { 3 | a = [1, 2, 3]; 4 | }); 5 | 6 | it("returns true if any number matches the block", () => { 7 | const callback = x => x > 1; 8 | expect(a.mySome(callback)).toBe(true); 9 | }); 10 | 11 | it("returns false if no elementes match the block", () => { 12 | const callback = x => x === 4; 13 | expect(a.mySome(callback)).toBe(false); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /problems/jumble_sort.js: -------------------------------------------------------------------------------- 1 | // Jumble sort takes a string and an alphabet. It returns a copy of the string 2 | // with the letters re-ordered according to their positions in the alphabet. If 3 | // no alphabet is passed in, it defaults to normal alphabetical order (a-z). 4 | // 5 | // Example: 6 | // jumble_sort("hello") => "ehllo" 7 | // jumble_sort("hello", ['o', 'l', 'h', 'e']) => 'ollhe' 8 | 9 | function jumbleSort(str, alphabet = null) { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /solutions/symmetric_substrings_solution.js: -------------------------------------------------------------------------------- 1 | String.prototype.symmetricSubstrings = function () { 2 | const symmetric = []; 3 | 4 | for (let i = 0; i < this.length; i++) { 5 | for (let j = 2; j <= this.length - i; j++) { 6 | const subst = this.slice(i, i + j); 7 | const reversed = subst.split('').reverse().join('') 8 | 9 | if (subst === reversed) symmetric.push(subst); 10 | } 11 | } 12 | 13 | return symmetric; 14 | } 15 | -------------------------------------------------------------------------------- /solutions/titleize_solution.js: -------------------------------------------------------------------------------- 1 | function titleize(title) { 2 | const littleWords = ['and', 'the', 'over']; 3 | 4 | const words = title.split(' '); 5 | const titleizedWords = words.map( (word, idx) => { 6 | if (idx != 0 && littleWords.indexOf(word) >= 0) { 7 | return word.toLowerCase(); 8 | } else { 9 | return word.slice(0, 1).toUpperCase() + word.slice(1); 10 | } 11 | }) 12 | 13 | return titleizedWords.join(' '); 14 | } 15 | -------------------------------------------------------------------------------- /specs/fibs_sum_spec.js: -------------------------------------------------------------------------------- 1 | describe('fibsSum', () => { 2 | it('It correctly gets the answer for the 1st fibonacci number', () => { 3 | expect(fibsSum(1)).toEqual(1); 4 | }); 5 | 6 | it('It correctly gets the answer for the first 2 fibonacci numbers', () => { 7 | expect(fibsSum(2)).toEqual(2); 8 | }); 9 | 10 | it('It correctly gets the answer for the first 6 fibonacci numbers', () => { 11 | expect(fibsSum(6)).toEqual(20); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /specs/symmetric_substrings_spec.js: -------------------------------------------------------------------------------- 1 | describe("#symmetricSubstrings", () => { 2 | it("handles a simple example", () => { 3 | expect("aba".symmetricSubstrings()).toEqual(["aba"]); 4 | }); 5 | 6 | it("handles two substrings", () => { 7 | expect("aba1cdc".symmetricSubstrings()).toEqual(["aba", "cdc"]); 8 | }); 9 | 10 | it("handles nested substrings", () => { 11 | expect("xabax".symmetricSubstrings()).toEqual(["aba", "xabax"]); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /specs/my_every_spec.js: -------------------------------------------------------------------------------- 1 | describe('myEvery', () => { 2 | beforeEach( () => { 3 | a = [2, 4, 6]; 4 | }); 5 | 6 | it("returns true if all elements match the block", () => { 7 | const callback = x => x % 2 === 0; 8 | expect(a.myEvery(callback)).toBe(true); 9 | }); 10 | 11 | it("returns false if not all elementes match the block", () => { 12 | const callback = x => x % 3 === 0; 13 | expect(a.myEvery(callback)).toBe(false); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /solutions/permutations_solution.js: -------------------------------------------------------------------------------- 1 | function permutations(array) { 2 | let result = []; 3 | 4 | const permute = (arr, m = []) => { 5 | if (arr.length === 0) { 6 | result.push(m) 7 | } else { 8 | for (let i = 0; i < arr.length; i++) { 9 | let curr = arr.slice(); 10 | let next = curr.splice(i, 1); 11 | permute(curr.slice(), m.concat(next)) 12 | } 13 | } 14 | 15 | return result; 16 | } 17 | return permute(array); 18 | } 19 | -------------------------------------------------------------------------------- /specs/my_filter_spec.js: -------------------------------------------------------------------------------- 1 | describe('myFilter', () => { 2 | beforeEach( () => { 3 | a = [1, 2, 3]; 4 | }); 5 | 6 | it('It correctly selects elements according to the passed in block', () => { 7 | const callback = x => x > 1; 8 | expect(a.myFilter(callback)).toEqual([2, 3]); 9 | }); 10 | 11 | it('It returns an empty array if there are no matches', () => { 12 | const callback = x => x === 4; 13 | expect(a.myFilter(callback)).toEqual([]); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /specs/my_find_spec.js: -------------------------------------------------------------------------------- 1 | describe("myFind", () => { 2 | let arr, spy; 3 | beforeEach(() => { 4 | arr = [1, 2, 3]; 5 | spy = { 6 | callback: (el) => false 7 | }; 8 | }); 9 | 10 | const equalsThree = (el) => el === 3; 11 | const equalsFour = (el) => el === 4; 12 | 13 | it("calls the callback passed to it", () => { 14 | spyOn(spy, "callback"); 15 | 16 | myFind(arr, spy.callback); 17 | 18 | expect(spy.callback).toHaveBeenCalled(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /specs/my_reject_spec.js: -------------------------------------------------------------------------------- 1 | describe('reject', () => { 2 | beforeEach( () => { 3 | a = [1, 2, 3]; 4 | }); 5 | 6 | it('it returns elements that do not match the passed in block', () => { 7 | const callback = x => x > 1; 8 | expect(a.reject(callback)).toEqual([1]); 9 | }); 10 | 11 | it('It returns all elements if no elements match the block', () => { 12 | const callback = x => x === 4; 13 | expect(a.reject(callback)).toEqual([1,2,3]); 14 | }); 15 | 16 | }); 17 | -------------------------------------------------------------------------------- /solutions/binary_search_solution.js: -------------------------------------------------------------------------------- 1 | Array.prototype.myBsearch = function(target, func) { 2 | if (this.length === 0) return null; 3 | const mid = Math.floor(this.length / 2); 4 | 5 | if (this[mid] === target) { 6 | return mid; 7 | } else if (this[mid] > target) { 8 | return this.slice(0, mid).myBsearch(target); 9 | } else { 10 | const result = this.slice(mid + 1, this.length).myBsearch(target); 11 | return result === null ? result : mid + 1 + result 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /specs/digital_root_spec.js: -------------------------------------------------------------------------------- 1 | describe("#digitalRoot", () => { 2 | it("calculates the digital root of a single-digit number", () => { 3 | expect(digitalRoot(9)).toEqual(9); 4 | }); 5 | 6 | it("calculates the digital root of a larger number", () => { 7 | expect(digitalRoot(4322)).toEqual(2); 8 | }); 9 | // 10 | // it("does not call #to_s on the argument", () => { 11 | // expect_any_instance_of(Fixnum).to_not receive(:to_s) 12 | // digitalRoot(4322); 13 | // }); 14 | }); 15 | -------------------------------------------------------------------------------- /problems/digital_root.js: -------------------------------------------------------------------------------- 1 | // Write a method, `digital_root(num)`. It should Sum the digits of a positive 2 | // integer. If it is greater than 10, sum the digits of the resulting number. 3 | // Keep repeating until there is only one digit in the result, called the 4 | // "digital root". **Do not use string conversion within your method.** 5 | // 6 | // You may wish to use a helper function, `digital_root_step(num)` which performs 7 | // one step of the process. 8 | 9 | function digitalRoot(num) { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /problems/two_sum.js: -------------------------------------------------------------------------------- 1 | // Write a method, `Array#two_sum`, that finds all pairs of positions where the 2 | // elements at those positions sum to zero. 3 | 4 | // NB: ordering matters. I want each of the pairs to be sorted smaller index 5 | // before bigger index. I want the array of pairs to be sorted 6 | // "dictionary-wise": 7 | // [0, 2] before [1, 2] (smaller first elements come first) 8 | // [0, 1] before [0, 2] (then smaller second elements come first) 9 | 10 | Array.prototype.twoSum = function () { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /specs/dups_spec.js: -------------------------------------------------------------------------------- 1 | describe("#dups", () => { 2 | it("solves a simple example", () => { 3 | expect([1, 3, 0, 1].dups()).toEqual({ 1: [0, 3] }); 4 | }); 5 | 6 | it("finds two dups", () => { 7 | expect([1, 3, 0, 3, 1].dups()).toEqual({ 1: [0, 4], 3: [1, 3] }); 8 | }); 9 | 10 | it("finds multi-dups", () => { 11 | expect([1, 3, 4, 3, 0, 3].dups()).toEqual({ 3: [1, 3, 5] }); 12 | }); 13 | 14 | it("returns {} when no dups found", () => { 15 | expect([1, 3, 4, 5].dups()).toEqual({}); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /specs/deep_dup_spec.js: -------------------------------------------------------------------------------- 1 | describe("deepDup", () => { 2 | beforeEach( () => { 3 | robotParts = [ 4 | ["nuts", "bolts", "washers"], 5 | ["capacitors", "resistors", "inductors"] 6 | ]; 7 | 8 | copy = deepDup(robotParts); 9 | }); 10 | 11 | it("makes a copy of the original array", () => { 12 | expect(copy).toEqual(robotParts); 13 | }); 14 | 15 | it("deeply copies arrays", () => { 16 | copy[1].push("LEDs"); 17 | expect(robotParts[1]).toEqual(["capacitors", "resistors", "inductors"]); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /solutions/quicksort_solution.js: -------------------------------------------------------------------------------- 1 | Array.prototype.quickSort = function (func) { 2 | if (this.length < 2) return this; 3 | 4 | if (!func) { 5 | func = (x, y) => { 6 | if (x < y) return - 1; 7 | return 1; 8 | } 9 | } 10 | 11 | const pivot = this[0]; 12 | let left = this.slice(1).filter( (el) => func(el, pivot) === -1); 13 | let right = this.slice(1).filter( (el) => func(el, pivot) != -1); 14 | left = left.quicksort(func); 15 | right = right.quicksort(func); 16 | 17 | return left.concat([pivot]).concat(right); 18 | } 19 | -------------------------------------------------------------------------------- /specs/jumble_sort_spec.js: -------------------------------------------------------------------------------- 1 | describe("#jumbleSort", () => { 2 | it("defaults to alphabetical order", () => { 3 | expect(jumbleSort("hello")).toEqual("ehllo"); 4 | }); 5 | 6 | it("takes an alphabet array and sorts by that order", () => { 7 | const alphabet = 'helo'.split(''); 8 | 9 | expect(jumbleSort("hello", alphabet)).toEqual("hello"); 10 | }); 11 | 12 | it("sorts by a reversed alphabet", () => { 13 | reverse = 'abcdefghijklmnopqrstuvwxyz'.split('').reverse().join('') 14 | expect(jumbleSort("hello", reverse)).toEqual("ollhe"); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /solutions/jumble_sort_solution.js: -------------------------------------------------------------------------------- 1 | function jumbleSort(str, alphabet = null) { 2 | alphabet = alphabet || 'abcdefghijklmnopqrstuvwxyz'.split(''); 3 | str = str.split(''); 4 | 5 | let sorted = false; 6 | while (!sorted) { 7 | sorted = true 8 | for (let i = 0; i < str.length; i++) { 9 | if (i === str.length - 1) break 10 | let current = str[i], next = str[i + 1]; 11 | if (alphabet.indexOf(current) > alphabet.indexOf(next)) { 12 | str[i] = next, str[i + 1] = current; 13 | sorted = false; 14 | } 15 | } 16 | } 17 | 18 | return str.join(''); 19 | } 20 | -------------------------------------------------------------------------------- /solutions/bubble_sort_solution.js: -------------------------------------------------------------------------------- 1 | Array.prototype.bubbleSort = function(func) { 2 | let sorted = false; 3 | 4 | if (!func) { 5 | func = (x, y) => { 6 | if (x <= y) return -1; 7 | return 1; 8 | } 9 | } 10 | 11 | while (!sorted) { 12 | sorted = true; 13 | for (let i = 0; i < this.length; i++) { 14 | if (i + 1 === this.length) continue; 15 | 16 | if (func(this[i], this[i + 1]) === 1) { 17 | sorted = false; 18 | let current = this[i], next = this[i + 1]; 19 | this[i] = next, this[i + 1] = current; 20 | } 21 | } 22 | } 23 | 24 | return this; 25 | } 26 | -------------------------------------------------------------------------------- /solutions/pig_latinify_solution.js: -------------------------------------------------------------------------------- 1 | function pigLatinify(sentence) { 2 | const words = sentence.split(' ') 3 | const translateWord = (word) => { 4 | vowels = 'aeiou'.split(''); 5 | if (vowels.indexOf(word[0]) != -1) { 6 | return `${word}ay`; 7 | } else { 8 | let phonemeEnd = 0; 9 | while(!(vowels.indexOf(word[phonemeEnd]) != -1)) { 10 | phonemeEnd += 1; 11 | } 12 | 13 | if (word[phonemeEnd - 1] === 'q') phonemeEnd += 1; 14 | return `${word.slice(phonemeEnd)}${word.slice(0, phonemeEnd)}ay`; 15 | } 16 | } 17 | 18 | return words.map( word => translateWord(word) ).join(' '); 19 | } 20 | -------------------------------------------------------------------------------- /specs/median_spec.js: -------------------------------------------------------------------------------- 1 | describe("#median", () => { 2 | beforeEach(() => { 3 | evenArray = [3, 2, 6, 7]; 4 | oddArray = [3, 2, 6, 7, 1]; 5 | }); 6 | 7 | it("returns null for the empty array", () => { 8 | expect([].median()).toBe(null); 9 | }); 10 | 11 | it("returns the element for an array of length 1", () => { 12 | expect([1].median()).toEqual(1); 13 | }); 14 | 15 | it("returns the median of an odd-length array", () => { 16 | expect(oddArray.median()).toEqual(3); 17 | }); 18 | 19 | it("returns the median of an even-length array", () => { 20 | expect(evenArray.median()).toEqual(4.5); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /specs/real_words_in_string_spec.js: -------------------------------------------------------------------------------- 1 | describe("realWordsInString", () => { 2 | it("finds a simple word", () => { 3 | const words = "asdfcatqwer".realWordsInString(["cat", "car"]); 4 | expect(words).toEqual(["cat"]); 5 | }); 6 | 7 | it("doesn't find words not in the dictionary", () => { 8 | const words = "batcabtarbrat".realWordsInString(["cat", "car"]); 9 | expect(words).toEqual([]); 10 | }); 11 | 12 | it("finds words within words", () => { 13 | const dictionary = ["bears", "ear", "a", "army"]; 14 | const words = "erbearsweatmyajs".realWordsInString(dictionary); 15 | expect(words).toEqual(["bears", "ear", "a"]); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /specs/titleize_spec.js: -------------------------------------------------------------------------------- 1 | describe("titleize", () => { 2 | it("capitalizes a word", () => { 3 | expect(titleize("jaws")).toEqual("Jaws"); 4 | }); 5 | 6 | it("capitalizes every word (aka title case)", () => { 7 | expect(titleize("david copperfield")).toEqual("David Copperfield"); 8 | }); 9 | 10 | it("doesn't capitalize 'little words' in a title", () => { 11 | expect(titleize("war and peace")).toEqual("War and Peace"); 12 | }); 13 | 14 | it("does capitalize 'little words' at the start of a title", () => { 15 | expect( 16 | titleize("the bridge over the river kwai") 17 | ).toEqual("The Bridge over the River Kwai"); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /specs/factorials_rec_spec.js: -------------------------------------------------------------------------------- 1 | describe("#factorialsRec", () => { 2 | it("returns first factorial number", () => { 3 | expect(factorialsRec(1)).toEqual([1]); 4 | }); 5 | 6 | it("returns first two factorial numbers", () => { 7 | expect(factorialsRec(2)).toEqual([1, 1]) 8 | }); 9 | 10 | it("returns many factorials numbers", () => { 11 | expect(factorialsRec(6)).toEqual([1, 1, 2, 6, 24, 120]); 12 | }); 13 | 14 | // it("calls itself recursively", () => { 15 | // // this should enforce you calling your method recursively. 16 | // 17 | // expect(self).to receive(:factorialsRec).at_least(:twice).and_call_original 18 | // factorialsRec(6) 19 | // }); 20 | }); 21 | -------------------------------------------------------------------------------- /specs/my_rotate_spec.js: -------------------------------------------------------------------------------- 1 | describe("rotate", () => { 2 | a = [ "a", "b", "c", "d" ] 3 | 4 | it("Rotates the elements 1 position if no argument is passed in", () => { 5 | expect(a.rotate()).toEqual(["b", "c", "d", "a"]); 6 | }); 7 | 8 | it("Rotates the elements correctly if an argument is passed in", () => { 9 | expect(a.rotate(2)).toEqual(["c", "d", "a", "b"]); 10 | }); 11 | 12 | it("Rotates the elements correctly if a negative argument is passed in", () => { 13 | expect(a.rotate(-3)).toEqual(["b", "c", "d", "a"]); 14 | }); 15 | 16 | it("Rotates the elements correctly for a large argument", () => { 17 | expect(a.rotate(15)).toEqual(["d", "a", "b", "c"]); 18 | }); 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /problems/caesar_cipher.js: -------------------------------------------------------------------------------- 1 | // Back in the good old days, you used to be able to write a darn near 2 | // uncrackable code by simply taking each letter of a message and incrementing it 3 | // by a fixed number, so "abc" by 2 would look like "cde", wrapping around back 4 | // to "a" when you pass "z". Write a function, `caesar_cipher(str, shift)` which 5 | // will take a message and an increment amount and outputs the encoded message. 6 | // Assume lowercase and no punctuation. Preserve spaces. 7 | // 8 | // To get an array of letters "a" to "z", you may use `("a".."z").to_a`. To find 9 | // the position of a letter in the array, you may use `Array#find_index`. 10 | 11 | function caesarCipher(str, shift) { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /solutions/real_words_in_string_solution.js: -------------------------------------------------------------------------------- 1 | String.prototype.realWordsInString = function (dictionary) { 2 | realWords = []; 3 | for (let i = 0; i < this.length; i++) { 4 | let first = i 5 | for (let j = 0; j < this.length; j++) { 6 | let last = j 7 | let word = this.slice(first, last); 8 | 9 | if (dictionary.indexOf(word) > -1) { 10 | if (realWords.indexOf(word) < 0) realWords.push(word); 11 | } 12 | } 13 | } 14 | 15 | return realWords; 16 | } 17 | 18 | // Brian solution 19 | String.prototype._realWordsInString = function(dictionary) { 20 | realWords = []; 21 | 22 | dictionary.forEach( (el) => { 23 | if (string.includes(el)) result.push(el); 24 | }); 25 | return result.sort(); 26 | } 27 | -------------------------------------------------------------------------------- /specs/quicksort_spec.js: -------------------------------------------------------------------------------- 1 | describe("quickSort", () => { 2 | it("Sorts an array of numbers with no duplicates", () => { 3 | const a = [ 2, 1, 3, 5, 0, 8, 4, 7, 6]; 4 | expect(a.quickSort()).toEqual(a.sort()); 5 | }); 6 | 7 | it("Sorts an array of numbers with duplicates", () => { 8 | const a = [3, 1, 2, 3, 9, 17, 10, 432, 10]; 9 | const sorted = [1, 2, 3, 3, 9, 10, 10, 17, 432]; 10 | expect(a.quickSort()).toEqual(sorted); 11 | }); 12 | 13 | it("Sorts according to the block passed in", () => { 14 | const a = [ 2, 1, 3, 5, 0, 8, 4, 7, 6]; 15 | const callback = (x, y) => { 16 | if (y < x) return - 1; 17 | return 1; 18 | }; 19 | 20 | expect(a.quickSort(callback)).toEqual(a.sort(callback)); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /SpecRunner.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Jasmine Spec Runner v2.5.2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /specs/two_sum_spec.js: -------------------------------------------------------------------------------- 1 | describe("#twoSum", () => { 2 | it("returns positions of pairs of numbers that add to zero", () => { 3 | expect([5, 1, -7, -5].twoSum()).toEqual([[0, 3]]); 4 | }); 5 | 6 | it("finds multiple pairs", () => { 7 | expect([5, -1, -5, 1].twoSum()).toEqual([[0, 2], [1, 3]]); 8 | }); 9 | 10 | it("finds pairs with same element", () => { 11 | expect([5, -5, -5].twoSum()).toEqual([[0, 1], [0, 2]]); 12 | }); 13 | 14 | it("returns [] when no pair is found", () => { 15 | expect([5, 5, 3, 1].twoSum()).toEqual([]); 16 | }); 17 | 18 | it("won't find spurious zero pairs", () => { 19 | expect([0, 1, 2, 3].twoSum()).toEqual([]); 20 | }); 21 | 22 | it("will find real zero pairs", () => { 23 | expect([0, 1, 2, 0].twoSum()).toEqual([[0, 3]]); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /specs/string_include_key_spec.js: -------------------------------------------------------------------------------- 1 | describe("stringIncludeKey", () => { 2 | it("returns true for the same string", () => { 3 | expect(stringIncludeKey("adblfci", "abc")).toEqual(true); 4 | }); 5 | 6 | it("handles keys with duplicate characters: case 1", () => { 7 | expect(stringIncludeKey("adbblfci", "abbc")).toEqual(true); 8 | }); 9 | 10 | it("handles keys with duplicate characters: case 2", () => { 11 | expect(stringIncludeKey("adbclfci", "abbc")).toEqual(false); 12 | }); 13 | 14 | it("returns false if the key characters are in the wrong order", () => { 15 | expect(stringIncludeKey("dblfcia", "abc")).toEqual(false); 16 | }); 17 | 18 | it("returns false if the string doesn't contain the key", () => { 19 | expect(stringIncludeKey("db", "abc")).toEqual(false); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /specs/my_curry_spec.js: -------------------------------------------------------------------------------- 1 | describe("Function.prototype.myCurry", () => { 2 | const adder = function (...argBalls) { 3 | return argBalls.reduce((a, b) => { 4 | return a + b; 5 | }, 0); 6 | } 7 | const addObj = { adder }; 8 | 9 | 10 | it("collects up arguments until there are numArgs of them", () => { 11 | expect(adder.myCurry(3)(1)(2)(3)).toEqual(6); 12 | }); 13 | 14 | it("should return itself if there are too few arguments still", () => { 15 | const myCurryResult = adder.myCurry(3)(1)(2); 16 | expect(myCurryResult).not.toEqual(6); 17 | expect(typeof(myCurryResult)).toEqual("function"); 18 | }); 19 | 20 | it("should call the original function", () => { 21 | spyOn(addObj, "adder"); 22 | 23 | addObj.adder.myCurry(3)(1)(2)(3); 24 | expect(addObj.adder).toHaveBeenCalled(); 25 | }); 26 | 27 | }); 28 | -------------------------------------------------------------------------------- /specs/bubble_sort_spec.js: -------------------------------------------------------------------------------- 1 | describe("#bubbleSort", () => { 2 | beforeEach(() => { 3 | array = [3, 1, 5, 4, 2]; 4 | }) 5 | 6 | it("works with an empty array", () => { 7 | expect([].bubbleSort().join()).toEqual([].join()); 8 | }); 9 | 10 | it("works with an array of one item", () => { 11 | expect([1].bubbleSort().join('')).toEqual([1].join('')); 12 | }) 13 | 14 | it("sorts numbers", () => { 15 | expect(array.bubbleSort().join('')).toEqual(array.sort().join('')); 16 | }); 17 | 18 | it("does not modify the original array", () => { 19 | const sortedArray = array.bubbleSort() 20 | expect(sortedArray).not.toEqual(array); 21 | }) 22 | 23 | it("will use a callback if given", () => { 24 | const descendSort = (x, y) => { 25 | if (x > y) return -1; 26 | return 1; 27 | } 28 | 29 | let sorted = array.bubbleSort(descendSort) 30 | expect(sorted.join('')).toEqual([5, 4, 3, 2, 1].join('')); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /solutions/merge_sort_solution.js: -------------------------------------------------------------------------------- 1 | Array.prototype.mergeSort = function (func) { 2 | if (this.length <= 1) return this; 3 | 4 | if (!func) func = (left, right) => { 5 | return left < right ? -1 : left > right ? 1 : 0; 6 | } 7 | 8 | const midpoint = Math.floor(this.length / 2); 9 | const sortedLeft = this.slice(0, midpoint).mergeSort(func); 10 | const sortedRight = this.slice(midpoint).mergeSort(func); 11 | 12 | return sortedLeft.merge(sortedRight, func); 13 | } 14 | 15 | Array.prototype.merge = function (arr, func) { 16 | let merged = []; 17 | 18 | while (this.length && arr.length) { 19 | switch(func(this[0], arr[0])) { 20 | case -1: 21 | merged.push(this.shift()); 22 | break 23 | case 0: 24 | merged.push(this.shift()); 25 | break 26 | case 1: 27 | merged.push(arr.shift()); 28 | break 29 | } 30 | } 31 | 32 | merged = merged.concat(this); 33 | merged = merged.concat(arr); 34 | 35 | return merged; 36 | } 37 | -------------------------------------------------------------------------------- /specs/merge_sort_spec.js: -------------------------------------------------------------------------------- 1 | describe("#mergeSort", () => { 2 | beforeEach( () => { 3 | array = [3, 1, 2, 5, 4]; 4 | }); 5 | 6 | it("works with an empty array", () => { 7 | expect([].mergeSort()).toEqual([]); 8 | }); 9 | 10 | it("works with an array of one item", () => { 11 | expect([1].mergeSort()).toEqual([1]); 12 | }); 13 | 14 | it("sorts numbers", () => { 15 | expect(array.mergeSort()).toEqual(array.sort()); 16 | }); 17 | 18 | it("will use callback if given", () => { 19 | const callback = (x, y) => { 20 | if (y < x) return -1; 21 | return 1; 22 | }; 23 | const reversed = array.mergeSort(callback); 24 | expect(reversed).toEqual([5, 4, 3, 2, 1]) 25 | }); 26 | 27 | it("does not modify original", () => { 28 | dupArray = array.slice(0); 29 | dupArray.mergeSort(); 30 | expect(dupArray).toEqual(array); 31 | }); 32 | // 33 | // it("calls the merge helper method", () => { 34 | // expect(Array).to receive(:merge).at_least(:once).and_call_original 35 | // array.mergeSort() 36 | // }); 37 | }); 38 | -------------------------------------------------------------------------------- /specs/binary_search_spec.js: -------------------------------------------------------------------------------- 1 | describe("my_bsearch", () => { 2 | it("finds the first element in the array", () => { 3 | expect([1, 2, 3].myBsearch(1)).toEqual(0); 4 | }); 5 | 6 | it("finds an element for an array with an even number of elements", () => { 7 | expect([2, 3, 4, 5].myBsearch(3)).toEqual(1); 8 | }); 9 | 10 | it("finds an element for an array with an odd number of elements", () => { 11 | expect([2, 4, 6, 8, 10].myBsearch(6)).toEqual(2); 12 | }); 13 | 14 | it("finds an element in the second half of the array (even)", () => { 15 | expect([1, 3, 4, 5, 9].myBsearch(5)).toEqual(3); 16 | }); 17 | 18 | it("finds an element in the second half of the array (odd)", () => { 19 | expect([1, 2, 3, 4, 5, 6].myBsearch(6)).toEqual(5); 20 | }); 21 | 22 | it("Returns nil if the element is not in the array (smaller)", () => { 23 | expect([1, 2, 3, 4, 5, 6].myBsearch(0)).toEqual(null); 24 | }); 25 | 26 | it("Returns null if the element is not in the array (bigger)", () => { 27 | expect([1, 2, 3, 4, 5, 7].myBsearch(6)).toEqual(null); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /specs/my_slice_spec.js: -------------------------------------------------------------------------------- 1 | describe("String.prototype.mySlice", () => { 2 | it("slices the string from the start index to the end index", () => { 3 | expect("abcd".mySlice(0, 2)).toEqual("ab"); 4 | }); 5 | 6 | it("slices to the end of the string when no second argument is passed", () => { 7 | expect("foobar".mySlice(3)).toEqual("bar"); 8 | }); 9 | 10 | it("returns an empty string when the first argument is higher", () => { 11 | expect("empty!".mySlice(1, 0)).toEqual(""); 12 | }); 13 | 14 | it("slices to the end of the string when the end index is greater than the string's length", () => { 15 | expect("super long string".mySlice(0, 200)).toEqual("super long string"); 16 | }); 17 | 18 | it("doesn't call `substr`, `slice`, or `substring`", () => { 19 | const str = new String("don't you do it!"); 20 | spyOn(str, "substr"); 21 | spyOn(str, "slice"); 22 | spyOn(str, "substring"); 23 | 24 | str.mySlice(0); 25 | 26 | expect(str.substr).not.toHaveBeenCalled(); 27 | expect(str.slice).not.toHaveBeenCalled(); 28 | expect(str.substring).not.toHaveBeenCalled(); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /MIT.LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008-2016 Pivotal Labs 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /specs/my_inject_spec.js: -------------------------------------------------------------------------------- 1 | describe('Array#myReduce', () => { 2 | let myArray; 3 | const noOp = (accum, el) => accum; 4 | 5 | const spy = { 6 | sum: (accum, el) => accum + el 7 | }; 8 | 9 | it("calls the callback, passing in the accumulator and each element", () => { 10 | myArray = [1, 2, 3]; 11 | spyOn(spy, "sum").and.callThrough(); 12 | 13 | myArray.myReduce(spy.sum); 14 | 15 | expect(spy.sum).toHaveBeenCalledWith(1, 2); 16 | expect(spy.sum).toHaveBeenCalledWith(3, 3); 17 | }); 18 | 19 | it("works with a sum callback", () => { 20 | myArray = [1, 2, 3, 4]; 21 | expect(myArray.myReduce(spy.sum)).toEqual(10); 22 | }); 23 | 24 | it("works with a multiplier callback", () => { 25 | myArray = [4, 4, 4]; 26 | const times = (accum, el) => accum * el; 27 | 28 | expect(myArray.myReduce(times)).toEqual(64); 29 | }); 30 | 31 | it("uses the first item as the accumulator", () => { 32 | myArray = [1, 2, 3, 4]; 33 | expect(myArray.myReduce(noOp)).toEqual(1); 34 | }); 35 | 36 | it("does not call Array.prototype.reduce", () => { 37 | myArray = [1, 2, 3, 4]; 38 | spyOn(myArray, "reduce"); 39 | 40 | myArray.myReduce(spy.sum); 41 | 42 | expect(myArray.reduce).not.toHaveBeenCalled(); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /specs/transpose_spec.js: -------------------------------------------------------------------------------- 1 | describe("#transpose", () => { 2 | //before each necessary 3 | const arr = [ 4 | [1, 2, 3], 5 | [4, 5, 6], 6 | [7, 8, 9] 7 | ]; 8 | const small_arr = [ 9 | [1, 2], 10 | [3, 4] 11 | ]; 12 | const rect_arr = [ 13 | [1, 2, 3], 14 | [4, 5, 6] 15 | ]; 16 | const tall_rect_arr = [ 17 | [1, 2], 18 | [3, 4], 19 | [5, 6] 20 | ]; 21 | 22 | it("should transpose a matrix", () => { 23 | expect(transpose(arr)).toEqual([ 24 | [1, 4, 7], 25 | [2, 5, 8], 26 | [3, 6, 9] 27 | ]); 28 | }); 29 | 30 | it("should transpose a matrix of a different size", () => { 31 | expect(transpose(small_arr)).toEqual([ 32 | [1, 3], 33 | [2, 4] 34 | ]); 35 | }); 36 | 37 | it("should transpose a rectangular matrix", () => { 38 | expect(transpose(rect_arr)).toEqual([ 39 | [1, 4], 40 | [2, 5], 41 | [3, 6] 42 | ]); 43 | }); 44 | 45 | it("should transpose a different rectangular matrix", () => { 46 | expect(transpose(tall_rect_arr)).toEqual([ 47 | [1, 3, 5], 48 | [2, 4, 6] 49 | ]); 50 | }); 51 | 52 | it("should not modify the original", () => { 53 | transpose(small_arr); 54 | expect(small_arr).toEqual([ 55 | [1, 2], 56 | [3, 4] 57 | ]); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /specs/pig_latinify_spec.js: -------------------------------------------------------------------------------- 1 | describe("#pigLatinify", () => { 2 | it("translates a word beginning with a vowel", () => { 3 | const s = pigLatinify("apple"); 4 | expect(s).toEqual("appleay"); 5 | }); 6 | 7 | it("translates a word beginning with a consonant", () => { 8 | const s = pigLatinify("banana"); 9 | expect(s).toEqual("ananabay"); 10 | }); 11 | 12 | it("translates a word beginning with two consonants", () => { 13 | const s = pigLatinify("cherry"); 14 | expect(s).toEqual("errychay"); 15 | }); 16 | 17 | it("translates two words", () => { 18 | const s = pigLatinify("eat pie"); 19 | expect(s).toEqual("eatay iepay"); 20 | }); 21 | 22 | it("translates a word beginning with three consonants", () => { 23 | expect(pigLatinify("three")).toEqual("eethray");; 24 | }); 25 | 26 | it("counts 'sch' as a single phoneme", () => { 27 | const s = pigLatinify("school"); 28 | expect(s).toEqual("oolschay"); 29 | }); 30 | 31 | it("counts 'qu' as a single phoneme", () => { 32 | const s = pigLatinify("quiet"); 33 | expect(s).toEqual("ietquay"); 34 | }); 35 | 36 | it("counts 'qu' as a consonant when it's preceded by a consonant", () => { 37 | const s = pigLatinify("square"); 38 | expect(s).toEqual("aresquay"); 39 | }); 40 | 41 | it("translates many words", () => { 42 | const s = pigLatinify("the quick brown fox"); 43 | expect(s).toEqual("ethay ickquay ownbray oxfay"); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /specs/my_call_spec.js: -------------------------------------------------------------------------------- 1 | describe("Function.prototype.myCall", () => { 2 | beforeEach(() => { 3 | class Cat { 4 | constructor (name) { 5 | this.name = name; 6 | } 7 | 8 | sayHello () { 9 | return this.name + " says hello!"; 10 | } 11 | 12 | greetOne (otherCat) { 13 | return this.name + " says hello to " + otherCat.name; 14 | } 15 | 16 | greetTwo (otherCat1, otherCat2) { 17 | return this.name + " says hello to " + otherCat1.name + " and " + 18 | otherCat2.name; 19 | } 20 | } 21 | 22 | sally = new Cat("Sally"); 23 | markov = new Cat("Markov"); 24 | curie = new Cat("Curie"); 25 | }); 26 | 27 | it("invokes the function it is called on", () => { 28 | expect(sally.greetOne.myCall(sally, markov)).toEqual("Sally says hello to Markov"); 29 | }); 30 | 31 | it("can take any number of arguments", () => { 32 | expect(sally.greetTwo.myCall(sally, markov, curie)) 33 | .toEqual("Sally says hello to Markov and Curie"); 34 | }); 35 | it("does not use the 'call' function", () => { 36 | spyOn(Function.prototype, "call").and.callThrough(); 37 | 38 | sally.greetTwo.myCall(sally, markov, curie); 39 | const count = Function.prototype.call.calls.count() 40 | expect(count).toBeLessThan(1); 41 | }); 42 | 43 | it("should call the function method style on the context", () => { 44 | expect(sally.sayHello.myCall(markov)).toEqual("Markov says hello!"); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /specs/my_bind_spec.js: -------------------------------------------------------------------------------- 1 | describe("Function.prototype.myBind", () => { 2 | // let Cat; 3 | let sally, markov, curie; 4 | 5 | beforeEach(() => { 6 | class Cat { 7 | constructor (name) { 8 | this.name = name; 9 | } 10 | 11 | sayHello () { 12 | return this.name + " says hello!"; 13 | } 14 | 15 | greetOne (otherCat) { 16 | return this.name + " says hello to " + otherCat.name; 17 | } 18 | 19 | greetTwo (otherCat1, otherCat2) { 20 | return this.name + " says hello to " + otherCat1.name + " and " + 21 | otherCat2.name; 22 | } 23 | } 24 | 25 | sally = new Cat("Sally"); 26 | markov = new Cat("Markov"); 27 | curie = new Cat("Curie"); 28 | }); 29 | 30 | it("should call the function method style on the context", () => { 31 | expect(sally.sayHello.myBind(sally)()).toEqual("Sally says hello!"); 32 | }); 33 | 34 | it("should pass in bind-time argument to the method", () => { 35 | expect(sally.greetOne.myBind(sally, markov)()) 36 | .toEqual("Sally says hello to Markov"); 37 | }); 38 | 39 | it("should pass in two bind-time arguments to the method", () => { 40 | expect(sally.greetTwo.myBind(sally, markov, curie)()) 41 | .toEqual("Sally says hello to Markov and Curie"); 42 | }); 43 | 44 | it("should combine bind-time and call-time arguments", () => { 45 | expect(sally.greetTwo.myBind(sally, markov)(curie)) 46 | .toEqual("Sally says hello to Markov and Curie"); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /specs/inherits_spec.js: -------------------------------------------------------------------------------- 1 | describe("inherits", () => { 2 | let Animal, Dog, dog; 3 | 4 | beforeEach(() => { 5 | Animal = function() { 6 | this.name = "Yogi"; 7 | }; 8 | 9 | Animal.prototype.makeNoise = function() { return "Hi!"; }; 10 | 11 | Dog = function() { 12 | this.age = 7; 13 | }; 14 | 15 | Dog.inherits(Animal); 16 | 17 | Dog.prototype.bark = function() { return "Woof!"; }; 18 | 19 | dog = new Dog(); 20 | }); 21 | 22 | it("should properly set up the prototype chain between a child and parent", () => { 23 | expect(dog.bark()).toBe("Woof!"); 24 | expect(dog.makeNoise()).toBe("Hi!"); 25 | }); 26 | 27 | it("should not call the parent's constructor function", () => { 28 | expect(dog.name).toBeUndefined(); 29 | }); 30 | 31 | it("should maintain separation of parent and child prototypes", () => { 32 | Dog.prototype.someProperty = 42; 33 | const animal = new Animal(); 34 | expect(animal.someProperty).toBeUndefined(); 35 | expect(animal.makeNoise()).toBe("Hi!"); 36 | }); 37 | 38 | it("should properly work for longer inheritance chains", () => { 39 | const Poodle = function () { this.name = "Bill"; }; 40 | 41 | Poodle.inherits(Dog); 42 | 43 | Poodle.prototype.shave = function() { return "Brrr."; }; 44 | 45 | const poodle = new Poodle(); 46 | expect(poodle.name).toBe("Bill"); 47 | expect(poodle.shave()).toBe("Brrr."); 48 | expect(poodle.makeNoise()).toBe("Hi!"); 49 | expect(poodle.bark()).toBe("Woof!"); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # a/A Practice Test Generator 2 | 3 | [Mallory](https://github.com/mallorybulkley/) created this simple CLI practice test generator during her first week at App Academy to help herself and other students prepare for our first assessment. She wanted a way to simulate the actual test rather than just solving practice problems individually. The questions, Jasmine tests, and solutions were largely pulled from exercises we had encountered during the prepwork and first week of class, or contributed by other students. I pulled on her work and refactored it into JavaScript. 4 | 5 | 6 | All of the practice problems are listed and categorized in `list.csv` (categories include: recursion, sorting, enumerable, array, string). When you run `generator.rb` on the command line and provide your desired number of questions from each category, it uses your input and the CSV file to randomly select practice problems. It combines these problems and writes 3 new files inside the repo folder: 7 | * `practice_test.js` contains the problems to be solved 8 | * `spec.js` combines the specs for the chosen problems into one file for easy testing 9 | * `solutions.js` combines the solutions for each problem 10 | 11 | ## How to use this generator 12 | 13 | 1. Clone this repo 14 | 15 | 2. Navigate to the folder in terminal and run 16 | `ruby generator.rb` 17 | 18 | 3. Input your practice test requests in the form `category: # of problems` 19 | 20 | 4. You will now have three new files: `practice_test.js`, `spec.js` and `solutions.js`. Once these files are created, open `SpecRunner.html` in your browser. If you have not generated these files, the page will not open. 21 | 22 | 5. Check your solutions against those in `solutions.js`. 23 | 24 | Note: if you run the generator again in the same folder, it will re-write those three files and erase your previous work. If you wish to save your previous work, you will need to rename the files. 25 | -------------------------------------------------------------------------------- /generator.rb: -------------------------------------------------------------------------------- 1 | require 'csv' 2 | require 'colorize' 3 | 4 | # Instructions 5 | system("clear") 6 | puts "Welcome to Mallory's a/A Practice Assessment Generator".cyan 7 | puts "This generator will create a practice test based on your input. " \ 8 | "You can choose how many problems from each category to include in your test. " 9 | puts "This program will generate 3 files in this folder: practice_test, spec, and solution. " \ 10 | "Complete the practice_test file, running the spec file to check your answers. " \ 11 | "When your time is up (you are timing yourself, right?), compare your answers to the solutions." 12 | puts "Good luck!" 13 | 14 | # read in csv with test info 15 | tests = CSV.read('list.csv', headers: true, header_converters: :symbol, converters: :all) 16 | 17 | # list possible categories 18 | categories = Array.new 19 | tests.each do |test| 20 | categories << test[1] 21 | end 22 | categories = categories.uniq 23 | puts "Possible categories: #{categories.join(", ")}".magenta 24 | puts 25 | 26 | # get user request 27 | puts "Input your requests, separated by commas and spaces please" 28 | puts "Example input: " + "array: 2, recursion: 1, etc. ".yellow 29 | input = gets.chomp.split(", ") 30 | 31 | categoryrequests = Hash.new(0) 32 | input.each do |request| 33 | req = request.downcase.split(": ") 34 | categoryrequests[req[0]] = req[1].to_i 35 | end 36 | 37 | # make test array for each category 38 | master = Array.new 39 | categories.each do |category| 40 | problems_in_category = Array.new 41 | tests.each do |test| 42 | if category == test[1] 43 | problems_in_category << test 44 | end 45 | end 46 | 47 | # pick tests at random from each category 48 | n = categoryrequests[category] 49 | master = master.concat(problems_in_category.sample(n)) 50 | end 51 | 52 | # create new test, spec and solution files 53 | practice_test = File.open("practice_test.js", "w") 54 | spec = File.open("spec.js", "w") 55 | solution = File.open("solution.js", "w") 56 | 57 | # require rspec and the practice_test in the spec 58 | # spec << "import Jasmine from 'jasmine';" << "\n" 59 | # spec << "import practiceTest from './practice_test';" << "\n" 60 | 61 | # loop through master tests and add text to the new files 62 | master.each do |test| 63 | practice_test << File.read(test[2]) << "\n" 64 | spec << File.read(test[3]) << "\n" 65 | solution << File.read(test[4]) << "\n" 66 | end 67 | 68 | # close the files that were just created 69 | practice_test.close 70 | spec.close 71 | solution.close 72 | 73 | puts 74 | puts "Done!" 75 | -------------------------------------------------------------------------------- /list.csv: -------------------------------------------------------------------------------- 1 | Name,Category,ProblemFile,SpecFile,SolutionFile 2 | base_converter,recursion,problems/base_converter.js,specs/base_converter_spec.js,solutions/base_converter_solution.js 3 | binary_search,array,problems/binary_search.js,specs/binary_search_spec.js,solutions/binary_search_solution.js 4 | bubble_sort,sort,problems/bubble_sort.js,specs/bubble_sort_spec.js,solutions/bubble_sort_solution.js 5 | caesar_cipher,string,problems/caesar_cipher.js,specs/caesar_cipher_spec.js,solutions/caesar_cipher_solution.js 6 | deep_dup,recursion,problems/deep_dup.js,specs/deep_dup_spec.js,solutions/deep_dup_solution.js 7 | digital_root,recursion,problems/digital_root.js,specs/digital_root_spec.js,solutions/digital_root_solution.js 8 | doubler,enumerable,problems/doubler.js,specs/doubler_spec.js,solutions/doubler_solution.js 9 | dups,array,problems/dups.js,specs/dups_spec.js,solutions/dups_solution.js 10 | exponent,recursion,problems/exponent.js,specs/exponent_spec.js,solutions/exponent_solution.js 11 | factorials_rec,recursion,problems/factorials_rec.js,specs/factorials_rec_spec.js,solutions/factorials_rec_solution.js 12 | factors,array,problems/factors.js,specs/factors_spec.js,solutions/factors_solution.js 13 | fibs_sum,recursion,problems/fibs_sum.js,specs/fibs_sum_spec.js,solutions/fibs_sum_solution.js 14 | first_even_numbers_sum,recursion,problems/first_even_numbers_sum.js,specs/first_even_numbers_sum_spec.js,solutions/first_even_numbers_sum_solution.js 15 | inherits,function,problems/inherits.js,specs/inherits_spec.js,specs/inherits_spec.js 16 | jumble_sort,sort,problems/jumble_sort.js,specs/jumble_sort_spec.js,solutions/jumble_sort_solution.js 17 | median,array,problems/median.js,specs/median_spec.js,solutions/median_solution.js 18 | merge_sort,sort,problems/merge_sort.js,specs/merge_sort_spec.js,solutions/merge_sort_solution.js 19 | my_every,enumerable,problems/my_every.js,specs/my_every_spec.js,solutions/my_every_solution.js 20 | my_some,enumerable,problems/my_some.js,specs/my_some_spec.js,solutions/my_some_solution.js 21 | my_bind,function,problems/my_bind.js,specs/my_bind_spec.js,solutions/my_bind_solution.js 22 | my_call,function,problems/my_call.js,specs/my_call_spec.js,solutions/my_call_solution.js 23 | my_curry,function,problems/my_curry.js,specs/my_curry_spec.js,solutions/my_curry_solution.js 24 | my_each,enumerable,problems/my_each.js,specs/my_each_spec.js,solutions/my_each_solution.js 25 | my_find,array,problems/my_find.js,specs/my_find_spec.js,solutions/my_find_solution.js 26 | my_flatten,array,problems/my_flatten.js,specs/my_flatten_spec.js,solutions/my_flatten_solution.js 27 | my_inject,enumerable,problems/my_inject.js,specs/my_inject_spec.js,solutions/my_inject_solution.js 28 | my_join,array,problems/my_join.js,specs/my_join_spec.js,solutions/my_join_solution.js 29 | my_reject,enumerable,problems/my_reject.js,specs/my_reject_spec.js,solutions/my_reject_solution.js 30 | my_reverse,array,problems/my_reverse.js,specs/my_reverse_spec.js,solutions/my_reverse_solution.js 31 | my_rotate,array,problems/my_rotate.js,specs/my_rotate_spec.js,solutions/my_rotate_solution.js 32 | my_filter,enumerable,problems/my_filter.js,specs/my_filter_spec.js,solutions/my_filter_solution.js 33 | my_slice,array,problems/my_slice.js,specs/my_slice_spec.js,solutions/my_slice_solution.js 34 | permutations,recursion,problems/permutations.js,specs/permutations_spec.js,solutions/permutations_solution.js 35 | pig_latinify,string,problems/pig_latinify.js,specs/pig_latinify_spec.js,solutions/pig_latinify_solution.js 36 | prime_factorization,recursion,problems/prime_factorization.js,specs/prime_factorization_spec.js,solutions/prime_factorization_solution.js 37 | primes,array,problems/primes.js,specs/primes_spec.js,solutions/primes_solution.js 38 | quicksort,sort,problems/quicksort.js,specs/quicksort_spec.js,solutions/quicksort_solution.js 39 | real_words_in_string,string,problems/real_words_in_string.js,specs/real_words_in_string_spec.js,solutions/real_words_in_string_solution.js 40 | rec_sum,recursion,problems/rec_sum.js,specs/rec_sum_spec.js,solutions/rec_sum_solution.js 41 | string_include_key,recursion,problems/string_include_key.js,specs/string_include_key_spec.js,solutions/string_include_key_solution.js 42 | subsets,recursion,problems/subsets.js,specs/subsets_spec.js,solutions/subsets_solution.js 43 | symmetric_substrings,string,problems/symmetric_substrings.js,specs/symmetric_substrings_spec.js,solutions/symmetric_substrings_solution.js 44 | titleize,string,problems/titleize.js,specs/titleize_spec.js,solutions/titleize_solution.js 45 | transpose,array,problems/transpose.js,specs/transpose_spec.js,solutions/transpose_solution.js 46 | two_sum,array,problems/two_sum.js,specs/two_sum_spec.js,solutions/two_sum_solution.js 47 | -------------------------------------------------------------------------------- /lib/jasmine-2.5.2/boot.js: -------------------------------------------------------------------------------- 1 | /** 2 | Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js` and `jasmine_html.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project. 3 | 4 | If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms. 5 | 6 | The location of `boot.js` can be specified and/or overridden in `jasmine.yml`. 7 | 8 | [jasmine-gem]: http://github.com/pivotal/jasmine-gem 9 | */ 10 | 11 | (function() { 12 | 13 | /** 14 | * ## Require & Instantiate 15 | * 16 | * Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference. 17 | */ 18 | window.jasmine = jasmineRequire.core(jasmineRequire); 19 | 20 | /** 21 | * Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference. 22 | */ 23 | jasmineRequire.html(jasmine); 24 | 25 | /** 26 | * Create the Jasmine environment. This is used to run all specs in a project. 27 | */ 28 | var env = jasmine.getEnv(); 29 | 30 | /** 31 | * ## The Global Interface 32 | * 33 | * Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged. 34 | */ 35 | var jasmineInterface = jasmineRequire.interface(jasmine, env); 36 | 37 | /** 38 | * Add all of the Jasmine global/public interface to the global scope, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`. 39 | */ 40 | extend(window, jasmineInterface); 41 | 42 | /** 43 | * ## Runner Parameters 44 | * 45 | * More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface. 46 | */ 47 | 48 | var queryString = new jasmine.QueryString({ 49 | getWindowLocation: function() { return window.location; } 50 | }); 51 | 52 | var catchingExceptions = queryString.getParam("catch"); 53 | env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions); 54 | 55 | var throwingExpectationFailures = queryString.getParam("throwFailures"); 56 | env.throwOnExpectationFailure(throwingExpectationFailures); 57 | 58 | var random = queryString.getParam("random"); 59 | env.randomizeTests(random); 60 | 61 | var seed = queryString.getParam("seed"); 62 | if (seed) { 63 | env.seed(seed); 64 | } 65 | 66 | /** 67 | * ## Reporters 68 | * The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any). 69 | */ 70 | var htmlReporter = new jasmine.HtmlReporter({ 71 | env: env, 72 | onRaiseExceptionsClick: function() { queryString.navigateWithNewParam("catch", !env.catchingExceptions()); }, 73 | onThrowExpectationsClick: function() { queryString.navigateWithNewParam("throwFailures", !env.throwingExpectationFailures()); }, 74 | onRandomClick: function() { queryString.navigateWithNewParam("random", !env.randomTests()); }, 75 | addToExistingQueryString: function(key, value) { return queryString.fullStringWithNewParam(key, value); }, 76 | getContainer: function() { return document.body; }, 77 | createElement: function() { return document.createElement.apply(document, arguments); }, 78 | createTextNode: function() { return document.createTextNode.apply(document, arguments); }, 79 | timer: new jasmine.Timer() 80 | }); 81 | 82 | /** 83 | * The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript. 84 | */ 85 | env.addReporter(jasmineInterface.jsApiReporter); 86 | env.addReporter(htmlReporter); 87 | 88 | /** 89 | * Filter which specs will be run by matching the start of the full name against the `spec` query param. 90 | */ 91 | var specFilter = new jasmine.HtmlSpecFilter({ 92 | filterString: function() { return queryString.getParam("spec"); } 93 | }); 94 | 95 | env.specFilter = function(spec) { 96 | return specFilter.matches(spec.getFullName()); 97 | }; 98 | 99 | /** 100 | * Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack. 101 | */ 102 | window.setTimeout = window.setTimeout; 103 | window.setInterval = window.setInterval; 104 | window.clearTimeout = window.clearTimeout; 105 | window.clearInterval = window.clearInterval; 106 | 107 | /** 108 | * ## Execution 109 | * 110 | * Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded. 111 | */ 112 | var currentWindowOnload = window.onload; 113 | 114 | window.onload = function() { 115 | if (currentWindowOnload) { 116 | currentWindowOnload(); 117 | } 118 | htmlReporter.initialize(); 119 | env.execute(); 120 | }; 121 | 122 | /** 123 | * Helper function for readability above. 124 | */ 125 | function extend(destination, source) { 126 | for (var property in source) destination[property] = source[property]; 127 | return destination; 128 | } 129 | 130 | }()); 131 | -------------------------------------------------------------------------------- /lib/jasmine-2.5.2/console.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008-2016 Pivotal Labs 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | function getJasmineRequireObj() { 24 | if (typeof module !== 'undefined' && module.exports) { 25 | return exports; 26 | } else { 27 | window.jasmineRequire = window.jasmineRequire || {}; 28 | return window.jasmineRequire; 29 | } 30 | } 31 | 32 | getJasmineRequireObj().console = function(jRequire, j$) { 33 | j$.ConsoleReporter = jRequire.ConsoleReporter(); 34 | }; 35 | 36 | getJasmineRequireObj().ConsoleReporter = function() { 37 | 38 | var noopTimer = { 39 | start: function(){}, 40 | elapsed: function(){ return 0; } 41 | }; 42 | 43 | function ConsoleReporter(options) { 44 | var print = options.print, 45 | showColors = options.showColors || false, 46 | onComplete = options.onComplete || function() {}, 47 | timer = options.timer || noopTimer, 48 | specCount, 49 | failureCount, 50 | failedSpecs = [], 51 | pendingCount, 52 | ansi = { 53 | green: '\x1B[32m', 54 | red: '\x1B[31m', 55 | yellow: '\x1B[33m', 56 | none: '\x1B[0m' 57 | }, 58 | failedSuites = []; 59 | 60 | print('ConsoleReporter is deprecated and will be removed in a future version.'); 61 | 62 | this.jasmineStarted = function() { 63 | specCount = 0; 64 | failureCount = 0; 65 | pendingCount = 0; 66 | print('Started'); 67 | printNewline(); 68 | timer.start(); 69 | }; 70 | 71 | this.jasmineDone = function() { 72 | printNewline(); 73 | for (var i = 0; i < failedSpecs.length; i++) { 74 | specFailureDetails(failedSpecs[i]); 75 | } 76 | 77 | if(specCount > 0) { 78 | printNewline(); 79 | 80 | var specCounts = specCount + ' ' + plural('spec', specCount) + ', ' + 81 | failureCount + ' ' + plural('failure', failureCount); 82 | 83 | if (pendingCount) { 84 | specCounts += ', ' + pendingCount + ' pending ' + plural('spec', pendingCount); 85 | } 86 | 87 | print(specCounts); 88 | } else { 89 | print('No specs found'); 90 | } 91 | 92 | printNewline(); 93 | var seconds = timer.elapsed() / 1000; 94 | print('Finished in ' + seconds + ' ' + plural('second', seconds)); 95 | printNewline(); 96 | 97 | for(i = 0; i < failedSuites.length; i++) { 98 | suiteFailureDetails(failedSuites[i]); 99 | } 100 | 101 | onComplete(failureCount === 0); 102 | }; 103 | 104 | this.specDone = function(result) { 105 | specCount++; 106 | 107 | if (result.status == 'pending') { 108 | pendingCount++; 109 | print(colored('yellow', '*')); 110 | return; 111 | } 112 | 113 | if (result.status == 'passed') { 114 | print(colored('green', '.')); 115 | return; 116 | } 117 | 118 | if (result.status == 'failed') { 119 | failureCount++; 120 | failedSpecs.push(result); 121 | print(colored('red', 'F')); 122 | } 123 | }; 124 | 125 | this.suiteDone = function(result) { 126 | if (result.failedExpectations && result.failedExpectations.length > 0) { 127 | failureCount++; 128 | failedSuites.push(result); 129 | } 130 | }; 131 | 132 | return this; 133 | 134 | function printNewline() { 135 | print('\n'); 136 | } 137 | 138 | function colored(color, str) { 139 | return showColors ? (ansi[color] + str + ansi.none) : str; 140 | } 141 | 142 | function plural(str, count) { 143 | return count == 1 ? str : str + 's'; 144 | } 145 | 146 | function repeat(thing, times) { 147 | var arr = []; 148 | for (var i = 0; i < times; i++) { 149 | arr.push(thing); 150 | } 151 | return arr; 152 | } 153 | 154 | function indent(str, spaces) { 155 | var lines = (str || '').split('\n'); 156 | var newArr = []; 157 | for (var i = 0; i < lines.length; i++) { 158 | newArr.push(repeat(' ', spaces).join('') + lines[i]); 159 | } 160 | return newArr.join('\n'); 161 | } 162 | 163 | function specFailureDetails(result) { 164 | printNewline(); 165 | print(result.fullName); 166 | 167 | for (var i = 0; i < result.failedExpectations.length; i++) { 168 | var failedExpectation = result.failedExpectations[i]; 169 | printNewline(); 170 | print(indent(failedExpectation.message, 2)); 171 | print(indent(failedExpectation.stack, 2)); 172 | } 173 | 174 | printNewline(); 175 | } 176 | 177 | function suiteFailureDetails(result) { 178 | for (var i = 0; i < result.failedExpectations.length; i++) { 179 | printNewline(); 180 | print(colored('red', 'An error was thrown in an afterAll')); 181 | printNewline(); 182 | print(colored('red', 'AfterAll ' + result.failedExpectations[i].message)); 183 | 184 | } 185 | printNewline(); 186 | } 187 | } 188 | 189 | return ConsoleReporter; 190 | }; 191 | -------------------------------------------------------------------------------- /lib/jasmine-2.5.2/jasmine-html.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008-2016 Pivotal Labs 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | jasmineRequire.html = function(j$) { 24 | j$.ResultsNode = jasmineRequire.ResultsNode(); 25 | j$.HtmlReporter = jasmineRequire.HtmlReporter(j$); 26 | j$.QueryString = jasmineRequire.QueryString(); 27 | j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter(); 28 | }; 29 | 30 | jasmineRequire.HtmlReporter = function(j$) { 31 | 32 | var noopTimer = { 33 | start: function() {}, 34 | elapsed: function() { return 0; } 35 | }; 36 | 37 | function HtmlReporter(options) { 38 | var env = options.env || {}, 39 | getContainer = options.getContainer, 40 | createElement = options.createElement, 41 | createTextNode = options.createTextNode, 42 | onRaiseExceptionsClick = options.onRaiseExceptionsClick || function() {}, 43 | onThrowExpectationsClick = options.onThrowExpectationsClick || function() {}, 44 | onRandomClick = options.onRandomClick || function() {}, 45 | addToExistingQueryString = options.addToExistingQueryString || defaultQueryString, 46 | timer = options.timer || noopTimer, 47 | results = [], 48 | specsExecuted = 0, 49 | failureCount = 0, 50 | pendingSpecCount = 0, 51 | htmlReporterMain, 52 | symbols, 53 | failedSuites = []; 54 | 55 | this.initialize = function() { 56 | clearPrior(); 57 | htmlReporterMain = createDom('div', {className: 'jasmine_html-reporter'}, 58 | createDom('div', {className: 'jasmine-banner'}, 59 | createDom('a', {className: 'jasmine-title', href: 'http://jasmine.github.io/', target: '_blank'}), 60 | createDom('span', {className: 'jasmine-version'}, j$.version) 61 | ), 62 | createDom('ul', {className: 'jasmine-symbol-summary'}), 63 | createDom('div', {className: 'jasmine-alert'}), 64 | createDom('div', {className: 'jasmine-results'}, 65 | createDom('div', {className: 'jasmine-failures'}) 66 | ) 67 | ); 68 | getContainer().appendChild(htmlReporterMain); 69 | }; 70 | 71 | var totalSpecsDefined; 72 | this.jasmineStarted = function(options) { 73 | totalSpecsDefined = options.totalSpecsDefined || 0; 74 | timer.start(); 75 | }; 76 | 77 | var summary = createDom('div', {className: 'jasmine-summary'}); 78 | 79 | var topResults = new j$.ResultsNode({}, '', null), 80 | currentParent = topResults; 81 | 82 | this.suiteStarted = function(result) { 83 | currentParent.addChild(result, 'suite'); 84 | currentParent = currentParent.last(); 85 | }; 86 | 87 | this.suiteDone = function(result) { 88 | if (result.status == 'failed') { 89 | failedSuites.push(result); 90 | } 91 | 92 | if (currentParent == topResults) { 93 | return; 94 | } 95 | 96 | currentParent = currentParent.parent; 97 | }; 98 | 99 | this.specStarted = function(result) { 100 | currentParent.addChild(result, 'spec'); 101 | }; 102 | 103 | var failures = []; 104 | this.specDone = function(result) { 105 | if(noExpectations(result) && typeof console !== 'undefined' && typeof console.error !== 'undefined') { 106 | console.error('Spec \'' + result.fullName + '\' has no expectations.'); 107 | } 108 | 109 | if (result.status != 'disabled') { 110 | specsExecuted++; 111 | } 112 | 113 | if (!symbols){ 114 | symbols = find('.jasmine-symbol-summary'); 115 | } 116 | 117 | symbols.appendChild(createDom('li', { 118 | className: noExpectations(result) ? 'jasmine-empty' : 'jasmine-' + result.status, 119 | id: 'spec_' + result.id, 120 | title: result.fullName 121 | } 122 | )); 123 | 124 | if (result.status == 'failed') { 125 | failureCount++; 126 | 127 | var failure = 128 | createDom('div', {className: 'jasmine-spec-detail jasmine-failed'}, 129 | createDom('div', {className: 'jasmine-description'}, 130 | createDom('a', {title: result.fullName, href: specHref(result)}, result.fullName) 131 | ), 132 | createDom('div', {className: 'jasmine-messages'}) 133 | ); 134 | var messages = failure.childNodes[1]; 135 | 136 | for (var i = 0; i < result.failedExpectations.length; i++) { 137 | var expectation = result.failedExpectations[i]; 138 | messages.appendChild(createDom('div', {className: 'jasmine-result-message'}, expectation.message)); 139 | messages.appendChild(createDom('div', {className: 'jasmine-stack-trace'}, expectation.stack)); 140 | } 141 | 142 | failures.push(failure); 143 | } 144 | 145 | if (result.status == 'pending') { 146 | pendingSpecCount++; 147 | } 148 | }; 149 | 150 | this.jasmineDone = function(doneResult) { 151 | var banner = find('.jasmine-banner'); 152 | var alert = find('.jasmine-alert'); 153 | var order = doneResult && doneResult.order; 154 | alert.appendChild(createDom('span', {className: 'jasmine-duration'}, 'finished in ' + timer.elapsed() / 1000 + 's')); 155 | 156 | banner.appendChild( 157 | createDom('div', { className: 'jasmine-run-options' }, 158 | createDom('span', { className: 'jasmine-trigger' }, 'Options'), 159 | createDom('div', { className: 'jasmine-payload' }, 160 | createDom('div', { className: 'jasmine-exceptions' }, 161 | createDom('input', { 162 | className: 'jasmine-raise', 163 | id: 'jasmine-raise-exceptions', 164 | type: 'checkbox' 165 | }), 166 | createDom('label', { className: 'jasmine-label', 'for': 'jasmine-raise-exceptions' }, 'raise exceptions')), 167 | createDom('div', { className: 'jasmine-throw-failures' }, 168 | createDom('input', { 169 | className: 'jasmine-throw', 170 | id: 'jasmine-throw-failures', 171 | type: 'checkbox' 172 | }), 173 | createDom('label', { className: 'jasmine-label', 'for': 'jasmine-throw-failures' }, 'stop spec on expectation failure')), 174 | createDom('div', { className: 'jasmine-random-order' }, 175 | createDom('input', { 176 | className: 'jasmine-random', 177 | id: 'jasmine-random-order', 178 | type: 'checkbox' 179 | }), 180 | createDom('label', { className: 'jasmine-label', 'for': 'jasmine-random-order' }, 'run tests in random order')) 181 | ) 182 | )); 183 | 184 | var raiseCheckbox = find('#jasmine-raise-exceptions'); 185 | 186 | raiseCheckbox.checked = !env.catchingExceptions(); 187 | raiseCheckbox.onclick = onRaiseExceptionsClick; 188 | 189 | var throwCheckbox = find('#jasmine-throw-failures'); 190 | throwCheckbox.checked = env.throwingExpectationFailures(); 191 | throwCheckbox.onclick = onThrowExpectationsClick; 192 | 193 | var randomCheckbox = find('#jasmine-random-order'); 194 | randomCheckbox.checked = env.randomTests(); 195 | randomCheckbox.onclick = onRandomClick; 196 | 197 | var optionsMenu = find('.jasmine-run-options'), 198 | optionsTrigger = optionsMenu.querySelector('.jasmine-trigger'), 199 | optionsPayload = optionsMenu.querySelector('.jasmine-payload'), 200 | isOpen = /\bjasmine-open\b/; 201 | 202 | optionsTrigger.onclick = function() { 203 | if (isOpen.test(optionsPayload.className)) { 204 | optionsPayload.className = optionsPayload.className.replace(isOpen, ''); 205 | } else { 206 | optionsPayload.className += ' jasmine-open'; 207 | } 208 | }; 209 | 210 | if (specsExecuted < totalSpecsDefined) { 211 | var skippedMessage = 'Ran ' + specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all'; 212 | var skippedLink = order && order.random ? '?random=true' : '?'; 213 | alert.appendChild( 214 | createDom('span', {className: 'jasmine-bar jasmine-skipped'}, 215 | createDom('a', {href: skippedLink, title: 'Run all specs'}, skippedMessage) 216 | ) 217 | ); 218 | } 219 | var statusBarMessage = ''; 220 | var statusBarClassName = 'jasmine-bar '; 221 | 222 | if (totalSpecsDefined > 0) { 223 | statusBarMessage += pluralize('spec', specsExecuted) + ', ' + pluralize('failure', failureCount); 224 | if (pendingSpecCount) { statusBarMessage += ', ' + pluralize('pending spec', pendingSpecCount); } 225 | statusBarClassName += (failureCount > 0) ? 'jasmine-failed' : 'jasmine-passed'; 226 | } else { 227 | statusBarClassName += 'jasmine-skipped'; 228 | statusBarMessage += 'No specs found'; 229 | } 230 | 231 | var seedBar; 232 | if (order && order.random) { 233 | seedBar = createDom('span', {className: 'jasmine-seed-bar'}, 234 | ', randomized with seed ', 235 | createDom('a', {title: 'randomized with seed ' + order.seed, href: seedHref(order.seed)}, order.seed) 236 | ); 237 | } 238 | 239 | alert.appendChild(createDom('span', {className: statusBarClassName}, statusBarMessage, seedBar)); 240 | 241 | var errorBarClassName = 'jasmine-bar jasmine-errored'; 242 | var errorBarMessagePrefix = 'AfterAll '; 243 | 244 | for(var i = 0; i < failedSuites.length; i++) { 245 | var failedSuite = failedSuites[i]; 246 | for(var j = 0; j < failedSuite.failedExpectations.length; j++) { 247 | alert.appendChild(createDom('span', {className: errorBarClassName}, errorBarMessagePrefix + failedSuite.failedExpectations[j].message)); 248 | } 249 | } 250 | 251 | var globalFailures = (doneResult && doneResult.failedExpectations) || []; 252 | for(i = 0; i < globalFailures.length; i++) { 253 | var failure = globalFailures[i]; 254 | alert.appendChild(createDom('span', {className: errorBarClassName}, errorBarMessagePrefix + failure.message)); 255 | } 256 | 257 | var results = find('.jasmine-results'); 258 | results.appendChild(summary); 259 | 260 | summaryList(topResults, summary); 261 | 262 | function summaryList(resultsTree, domParent) { 263 | var specListNode; 264 | for (var i = 0; i < resultsTree.children.length; i++) { 265 | var resultNode = resultsTree.children[i]; 266 | if (resultNode.type == 'suite') { 267 | var suiteListNode = createDom('ul', {className: 'jasmine-suite', id: 'suite-' + resultNode.result.id}, 268 | createDom('li', {className: 'jasmine-suite-detail'}, 269 | createDom('a', {href: specHref(resultNode.result)}, resultNode.result.description) 270 | ) 271 | ); 272 | 273 | summaryList(resultNode, suiteListNode); 274 | domParent.appendChild(suiteListNode); 275 | } 276 | if (resultNode.type == 'spec') { 277 | if (domParent.getAttribute('class') != 'jasmine-specs') { 278 | specListNode = createDom('ul', {className: 'jasmine-specs'}); 279 | domParent.appendChild(specListNode); 280 | } 281 | var specDescription = resultNode.result.description; 282 | if(noExpectations(resultNode.result)) { 283 | specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription; 284 | } 285 | if(resultNode.result.status === 'pending' && resultNode.result.pendingReason !== '') { 286 | specDescription = specDescription + ' PENDING WITH MESSAGE: ' + resultNode.result.pendingReason; 287 | } 288 | specListNode.appendChild( 289 | createDom('li', { 290 | className: 'jasmine-' + resultNode.result.status, 291 | id: 'spec-' + resultNode.result.id 292 | }, 293 | createDom('a', {href: specHref(resultNode.result)}, specDescription) 294 | ) 295 | ); 296 | } 297 | } 298 | } 299 | 300 | if (failures.length) { 301 | alert.appendChild( 302 | createDom('span', {className: 'jasmine-menu jasmine-bar jasmine-spec-list'}, 303 | createDom('span', {}, 'Spec List | '), 304 | createDom('a', {className: 'jasmine-failures-menu', href: '#'}, 'Failures'))); 305 | alert.appendChild( 306 | createDom('span', {className: 'jasmine-menu jasmine-bar jasmine-failure-list'}, 307 | createDom('a', {className: 'jasmine-spec-list-menu', href: '#'}, 'Spec List'), 308 | createDom('span', {}, ' | Failures '))); 309 | 310 | find('.jasmine-failures-menu').onclick = function() { 311 | setMenuModeTo('jasmine-failure-list'); 312 | }; 313 | find('.jasmine-spec-list-menu').onclick = function() { 314 | setMenuModeTo('jasmine-spec-list'); 315 | }; 316 | 317 | setMenuModeTo('jasmine-failure-list'); 318 | 319 | var failureNode = find('.jasmine-failures'); 320 | for (i = 0; i < failures.length; i++) { 321 | failureNode.appendChild(failures[i]); 322 | } 323 | } 324 | }; 325 | 326 | return this; 327 | 328 | function find(selector) { 329 | return getContainer().querySelector('.jasmine_html-reporter ' + selector); 330 | } 331 | 332 | function clearPrior() { 333 | // return the reporter 334 | var oldReporter = find(''); 335 | 336 | if(oldReporter) { 337 | getContainer().removeChild(oldReporter); 338 | } 339 | } 340 | 341 | function createDom(type, attrs, childrenVarArgs) { 342 | var el = createElement(type); 343 | 344 | for (var i = 2; i < arguments.length; i++) { 345 | var child = arguments[i]; 346 | 347 | if (typeof child === 'string') { 348 | el.appendChild(createTextNode(child)); 349 | } else { 350 | if (child) { 351 | el.appendChild(child); 352 | } 353 | } 354 | } 355 | 356 | for (var attr in attrs) { 357 | if (attr == 'className') { 358 | el[attr] = attrs[attr]; 359 | } else { 360 | el.setAttribute(attr, attrs[attr]); 361 | } 362 | } 363 | 364 | return el; 365 | } 366 | 367 | function pluralize(singular, count) { 368 | var word = (count == 1 ? singular : singular + 's'); 369 | 370 | return '' + count + ' ' + word; 371 | } 372 | 373 | function specHref(result) { 374 | return addToExistingQueryString('spec', result.fullName); 375 | } 376 | 377 | function seedHref(seed) { 378 | return addToExistingQueryString('seed', seed); 379 | } 380 | 381 | function defaultQueryString(key, value) { 382 | return '?' + key + '=' + value; 383 | } 384 | 385 | function setMenuModeTo(mode) { 386 | htmlReporterMain.setAttribute('class', 'jasmine_html-reporter ' + mode); 387 | } 388 | 389 | function noExpectations(result) { 390 | return (result.failedExpectations.length + result.passedExpectations.length) === 0 && 391 | result.status === 'passed'; 392 | } 393 | } 394 | 395 | return HtmlReporter; 396 | }; 397 | 398 | jasmineRequire.HtmlSpecFilter = function() { 399 | function HtmlSpecFilter(options) { 400 | var filterString = options && options.filterString() && options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); 401 | var filterPattern = new RegExp(filterString); 402 | 403 | this.matches = function(specName) { 404 | return filterPattern.test(specName); 405 | }; 406 | } 407 | 408 | return HtmlSpecFilter; 409 | }; 410 | 411 | jasmineRequire.ResultsNode = function() { 412 | function ResultsNode(result, type, parent) { 413 | this.result = result; 414 | this.type = type; 415 | this.parent = parent; 416 | 417 | this.children = []; 418 | 419 | this.addChild = function(result, type) { 420 | this.children.push(new ResultsNode(result, type, this)); 421 | }; 422 | 423 | this.last = function() { 424 | return this.children[this.children.length - 1]; 425 | }; 426 | } 427 | 428 | return ResultsNode; 429 | }; 430 | 431 | jasmineRequire.QueryString = function() { 432 | function QueryString(options) { 433 | 434 | this.navigateWithNewParam = function(key, value) { 435 | options.getWindowLocation().search = this.fullStringWithNewParam(key, value); 436 | }; 437 | 438 | this.fullStringWithNewParam = function(key, value) { 439 | var paramMap = queryStringToParamMap(); 440 | paramMap[key] = value; 441 | return toQueryString(paramMap); 442 | }; 443 | 444 | this.getParam = function(key) { 445 | return queryStringToParamMap()[key]; 446 | }; 447 | 448 | return this; 449 | 450 | function toQueryString(paramMap) { 451 | var qStrPairs = []; 452 | for (var prop in paramMap) { 453 | qStrPairs.push(encodeURIComponent(prop) + '=' + encodeURIComponent(paramMap[prop])); 454 | } 455 | return '?' + qStrPairs.join('&'); 456 | } 457 | 458 | function queryStringToParamMap() { 459 | var paramStr = options.getWindowLocation().search.substring(1), 460 | params = [], 461 | paramMap = {}; 462 | 463 | if (paramStr.length > 0) { 464 | params = paramStr.split('&'); 465 | for (var i = 0; i < params.length; i++) { 466 | var p = params[i].split('='); 467 | var value = decodeURIComponent(p[1]); 468 | if (value === 'true' || value === 'false') { 469 | value = JSON.parse(value); 470 | } 471 | paramMap[decodeURIComponent(p[0])] = value; 472 | } 473 | } 474 | 475 | return paramMap; 476 | } 477 | 478 | } 479 | 480 | return QueryString; 481 | }; 482 | -------------------------------------------------------------------------------- /lib/jasmine-2.5.2/jasmine.css: -------------------------------------------------------------------------------- 1 | body { overflow-y: scroll; } 2 | 3 | .jasmine_html-reporter { background-color: #eee; padding: 5px; margin: -8px; font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333; } 4 | .jasmine_html-reporter a { text-decoration: none; } 5 | .jasmine_html-reporter a:hover { text-decoration: underline; } 6 | .jasmine_html-reporter p, .jasmine_html-reporter h1, .jasmine_html-reporter h2, .jasmine_html-reporter h3, .jasmine_html-reporter h4, .jasmine_html-reporter h5, .jasmine_html-reporter h6 { margin: 0; line-height: 14px; } 7 | .jasmine_html-reporter .jasmine-banner, .jasmine_html-reporter .jasmine-symbol-summary, .jasmine_html-reporter .jasmine-summary, .jasmine_html-reporter .jasmine-result-message, .jasmine_html-reporter .jasmine-spec .jasmine-description, .jasmine_html-reporter .jasmine-spec-detail .jasmine-description, .jasmine_html-reporter .jasmine-alert .jasmine-bar, .jasmine_html-reporter .jasmine-stack-trace { padding-left: 9px; padding-right: 9px; } 8 | .jasmine_html-reporter .jasmine-banner { position: relative; } 9 | .jasmine_html-reporter .jasmine-banner .jasmine-title { background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAAAZCAMAAACGusnyAAACdlBMVEX/////AP+AgICqVaqAQICZM5mAVYCSSZKAQICOOY6ATYCLRouAQICJO4mSSYCIRIiPQICHPIeOR4CGQ4aMQICGPYaLRoCFQ4WKQICPPYWJRYCOQoSJQICNPoSIRICMQoSHQICHRICKQoOHQICKPoOJO4OJQYOMQICMQ4CIQYKLQICIPoKLQ4CKQICNPoKJQISMQ4KJQoSLQYKJQISLQ4KIQoSKQYKIQICIQISMQoSKQYKLQIOLQoOJQYGLQIOKQIOMQoGKQYOLQYGKQIOLQoGJQYOJQIOKQYGJQIOKQoGKQIGLQIKLQ4KKQoGLQYKJQIGKQYKJQIGKQIKJQoGKQYKLQIGKQYKLQIOJQoKKQoOJQYKKQIOJQoKKQoOKQIOLQoKKQYOLQYKJQIOKQoKKQYKKQoKJQYOKQYKLQIOKQoKLQYOKQYKLQIOJQoGKQYKJQYGJQoGKQYKLQoGLQYGKQoGJQYKKQYGJQIKKQoGJQYKLQIKKQYGLQYKKQYGKQYGKQYKJQYOKQoKJQYOKQYKLQYOLQYOKQYKLQYOKQoKKQYKKQYOKQYOJQYKKQYKLQYKKQIKKQoKKQYKKQYKKQoKJQIKKQYKLQYKKQYKKQIKKQYKKQYKKQYKKQIKKQYKJQYGLQYGKQYKKQYKKQYGKQIKKQYGKQYOJQoKKQYOLQYKKQYOKQoKKQYKKQoKKQYKKQYKJQYKLQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKJQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKLQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKmIDpEAAAA0XRSTlMAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAiIyQlJycoKissLS4wMTQ1Njc4OTo7PDw+P0BCQ0RISUpLTE1OUFNUVVdYWFlaW15fYGFiY2ZnaGlqa2xtb3BxcnN0dnh5ent8fX5/gIGChIWIioyNjo+QkZOUlZaYmZqbnJ2eoKGio6WmqKmsra6vsLGztre4ubq7vL2+wMHDxMjJysvNzs/Q0dLU1tfY2dvc3t/g4eLj5ebn6Onq6+zt7u/w8vP09fb3+Pn6+/z9/vkVQXAAAAMaSURBVHhe5dXxV1N1GMfxz2ABbDgIAm5VDJOyVDIJLUMaVpBWUZUaGbmqoGpZRSiGiRWp6KoZ5AB0ZY50RImZQIlahKkMYXv/R90dBvET/rJfOr3Ouc8v99zPec59zvf56j+vYKlViSf7250X4Mr3O29Tgq08BdGB4DhcekEJ5YkQKFsgWZdtj9JpV+I8xPjLFqkrsEIqO8PHSpis36jWazcqjEsfJjkvRssVU37SdIOu4XCf5vEJPsnwJpnRNU9JmxhMk8l1gehIrq7hTFjzOD+Vf88629qKMJVNltInFeRexRQyJlNeqd1iGDlSzrIUIyXbyFfm3RYprcQRe7lqtWyGYbfc6dT0R2vmdOOkX3u55C1rP37ftiH+tDby4r/RBT0w8TyEkr+epB9XgPDmSYYWbrhCuFYaIyw3fDQAXTnSkh+ANofiHmWf9l+FY1I90FdQTetstO00o23novzVsJ7uB3/C5TkbjRwZ5JerwV4iRWq9HFbFMaK/d0TYqayRiQPuIxxS3Bu8JWU90/60tKi7vkhaznez0a/TbVOKj5CaOZh6fWG6/Lyv9B/ZLR1gw/S/fpbeVD3MCW1li6SvWDOn65tr99/uvWtBS0XDm4s1t+sOHpG0kpBKx/l77wOSnxLpcx6TXmXLTPQOKYOf9Q1dfr8/SJ2mFdCvl1Yl93DiHUZvXeLJbGSzYu5gVJ2slbSakOR8dxCq5adQ2oFLqsE9Ex3L4qQO0eOPeU5x56bypXp4onSEb5OkICX6lDat55TeoztNKQcJaakrz9KCb95oD69IKq+yKW4XPjknaS52V0TZqE2cTtXjcHSCRmUO88e+85hj3EP74i9p8pylw7lxgMDyyl6OV7ZejnjNMfatu87LxRbH0IS35gt2a4ZjmGpVBdKK3Wr6INk8jWWSGqbA55CKgjBRC6E9w78ydTg3ABS3AFV1QN0Y4Aa2pgEjWnQURj9L0ayK6R2ysEqxHUKzYnLvvyU+i9KM2JHJzE4vyZOyDcOwOsySajeLPc8sNvPJkFlyJd20wpqAzZeAfZ3oWybxd+P/3j+SG3uSBdf2VQAAAABJRU5ErkJggg==') no-repeat; background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgdmVyc2lvbj0iMS4xIgogICB3aWR0aD0iNjgxLjk2MjUyIgogICBoZWlnaHQ9IjE4Ny41IgogICBpZD0ic3ZnMiIKICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhOCI+PHJkZjpSREY+PGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPjxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PjxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz48L2NjOldvcms+PC9yZGY6UkRGPjwvbWV0YWRhdGE+PGRlZnMKICAgICBpZD0iZGVmczYiPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTgiPjxwYXRoCiAgICAgICAgIGQ9Ik0gMCwxNTAwIDAsMCBsIDU0NTUuNzQsMCAwLDE1MDAgTCAwLDE1MDAgeiIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgyMCIgLz48L2NsaXBQYXRoPjwvZGVmcz48ZwogICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMjUsMCwwLC0xLjI1LDAsMTg3LjUpIgogICAgIGlkPSJnMTAiPjxnCiAgICAgICB0cmFuc2Zvcm09InNjYWxlKDAuMSwwLjEpIgogICAgICAgaWQ9ImcxMiI+PGcKICAgICAgICAgaWQ9ImcxNCI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxOCkiCiAgICAgICAgICAgaWQ9ImcxNiI+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gMTU0NCw1OTkuNDM0IGMgMC45MiwtNDAuMzUyIDI1LjY4LC04MS42MDIgNzEuNTMsLTgxLjYwMiAyNy41MSwwIDQ3LjY4LDEyLjgzMiA2MS40NCwzNS43NTQgMTIuODMsMjIuOTMgMTIuODMsNTYuODUyIDEyLjgzLDgyLjUyNyBsIDAsMzI5LjE4NCAtNzEuNTIsMCAwLDEwNC41NDMgMjY2LjgzLDAgMCwtMTA0LjU0MyAtNzAuNiwwIDAsLTM0NC43NyBjIDAsLTU4LjY5MSAtMy42OCwtMTA0LjUzMSAtNDQuOTMsLTE1Mi4yMTggLTM2LjY4LC00Mi4xOCAtOTYuMjgsLTY2LjAyIC0xNTMuMTQsLTY2LjAyIC0xMTcuMzcsMCAtMjA3LjI0LDc3Ljk0MSAtMjAyLjY0LDE5Ny4xNDUgbCAxMzAuMiwwIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMjIiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDIzMDEuNCw2NjIuNjk1IGMgMCw4MC43MDMgLTY2Ljk0LDE0NS44MTMgLTE0Ny42MywxNDUuODEzIC04My40NCwwIC0xNDcuNjMsLTY4Ljc4MSAtMTQ3LjYzLC0xNTEuMzAxIDAsLTc5Ljc4NSA2Ni45NCwtMTQ1LjgwMSAxNDUuOCwtMTQ1LjgwMSA4NC4zNSwwIDE0OS40Niw2Ny44NTIgMTQ5LjQ2LDE1MS4yODkgeiBtIC0xLjgzLC0xODEuNTQ3IGMgLTM1Ljc3LC01NC4wOTcgLTkzLjUzLC03OC44NTkgLTE1Ny43MiwtNzguODU5IC0xNDAuMywwIC0yNTEuMjQsMTE2LjQ0OSAtMjUxLjI0LDI1NC45MTggMCwxNDIuMTI5IDExMy43LDI2MC40MSAyNTYuNzQsMjYwLjQxIDYzLjI3LDAgMTE4LjI5LC0yOS4zMzYgMTUyLjIyLC04Mi41MjMgbCAwLDY5LjY4NyAxNzUuMTQsMCAwLC0xMDQuNTI3IC02MS40NCwwIDAsLTI4MC41OTggNjEuNDQsMCAwLC0xMDQuNTI3IC0xNzUuMTQsMCAwLDY2LjAxOSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDI0IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSAyNjIyLjMzLDU1Ny4yNTggYyAzLjY3LC00NC4wMTYgMzMuMDEsLTczLjM0OCA3OC44NiwtNzMuMzQ4IDMzLjkzLDAgNjYuOTMsMjMuODI0IDY2LjkzLDYwLjUwNCAwLDQ4LjYwNiAtNDUuODQsNTYuODU2IC04My40NCw2Ni45NDEgLTg1LjI4LDIyLjAwNCAtMTc4LjgxLDQ4LjYwNiAtMTc4LjgxLDE1NS44NzkgMCw5My41MzYgNzguODYsMTQ3LjYzMyAxNjUuOTgsMTQ3LjYzMyA0NCwwIDgzLjQzLC05LjE3NiAxMTAuOTQsLTQ0LjAwOCBsIDAsMzMuOTIyIDgyLjUzLDAgMCwtMTMyLjk2NSAtMTA4LjIxLDAgYyAtMS44MywzNC44NTYgLTI4LjQyLDU3Ljc3NCAtNjMuMjYsNTcuNzc0IC0zMC4yNiwwIC02Mi4zNSwtMTcuNDIyIC02Mi4zNSwtNTEuMzQ4IDAsLTQ1Ljg0NyA0NC45MywtNTUuOTMgODAuNjksLTY0LjE4IDg4LjAyLC0yMC4xNzUgMTgyLjQ3LC00Ny42OTUgMTgyLjQ3LC0xNTcuNzM0IDAsLTk5LjAyNyAtODMuNDQsLTE1NC4wMzkgLTE3NS4xMywtMTU0LjAzOSAtNDkuNTMsMCAtOTQuNDYsMTUuNTgyIC0xMjYuNTUsNTMuMTggbCAwLC00MC4zNCAtODUuMjcsMCAwLDE0Mi4xMjkgMTE0LjYyLDAiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgaWQ9InBhdGgyNiIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiM4YTQxODI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIC8+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gMjk4OC4xOCw4MDAuMjU0IC02My4yNiwwIDAsMTA0LjUyNyAxNjUuMDUsMCAwLC03My4zNTUgYyAzMS4xOCw1MS4zNDcgNzguODYsODUuMjc3IDE0MS4yMSw4NS4yNzcgNjcuODUsMCAxMjQuNzEsLTQxLjI1OCAxNTIuMjEsLTEwMi42OTkgMjYuNiw2Mi4zNTEgOTIuNjIsMTAyLjY5OSAxNjAuNDcsMTAyLjY5OSA1My4xOSwwIDEwNS40NiwtMjIgMTQxLjIxLC02Mi4zNTEgMzguNTIsLTQ0LjkzOCAzOC41MiwtOTMuNTMyIDM4LjUyLC0xNDkuNDU3IGwgMCwtMTg1LjIzOSA2My4yNywwIDAsLTEwNC41MjcgLTIzOC40MiwwIDAsMTA0LjUyNyA2My4yOCwwIDAsMTU3LjcxNSBjIDAsMzIuMTAyIDAsNjAuNTI3IC0xNC42Nyw4OC45NTcgLTE4LjM0LDI2LjU4MiAtNDguNjEsNDAuMzQ0IC03OS43Nyw0MC4zNDQgLTMwLjI2LDAgLTYzLjI4LC0xMi44NDQgLTgyLjUzLC0zNi42NzIgLTIyLjkzLC0yOS4zNTUgLTIyLjkzLC01Ni44NjMgLTIyLjkzLC05Mi42MjkgbCAwLC0xNTcuNzE1IDYzLjI3LDAgMCwtMTA0LjUyNyAtMjM4LjQxLDAgMCwxMDQuNTI3IDYzLjI4LDAgMCwxNTAuMzgzIGMgMCwyOS4zNDggMCw2Ni4wMjMgLTE0LjY3LDkxLjY5OSAtMTUuNTksMjkuMzM2IC00Ny42OSw0NC45MzQgLTgwLjcsNDQuOTM0IC0zMS4xOCwwIC01Ny43NywtMTEuMDA4IC03Ny45NCwtMzUuNzc0IC0yNC43NywtMzAuMjUzIC0yNi42LC02Mi4zNDMgLTI2LjYsLTk5Ljk0MSBsIDAsLTE1MS4zMDEgNjMuMjcsMCAwLC0xMDQuNTI3IC0yMzguNCwwIDAsMTA0LjUyNyA2My4yNiwwIDAsMjgwLjU5OCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDI4IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSAzOTk4LjY2LDk1MS41NDcgLTExMS44NywwIDAsMTE4LjI5MyAxMTEuODcsMCAwLC0xMTguMjkzIHogbSAwLC00MzEuODkxIDYzLjI3LDAgMCwtMTA0LjUyNyAtMjM5LjMzLDAgMCwxMDQuNTI3IDY0LjE5LDAgMCwyODAuNTk4IC02My4yNywwIDAsMTA0LjUyNyAxNzUuMTQsMCAwLC0zODUuMTI1IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzAiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDQxNTkuMTIsODAwLjI1NCAtNjMuMjcsMCAwLDEwNC41MjcgMTc1LjE0LDAgMCwtNjkuNjg3IGMgMjkuMzUsNTQuMTAxIDg0LjM2LDgwLjY5OSAxNDQuODcsODAuNjk5IDUzLjE5LDAgMTA1LjQ1LC0yMi4wMTYgMTQxLjIyLC02MC41MjcgNDAuMzQsLTQ0LjkzNCA0MS4yNiwtODguMDMyIDQxLjI2LC0xNDMuOTU3IGwgMCwtMTkxLjY1MyA2My4yNywwIDAsLTEwNC41MjcgLTIzOC40LDAgMCwxMDQuNTI3IDYzLjI2LDAgMCwxNTguNjM3IGMgMCwzMC4yNjIgMCw2MS40MzQgLTE5LjI2LDg4LjAzNSAtMjAuMTcsMjYuNTgyIC01My4xOCwzOS40MTQgLTg2LjE5LDM5LjQxNCAtMzMuOTMsMCAtNjguNzcsLTEzLjc1IC04OC45NCwtNDEuMjUgLTIxLjA5LC0yNy41IC0yMS4wOSwtNjkuNjg3IC0yMS4wOSwtMTAyLjcwNyBsIDAsLTE0Mi4xMjkgNjMuMjYsMCAwLC0xMDQuNTI3IC0yMzguNCwwIDAsMTA0LjUyNyA2My4yNywwIDAsMjgwLjU5OCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDMyIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA1MDgyLjQ4LDcwMy45NjUgYyAtMTkuMjQsNzAuNjA1IC04MS42LDExNS41NDcgLTE1NC4wNCwxMTUuNTQ3IC02Ni4wNCwwIC0xMjkuMywtNTEuMzQ4IC0xNDMuMDUsLTExNS41NDcgbCAyOTcuMDksMCB6IG0gODUuMjcsLTE0NC44ODMgYyAtMzguNTEsLTkzLjUyMyAtMTI5LjI3LC0xNTYuNzkzIC0yMzEuMDUsLTE1Ni43OTMgLTE0My4wNywwIC0yNTcuNjgsMTExLjg3MSAtMjU3LjY4LDI1NS44MzYgMCwxNDQuODgzIDEwOS4xMiwyNjEuMzI4IDI1NC45MSwyNjEuMzI4IDY3Ljg3LDAgMTM1LjcyLC0zMC4yNTggMTgzLjM5LC03OC44NjMgNDguNjIsLTUxLjM0NCA2OC43OSwtMTEzLjY5NSA2OC43OSwtMTgzLjM4MyBsIC0zLjY3LC0zOS40MzQgLTM5Ni4xMywwIGMgMTQuNjcsLTY3Ljg2MyA3Ny4wMywtMTE3LjM2MyAxNDYuNzIsLTExNy4zNjMgNDguNTksMCA5MC43NiwxOC4zMjggMTE4LjI4LDU4LjY3MiBsIDExNi40NCwwIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzQiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDY5MC44OTUsODUwLjcwMyA5MC43NSwwIDIyLjU0MywzMS4wMzUgMCwyNDMuMTIyIC0xMzUuODI5LDAgMCwtMjQzLjE0MSAyMi41MzYsLTMxLjAxNiIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDM2IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA2MzIuMzk1LDc0Mi4yNTggMjguMDM5LDg2LjMwNCAtMjIuNTUxLDMxLjA0IC0yMzEuMjIzLDc1LjEyOCAtNDEuOTc2LC0xMjkuMTgzIDIzMS4yNTcsLTc1LjEzNyAzNi40NTQsMTEuODQ4IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzgiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDcxNy40NDksNjUzLjEwNSAtNzMuNDEsNTMuMzYgLTM2LjQ4OCwtMTEuODc1IC0xNDIuOTAzLC0xOTYuNjkyIDEwOS44ODMsLTc5LjgyOCAxNDIuOTE4LDE5Ni43MDMgMCwzOC4zMzIiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgaWQ9InBhdGg0MCIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiM4YTQxODI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIC8+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gODI4LjUyLDcwNi40NjUgLTczLjQyNiwtNTMuMzQgMC4wMTEsLTM4LjM1OSBMIDg5OC4wMDQsNDE4LjA3IDEwMDcuOSw0OTcuODk4IDg2NC45NzMsNjk0LjYwOSA4MjguNTIsNzA2LjQ2NSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDQyIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA4MTIuMDg2LDgyOC41ODYgMjguMDU1LC04Ni4zMiAzNi40ODQsLTExLjgzNiAyMzEuMjI1LDc1LjExNyAtNDEuOTcsMTI5LjE4MyAtMjMxLjIzOSwtNzUuMTQgLTIyLjU1NSwtMzEuMDA0IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoNDQiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDczNi4zMDEsMTMzNS44OCBjIC0zMjMuMDQ3LDAgLTU4NS44NzUsLTI2Mi43OCAtNTg1Ljg3NSwtNTg1Ljc4MiAwLC0zMjMuMTE4IDI2Mi44MjgsLTU4NS45NzcgNTg1Ljg3NSwtNTg1Ljk3NyAzMjMuMDE5LDAgNTg1LjgwOSwyNjIuODU5IDU4NS44MDksNTg1Ljk3NyAwLDMyMy4wMDIgLTI2Mi43OSw1ODUuNzgyIC01ODUuODA5LDU4NS43ODIgbCAwLDAgeiBtIDAsLTExOC42MSBjIDI1Ny45NzIsMCA0NjcuMTg5LC0yMDkuMTMgNDY3LjE4OSwtNDY3LjE3MiAwLC0yNTguMTI5IC0yMDkuMjE3LC00NjcuMzQ4IC00NjcuMTg5LC00NjcuMzQ4IC0yNTguMDc0LDAgLTQ2Ny4yNTQsMjA5LjIxOSAtNDY3LjI1NCw0NjcuMzQ4IDAsMjU4LjA0MiAyMDkuMTgsNDY3LjE3MiA0NjcuMjU0LDQ2Ny4xNzIiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgaWQ9InBhdGg0NiIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiM4YTQxODI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIC8+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gMTA5MS4xMyw2MTkuODgzIC0xNzUuNzcxLDU3LjEyMSAxMS42MjksMzUuODA4IDE3NS43NjIsLTU3LjEyMSAtMTEuNjIsLTM1LjgwOCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDQ4IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0iTSA4NjYuOTU3LDkwMi4wNzQgODM2LjUsOTI0LjE5OSA5NDUuMTIxLDEwNzMuNzMgOTc1LjU4NiwxMDUxLjYxIDg2Ni45NTcsOTAyLjA3NCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDUwIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0iTSA2MDcuNDY1LDkwMy40NDUgNDk4Ljg1NSwxMDUyLjk3IDUyOS4zMiwxMDc1LjEgNjM3LjkzLDkyNS41NjYgNjA3LjQ2NSw5MDMuNDQ1IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoNTIiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDM4MC42ODgsNjIyLjEyOSAtMTEuNjI2LDM1LjgwMSAxNzUuNzU4LDU3LjA5IDExLjYyMSwtMzUuODAxIC0xNzUuNzUzLC01Ny4wOSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDU0IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA3MTYuMjg5LDM3Ni41OSAzNy42NDA2LDAgMCwxODQuODE2IC0zNy42NDA2LDAgMCwtMTg0LjgxNiB6IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoNTYiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjwvZz48L2c+PC9nPjwvZz48L3N2Zz4=') no-repeat, none; -moz-background-size: 100%; -o-background-size: 100%; -webkit-background-size: 100%; background-size: 100%; display: block; float: left; width: 90px; height: 25px; } 10 | .jasmine_html-reporter .jasmine-banner .jasmine-version { margin-left: 14px; position: relative; top: 6px; } 11 | .jasmine_html-reporter #jasmine_content { position: fixed; right: 100%; } 12 | .jasmine_html-reporter .jasmine-version { color: #aaa; } 13 | .jasmine_html-reporter .jasmine-banner { margin-top: 14px; } 14 | .jasmine_html-reporter .jasmine-duration { color: #fff; float: right; line-height: 28px; padding-right: 9px; } 15 | .jasmine_html-reporter .jasmine-symbol-summary { overflow: hidden; *zoom: 1; margin: 14px 0; } 16 | .jasmine_html-reporter .jasmine-symbol-summary li { display: inline-block; height: 10px; width: 14px; font-size: 16px; } 17 | .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-passed { font-size: 14px; } 18 | .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-passed:before { color: #007069; content: "\02022"; } 19 | .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-failed { line-height: 9px; } 20 | .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-failed:before { color: #ca3a11; content: "\d7"; font-weight: bold; margin-left: -1px; } 21 | .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-disabled { font-size: 14px; } 22 | .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-disabled:before { color: #bababa; content: "\02022"; } 23 | .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-pending { line-height: 17px; } 24 | .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-pending:before { color: #ba9d37; content: "*"; } 25 | .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-empty { font-size: 14px; } 26 | .jasmine_html-reporter .jasmine-symbol-summary li.jasmine-empty:before { color: #ba9d37; content: "\02022"; } 27 | .jasmine_html-reporter .jasmine-run-options { float: right; margin-right: 5px; border: 1px solid #8a4182; color: #8a4182; position: relative; line-height: 20px; } 28 | .jasmine_html-reporter .jasmine-run-options .jasmine-trigger { cursor: pointer; padding: 8px 16px; } 29 | .jasmine_html-reporter .jasmine-run-options .jasmine-payload { position: absolute; display: none; right: -1px; border: 1px solid #8a4182; background-color: #eee; white-space: nowrap; padding: 4px 8px; } 30 | .jasmine_html-reporter .jasmine-run-options .jasmine-payload.jasmine-open { display: block; } 31 | .jasmine_html-reporter .jasmine-bar { line-height: 28px; font-size: 14px; display: block; color: #eee; } 32 | .jasmine_html-reporter .jasmine-bar.jasmine-failed { background-color: #ca3a11; } 33 | .jasmine_html-reporter .jasmine-bar.jasmine-passed { background-color: #007069; } 34 | .jasmine_html-reporter .jasmine-bar.jasmine-skipped { background-color: #bababa; } 35 | .jasmine_html-reporter .jasmine-bar.jasmine-errored { background-color: #ca3a11; } 36 | .jasmine_html-reporter .jasmine-bar.jasmine-menu { background-color: #fff; color: #aaa; } 37 | .jasmine_html-reporter .jasmine-bar.jasmine-menu a { color: #333; } 38 | .jasmine_html-reporter .jasmine-bar a { color: white; } 39 | .jasmine_html-reporter.jasmine-spec-list .jasmine-bar.jasmine-menu.jasmine-failure-list, .jasmine_html-reporter.jasmine-spec-list .jasmine-results .jasmine-failures { display: none; } 40 | .jasmine_html-reporter.jasmine-failure-list .jasmine-bar.jasmine-menu.jasmine-spec-list, .jasmine_html-reporter.jasmine-failure-list .jasmine-summary { display: none; } 41 | .jasmine_html-reporter .jasmine-results { margin-top: 14px; } 42 | .jasmine_html-reporter .jasmine-summary { margin-top: 14px; } 43 | .jasmine_html-reporter .jasmine-summary ul { list-style-type: none; margin-left: 14px; padding-top: 0; padding-left: 0; } 44 | .jasmine_html-reporter .jasmine-summary ul.jasmine-suite { margin-top: 7px; margin-bottom: 7px; } 45 | .jasmine_html-reporter .jasmine-summary li.jasmine-passed a { color: #007069; } 46 | .jasmine_html-reporter .jasmine-summary li.jasmine-failed a { color: #ca3a11; } 47 | .jasmine_html-reporter .jasmine-summary li.jasmine-empty a { color: #ba9d37; } 48 | .jasmine_html-reporter .jasmine-summary li.jasmine-pending a { color: #ba9d37; } 49 | .jasmine_html-reporter .jasmine-summary li.jasmine-disabled a { color: #bababa; } 50 | .jasmine_html-reporter .jasmine-description + .jasmine-suite { margin-top: 0; } 51 | .jasmine_html-reporter .jasmine-suite { margin-top: 14px; } 52 | .jasmine_html-reporter .jasmine-suite a { color: #333; } 53 | .jasmine_html-reporter .jasmine-failures .jasmine-spec-detail { margin-bottom: 28px; } 54 | .jasmine_html-reporter .jasmine-failures .jasmine-spec-detail .jasmine-description { background-color: #ca3a11; } 55 | .jasmine_html-reporter .jasmine-failures .jasmine-spec-detail .jasmine-description a { color: white; } 56 | .jasmine_html-reporter .jasmine-result-message { padding-top: 14px; color: #333; white-space: pre; } 57 | .jasmine_html-reporter .jasmine-result-message span.jasmine-result { display: block; } 58 | .jasmine_html-reporter .jasmine-stack-trace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666; border: 1px solid #ddd; background: white; white-space: pre; } 59 | --------------------------------------------------------------------------------