From 31fa7ab5876d9aba591c9da82e69c04ae495d6d7 Mon Sep 17 00:00:00 2001 From: Josh Johnson Date: Fri, 28 Sep 2012 11:34:44 -0500 Subject: [PATCH 01/13] progress so far --- easy/buzz_lightyear/php/buzz_lightyear.php | 9 ++++ easy/buzz_lightyear/ruby/buzz_lightyear.rb | 8 +++- .../fibonacci_series/php/fibonacci_series.php | 24 ++++++++++ easy/fibonacci_series/ruby/fibber.rb | 45 +++++++++++++++++++ .../fibonacci_series/ruby/fibonacci_series.rb | 18 ++++++-- 5 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 easy/fibonacci_series/ruby/fibber.rb diff --git a/easy/buzz_lightyear/php/buzz_lightyear.php b/easy/buzz_lightyear/php/buzz_lightyear.php index 7dfe56d..d38709e 100644 --- a/easy/buzz_lightyear/php/buzz_lightyear.php +++ b/easy/buzz_lightyear/php/buzz_lightyear.php @@ -6,7 +6,16 @@ * Give all possible values of `$x` where `$x == $x + 2;` will evaluate to `true` */ +$values = array(1e17, PHP_INT_MAX, true); +foreach ($values as $x) { + if ($x == $x + 2) { + echo '$x == $x + 2; evaluates to true when $x = ?' . "\n"; + echo "\n";var_export($x);echo "\n"; + var_dump($x == $x + 2); + echo "\n\n"; + } +} ?> \ No newline at end of file diff --git a/easy/buzz_lightyear/ruby/buzz_lightyear.rb b/easy/buzz_lightyear/ruby/buzz_lightyear.rb index a95b225..cabe10c 100644 --- a/easy/buzz_lightyear/ruby/buzz_lightyear.rb +++ b/easy/buzz_lightyear/ruby/buzz_lightyear.rb @@ -1,3 +1,9 @@ # Buzz Lightyear Code Challenge # -# Give all possible values of `x` where `x == x + 2` will evaluate to `true` \ No newline at end of file +# Give all possible values of `x` where `x == x + 2` will evaluate to `true` + +values = [ 1.0/0, -1.0/0, 1e17 ] + +values.each do |x| + puts "#{x} evaluates to true" if x == x + 2 +end \ No newline at end of file diff --git a/easy/fibonacci_series/php/fibonacci_series.php b/easy/fibonacci_series/php/fibonacci_series.php index efd32be..d9efe2e 100644 --- a/easy/fibonacci_series/php/fibonacci_series.php +++ b/easy/fibonacci_series/php/fibonacci_series.php @@ -36,7 +36,31 @@ $lines = file($argv[1]); +foreach ($lines as $n) { + $fibber = new Fibber(); + echo "Finding Fibonacci value at position {$n}: " . $fibber->fib_a($n) . "\n"; +} + +final class Fibber +{ + public function fib_a($n) + { + $n = (int)$n; + + if ($n < 2) { + return $n; + } else { + $vals = array(0,1); + $i = $n - 1; + while ($i <= $n) { + $vals[] = $vals[count($vals) - 1] + $vals[count($vals) - 2]; + } + + return end($vals); + } + } +} ?> \ No newline at end of file diff --git a/easy/fibonacci_series/ruby/fibber.rb b/easy/fibonacci_series/ruby/fibber.rb new file mode 100644 index 0000000..1067943 --- /dev/null +++ b/easy/fibonacci_series/ruby/fibber.rb @@ -0,0 +1,45 @@ +class Fibber + # recursive + def fib(n) + n = n.to_i + n < 2 ? n : fib(n-1) + fib(n-2) + end + + # == fib_iterative + # + # Although it is based directly on the definition of a Fibonacci number, + # the recursive Fibonacci algorithm is extremely expensive, requiring + # time O(2n). It also performs a huge amount of redundant work because + # it computes many Fibonnaci values from scratch many times. A simple + # linear-time iterative approach which calculates each value of fib + # successively can avoid these issues: + def fib_iterative(n) + n = n.to_i + curr = 0 + succ = 1 + + n.times do |i| + curr, succ = succ, curr + succ + end + + curr + end + + # == fib_array(n) + # + # The Array Method is an easier to read, linear computation that + # saves previous values to an array for lookup. This makes it much + # faster than recursion, though of course, uses more memory. + def fib_array(n) + n = n.to_i + return n if n < 2 + + vals = [0, 1] + (n-1).times do + vals.push(vals[-1] + vals[-2]) + end + + vals.last + end + +end \ No newline at end of file diff --git a/easy/fibonacci_series/ruby/fibonacci_series.rb b/easy/fibonacci_series/ruby/fibonacci_series.rb index 3f97a59..a609569 100644 --- a/easy/fibonacci_series/ruby/fibonacci_series.rb +++ b/easy/fibonacci_series/ruby/fibonacci_series.rb @@ -23,7 +23,19 @@ # -- Example: # # $ ruby fibonacci_series.rb list.txt -# -File.open(ARGV[0]).each_line do |line| +# +require './fibber.rb' + +File.open(ARGV[0]).each_line do |n| # begin coding here -end + fibber = Fibber.new + + puts "Finding Fibonacci value at position #{n.to_i}" + + puts "using Fibber#fib_array(n)" + puts fibber.fib_array(n) + + puts "using Fibber#fib_iterative(n)" + puts fibber.fib_iterative(n) + +end \ No newline at end of file From 6f0b8d9922fb91f2c52484e085c34cfcf2c30aa5 Mon Sep 17 00:00:00 2001 From: Josh Johnson Date: Fri, 28 Sep 2012 17:24:32 -0500 Subject: [PATCH 02/13] found a better way to do the fibonacci series with a hash so it's uber ruby --- easy/fibonacci_series/ruby/fibber.rb | 45 ------------------- .../fibonacci_series/ruby/fibonacci_series.rb | 34 ++++++-------- 2 files changed, 14 insertions(+), 65 deletions(-) delete mode 100644 easy/fibonacci_series/ruby/fibber.rb diff --git a/easy/fibonacci_series/ruby/fibber.rb b/easy/fibonacci_series/ruby/fibber.rb deleted file mode 100644 index 1067943..0000000 --- a/easy/fibonacci_series/ruby/fibber.rb +++ /dev/null @@ -1,45 +0,0 @@ -class Fibber - # recursive - def fib(n) - n = n.to_i - n < 2 ? n : fib(n-1) + fib(n-2) - end - - # == fib_iterative - # - # Although it is based directly on the definition of a Fibonacci number, - # the recursive Fibonacci algorithm is extremely expensive, requiring - # time O(2n). It also performs a huge amount of redundant work because - # it computes many Fibonnaci values from scratch many times. A simple - # linear-time iterative approach which calculates each value of fib - # successively can avoid these issues: - def fib_iterative(n) - n = n.to_i - curr = 0 - succ = 1 - - n.times do |i| - curr, succ = succ, curr + succ - end - - curr - end - - # == fib_array(n) - # - # The Array Method is an easier to read, linear computation that - # saves previous values to an array for lookup. This makes it much - # faster than recursion, though of course, uses more memory. - def fib_array(n) - n = n.to_i - return n if n < 2 - - vals = [0, 1] - (n-1).times do - vals.push(vals[-1] + vals[-2]) - end - - vals.last - end - -end \ No newline at end of file diff --git a/easy/fibonacci_series/ruby/fibonacci_series.rb b/easy/fibonacci_series/ruby/fibonacci_series.rb index a609569..589b9eb 100644 --- a/easy/fibonacci_series/ruby/fibonacci_series.rb +++ b/easy/fibonacci_series/ruby/fibonacci_series.rb @@ -1,41 +1,35 @@ # == Fibonacci Series Code Challenge # -# The Fibonacci series is defined as: -# -# F(0) = 0; F(1) = 1; F(n) = F(n-1) + F(n-2) when n > 1; -# +# The Fibonacci series is defined as: +# +# F(0) = 0; F(1) = 1; F(n) = F(n-1) + F(n-2) when n > 1; +# # Given a positive integer 'n', print out the F(n). -# +# # -- Example Input: -# +# # 5 # 12 -# -# +# +# # -- Example Output: -# +# # 5 # 144 # # # ARGV[0] should be the text file you pass in when you call this script -# +# # -- Example: -# +# # $ ruby fibonacci_series.rb list.txt # require './fibber.rb' File.open(ARGV[0]).each_line do |n| # begin coding here - fibber = Fibber.new - - puts "Finding Fibonacci value at position #{n.to_i}" - - puts "using Fibber#fib_array(n)" - puts fibber.fib_array(n) - puts "using Fibber#fib_iterative(n)" - puts fibber.fib_iterative(n) + fibonacci = Hash.new{ |h,k| h[k] = k < 2 ? k : h[k-1] + h[k-2] } + puts fibonacci[n.to_i] -end \ No newline at end of file +end From c4c5c2172fc53e46c91d66e91ab8c8e804ff53c7 Mon Sep 17 00:00:00 2001 From: Josh Johnson Date: Fri, 28 Sep 2012 17:38:45 -0500 Subject: [PATCH 03/13] add benchmark times --- easy/fibonacci_series/ruby/fibonacci_series.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/easy/fibonacci_series/ruby/fibonacci_series.rb b/easy/fibonacci_series/ruby/fibonacci_series.rb index 589b9eb..a093dae 100644 --- a/easy/fibonacci_series/ruby/fibonacci_series.rb +++ b/easy/fibonacci_series/ruby/fibonacci_series.rb @@ -24,12 +24,15 @@ # # $ ruby fibonacci_series.rb list.txt # -require './fibber.rb' + +start_time = Time.now File.open(ARGV[0]).each_line do |n| # begin coding here + # Hash memoization fibonacci = Hash.new{ |h,k| h[k] = k < 2 ? k : h[k-1] + h[k-2] } puts fibonacci[n.to_i] - end + +puts "\nCompleted in #{Time.now - start_time} ms" From c373898c0ab3ca7c82d099defe3912cbfc2ef4c6 Mon Sep 17 00:00:00 2001 From: Josh Johnson Date: Fri, 28 Sep 2012 17:49:14 -0500 Subject: [PATCH 04/13] finished ruby fizz buzz challenge --- easy/fizz_buzz/ruby/fizz_buzz.rb | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/easy/fizz_buzz/ruby/fizz_buzz.rb b/easy/fizz_buzz/ruby/fizz_buzz.rb index d787cdb..6aa8d40 100644 --- a/easy/fizz_buzz/ruby/fizz_buzz.rb +++ b/easy/fizz_buzz/ruby/fizz_buzz.rb @@ -1,8 +1,22 @@ #== Fizz Buzz Code Challenge -# -# Write a program that prints out the pattern generated by playing -# a variation of the Fizz Buzz game where we'll count from 1 to 100 -# replacing any number divisible by four with `Fizz`, any number -# divisible by six with `Buzz`, any number divisible by either four or six -# with `Fizz Buzz`, and any number divisible by the product of `4 x 6` with +# +# Write a program that prints out the pattern generated by playing +# a variation of the Fizz Buzz game where we'll count from 1 to 100 +# replacing any number divisible by four with `Fizz`, any number +# divisible by six with `Buzz`, any number divisible by either four or six +# with `Fizz Buzz`, and any number divisible by the product of `4 x 6` with # `Fizz Buzz BOOM`. + +start_time = Time.now + +(1..100).to_a.each do |n| + case true + when n % 24 == 0 then puts 'Fizz Buzz BOOM' + when n % 12 == 0 then puts 'Fizz Buzz' + when n % 6 == 0 then puts 'Buzz' + when n % 4 == 0 then puts 'Fizz' + else puts n + end +end + +puts "\nCompleted in #{Time.now - start_time} ms" From 4bba4c55d91f544ceb61796a1d44a8cd32f7700f Mon Sep 17 00:00:00 2001 From: Josh Johnson Date: Fri, 28 Sep 2012 18:56:08 -0500 Subject: [PATCH 05/13] finishes reverse words for js and ruby --- easy/reverse_words/js/reverse_words.js | 8 +++-- easy/reverse_words/js/styles.css | 45 +++++++++++++----------- easy/reverse_words/ruby/reverse_words.rb | 29 +++++++++------ 3 files changed, 49 insertions(+), 33 deletions(-) diff --git a/easy/reverse_words/js/reverse_words.js b/easy/reverse_words/js/reverse_words.js index ec0eee9..f2d2369 100644 --- a/easy/reverse_words/js/reverse_words.js +++ b/easy/reverse_words/js/reverse_words.js @@ -6,5 +6,9 @@ $(document).ready(function() { // Put code here... - -});​ \ No newline at end of file + var lines = $('#input pre').text().split('\n'); + $.each(lines, function(n, line) { + reversed = line.split(" ").reverse().join(" "); + $('#output').append('

' + reversed + '

'); + }); +}); diff --git a/easy/reverse_words/js/styles.css b/easy/reverse_words/js/styles.css index e0fd177..d823a5b 100644 --- a/easy/reverse_words/js/styles.css +++ b/easy/reverse_words/js/styles.css @@ -9,12 +9,12 @@ body { code { background: #efefef; padding: 2px 4px; - color: #c30; + color: #c30; } -p { - line-height: 1.75em; - margin-bottom: 1.2em; +p { + line-height: 1.75em; + margin-bottom: 1.2em; } strong { font-weight: bold; } @@ -28,39 +28,39 @@ strong { font-weight: bold; } #wrapper header { border-bottom: 1px solid #ddd; - padding: 0 0 0.8em; + padding: 0 0 0.8em; } -#wrapper header h1 { - font-size: 32px; - margin: 0.5em 0 1.2em; +#wrapper header h1 { + font-size: 32px; + margin: 0.5em 0 1.2em; } -#wrapper h1 small { - font-size: 0.65em; +#wrapper h1 small { + font-size: 0.65em; color: #ddd; -} +} -#wrapper h1 small .difficulty { +#wrapper h1 small .difficulty { color: #c30; text-align: right; -} +} -#wrapper header h3 { - font-size: 16px; - color: #3cc; - margin-bottom: 1.2em; +#wrapper header h3 { + font-size: 16px; + color: #3cc; + margin-bottom: 1.2em; } #wrapper .sample { background: #ededed; - color: #777; + color: #777; border: 1px solid #cdcdcd; margin: 20px 0; } -#wrapper .sample pre { - padding: 10px 10px 0; +#wrapper .sample pre { + padding: 10px 10px 0; } #wrapper #output { @@ -69,3 +69,8 @@ strong { font-weight: bold; } color: #3cc; background: #3c3c3c; } + +#wrapper #output p { + line-height: 1.2em; + margin-bottom: 0; +} diff --git a/easy/reverse_words/ruby/reverse_words.rb b/easy/reverse_words/ruby/reverse_words.rb index d29fb86..6846ba6 100644 --- a/easy/reverse_words/ruby/reverse_words.rb +++ b/easy/reverse_words/ruby/reverse_words.rb @@ -1,29 +1,36 @@ ############################################# # == Reverse Words Code Challenge # ############################################# -# -# Write a method to reverse the words of an input sentence. +# +# Write a method to reverse the words of an input sentence. # Reverse and print out each line's content as a new line to the console. -# -# +# +# # -- Example Input: -# +# # Hello World # August Ash -# -# +# +# # -- Example Output: -# +# # World Hello # Ash August # # # ARGV[0] should be the text file you pass in when you call this script -# +# # -- Example: -# +# # $ ruby reverse_words.rb list.txt -# +# + +start_time = Time.now + File.open(ARGV[0]).each_line do |line| # begin coding here + puts line.split(' ').reverse.join(' ') end + +puts "\nCompleted in #{Time.now - start_time} ms" + From 9d1174734584f9ee0840fec8a2a8cf7df952752d Mon Sep 17 00:00:00 2001 From: Josh Johnson Date: Fri, 28 Sep 2012 19:26:19 -0500 Subject: [PATCH 06/13] finishes reverse words for php --- easy/reverse_words/php/reverse_words.php | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/easy/reverse_words/php/reverse_words.php b/easy/reverse_words/php/reverse_words.php index f9f685c..caddb76 100644 --- a/easy/reverse_words/php/reverse_words.php +++ b/easy/reverse_words/php/reverse_words.php @@ -2,7 +2,7 @@ /** * Reverse Words Code Challenge * - * Write a method to reverse the words of an input sentence. + * Write a method to reverse the words of an input sentence. * Reverse and print out each line's content as a new line to the console. * * @@ -17,7 +17,7 @@ * World Hello * Ash August * - * To access the text file you can either hard code it in here + * To access the text file you can either hard code it in here * or make it a command line argument like so: * * $ php reverse_words.php list.txt @@ -30,7 +30,24 @@ * * $lines = file('list.txt'); */ + +$start_time = microtime(); + $lines = file($argv[1]); +foreach ($lines as $lineNumber => $line) { + if (!empty($line)) { + $str = preg_replace('/[\r\n]+/', '', $line); + $arr = explode(' ', $str); + $reversedArr = array_reverse($arr); + $reversedStr = join(' ', $reversedArr); + echo $reversedStr . "\n"; + } +} + +$end_time = microtime(); +$time = $end_time - $start_time; + +echo "\nCompleted in " . $time . " ms"; -?> \ No newline at end of file +?> From eca9893d12a5d6aa75bf9ec0ef34a74231f5b7c7 Mon Sep 17 00:00:00 2001 From: Josh Johnson Date: Fri, 28 Sep 2012 21:30:44 -0500 Subject: [PATCH 07/13] add time tracking and one-line the sucka --- easy/buzz_lightyear/ruby/buzz_lightyear.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/easy/buzz_lightyear/ruby/buzz_lightyear.rb b/easy/buzz_lightyear/ruby/buzz_lightyear.rb index cabe10c..3b3760a 100644 --- a/easy/buzz_lightyear/ruby/buzz_lightyear.rb +++ b/easy/buzz_lightyear/ruby/buzz_lightyear.rb @@ -2,8 +2,8 @@ # # Give all possible values of `x` where `x == x + 2` will evaluate to `true` -values = [ 1.0/0, -1.0/0, 1e17 ] +start_time = Time.now -values.each do |x| - puts "#{x} evaluates to true" if x == x + 2 -end \ No newline at end of file +[1.0/0, -1.0/0, 1e17].each { |x| p "#{x} evaluates to true" if x == x + 2 } + +puts "\nCompleted in #{Time.now - start_time} ms" From 188fe704de5f9fbff2579a52f4a4e9b59ddeafe2 Mon Sep 17 00:00:00 2001 From: Josh Johnson Date: Mon, 1 Oct 2012 10:14:23 -0500 Subject: [PATCH 08/13] finishes odd numbers challenge --- easy/odd_numbers/js/odd_numbers.js | 8 ++++++-- easy/odd_numbers/php/odd_numbers.php | 8 ++++++++ easy/odd_numbers/ruby/odd_numbers.rb | 8 +++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/easy/odd_numbers/js/odd_numbers.js b/easy/odd_numbers/js/odd_numbers.js index ec0eee9..19c4b72 100644 --- a/easy/odd_numbers/js/odd_numbers.js +++ b/easy/odd_numbers/js/odd_numbers.js @@ -6,5 +6,9 @@ $(document).ready(function() { // Put code here... - -});​ \ No newline at end of file + for (i=1; i<=99; i++) { + if (i % 2 != 0) { + $("#output").append('

' + i + '

'); + } + } +}); \ No newline at end of file diff --git a/easy/odd_numbers/php/odd_numbers.php b/easy/odd_numbers/php/odd_numbers.php index ee926ef..ba9c77d 100644 --- a/easy/odd_numbers/php/odd_numbers.php +++ b/easy/odd_numbers/php/odd_numbers.php @@ -7,7 +7,15 @@ * one number per line to the console (STDOUT) */ +$start = microtime(); +foreach(range(1, 99) as $number) { + echo $n = ($number % 2 != 0) ? "{$number}\n" : ''; +} +$end = microtime(); +$time = $end - $start; + +echo "\nCompleted in " . $time . " ms"; ?> \ No newline at end of file diff --git a/easy/odd_numbers/ruby/odd_numbers.rb b/easy/odd_numbers/ruby/odd_numbers.rb index cae7e37..fbe317b 100644 --- a/easy/odd_numbers/ruby/odd_numbers.rb +++ b/easy/odd_numbers/ruby/odd_numbers.rb @@ -1,4 +1,10 @@ # Odd Numbers Code Challenge # -# Write a program to print the odd numbers from 1 to 99, +# Write a program to print the odd numbers from 1 to 99, # one number per line to the console (STDOUT) + +start_time = Time.now + +(1..99).to_a.each { |n| p n unless n % 2 == 0 } + +puts "\nCompleted in #{Time.now - start_time} ms" From a935f6badc56a76063ea703c49e7212933e475a6 Mon Sep 17 00:00:00 2001 From: Josh Johnson Date: Mon, 1 Oct 2012 10:14:49 -0500 Subject: [PATCH 09/13] finishes fizz buzz challenge for php --- easy/fizz_buzz/php/fizz_buzz.php | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/easy/fizz_buzz/php/fizz_buzz.php b/easy/fizz_buzz/php/fizz_buzz.php index aaa1c27..0eb2331 100644 --- a/easy/fizz_buzz/php/fizz_buzz.php +++ b/easy/fizz_buzz/php/fizz_buzz.php @@ -6,11 +6,37 @@ * Write a program that prints out the pattern generated by playing * a variation of the Fizz Buzz game where we'll count from 1 to 100 * replacing any number divisible by four with `Fizz`, any number - * divisible by six with `Buzz`, any number divisible by either four or six + * divisible by six with `Buzz`, any number divisible by both four and six * with `Fizz Buzz`, and any number divisible by the product of `4 x 6` with * `Fizz Buzz BOOM`. */ +$start = microtime(); + +foreach(range(1, 100) as $n) { + switch (true) { + case($n % 24 == 0): + echo "Fizz Buzz BOOM\n"; + break; + case($n % 4 == 0 && $n % 6 == 0): + echo "Fizz Buzz\n"; + break; + case($n % 6 == 0): + echo "Buzz\n"; + break; + case($n % 4 == 0): + echo "Fizz\n"; + break; + default: + echo "$n\n"; + break; + } +} + +$end = microtime(); +$time = $end - $start; + +echo "\nCompleted in " . $time . " ms"; From 1bf1bc25ee746da6797452158805d33a973a1d3e Mon Sep 17 00:00:00 2001 From: Josh Johnson Date: Fri, 9 Nov 2012 10:51:24 -0600 Subject: [PATCH 10/13] finish javascript version of buzz lightyear --- easy/buzz_lightyear/js/buzz_lightyear.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/easy/buzz_lightyear/js/buzz_lightyear.js b/easy/buzz_lightyear/js/buzz_lightyear.js index 852dd46..eb456cc 100644 --- a/easy/buzz_lightyear/js/buzz_lightyear.js +++ b/easy/buzz_lightyear/js/buzz_lightyear.js @@ -6,5 +6,15 @@ $(document).ready(function() { // Put code here... + values = [1.0/0, -1.0/0, 1e17, true, false]; + $("#output").append("Checking these values: " + values); -}); \ No newline at end of file + $.each(values, function(key, x){ + if (x == x + 2) { + $('#output').append("

When x = " + x + " then x == x + 2 evaluates to true!

"); + } else { + $('#output').append("

When x = " + x + " then x == x + 2 evaluates to false!

"); + } + }); + +}); From 208d6c2b00e1fdd1193ea620fbb00c3a7c930dd0 Mon Sep 17 00:00:00 2001 From: Josh Johnson Date: Fri, 9 Nov 2012 10:51:49 -0600 Subject: [PATCH 11/13] finish ruby version of sum_of_integers --- .../sum_of_integers/ruby/sum_of_integers.rb | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/medium/sum_of_integers/ruby/sum_of_integers.rb b/medium/sum_of_integers/ruby/sum_of_integers.rb index 71dac97..8c5ebcc 100644 --- a/medium/sum_of_integers/ruby/sum_of_integers.rb +++ b/medium/sum_of_integers/ruby/sum_of_integers.rb @@ -1,31 +1,45 @@ # == Sum of Integers # -# Write a program to determine the largest sum of contiguous integers -# in a list. In other words, of all the possible contiguous subarrays +# Write a program to determine the largest sum of contiguous integers +# in a list. In other words, of all the possible contiguous subarrays # for a given array, find the one with the largest sum, and print that sum. -# -# -# Your program should accept a textfile as its first argument. This file -# will a comma separated list of integers, one set per line. e.g. -# +# +# +# Your program should accept a textfile as its first argument. This file +# will a comma separated list of integers, one set per line. e.g. +# # -- Example Input: -# +# # -10, 2, 3, -2, 0, 5, -15 # 2,3,-2,-1,10 -# -# +# +# # -- Example Output: -# +# # 8 # 12 # # # ARGV[0] should be the text file you pass in when you call this script -# +# # -- Example: -# +# # $ ruby sum_of_integers.rb list.txt -# +# +# +# -- ANSWER SHOULD BE: +# +# 23 +# 22 +# File.open(ARGV[0]).each_line do |line| # begin coding here -end \ No newline at end of file + max_so_far = 0 + max_ending_here = 0 + + line.split(',').each do |n| + max_ending_here = [0, max_ending_here + n.to_i].max + max_so_far = [max_ending_here, max_so_far].max + end + puts max_so_far +end From 077f0614bbc3b2cf0128f2528abb485fab4e0ffd Mon Sep 17 00:00:00 2001 From: Josh Johnson Date: Sat, 1 Dec 2012 23:29:39 -0600 Subject: [PATCH 12/13] initial code challenge for color contrast calculator --- hard/color_contrast_calculator/index.html | 269 ++++++++++++++++++++++ hard/color_contrast_calculator/styles.css | 97 ++++++++ 2 files changed, 366 insertions(+) create mode 100644 hard/color_contrast_calculator/index.html create mode 100644 hard/color_contrast_calculator/styles.css diff --git a/hard/color_contrast_calculator/index.html b/hard/color_contrast_calculator/index.html new file mode 100644 index 0000000..b140905 --- /dev/null +++ b/hard/color_contrast_calculator/index.html @@ -0,0 +1,269 @@ + + + + + + + + + + + + +
+
+

+ Contrast Calculator + // advanced +

+

Instructions:

+

+ A few years ago we were tasked with creating a color contrast calculator for a store front to help customers comply with Americans with Disabilities Act (ADA). Over the years we've found that: +

    +
  • maintaining the contrast calculator is cumbersome
  • +
  • code is repeated numerous times, so any changes to the code needs to be applied multiple times
  • +
  • the client is unable to make updates or changes without our assistance
  • +
  • Flash is not supported for some mobile devices
  • +
+

+

+ We can address three of these four issues by porting the Flash application to Javascript (we'll leave the discussion of the client updating the colors for another day). For this advanced challenge, we'll be utilizing: +

+

+ +

Assignment:

+

+ Your job will be to write an object-oriented Javascript class that will render an interactive contrast calculator and render that output to the #output element below. The color data is provided to you as JSON within the data-color-values attribute of the div#colors element. +

+ +

Example Contrast Calculator (Flash Version)

+

+ Color Contrast Calculator example +

+ +
+ +

Example Color Data:

+
+{
+  "background": {
+      "0": { "name": "10234 Misty Blue", "value": "8", "hex": "727A8F", "category": 2 }
+    , "1": { "name": "10563 Metalic Silver", "value": "93", "hex": "bbbbbb", "category": 2 }
+    , "2": { "name": "13 Rose", "value": "6", "hex": "895D5E", "category": 2 }
+    , "3": { "name": "142 Steel Blue", "value": "11", "hex": "788DA2", "category": 2 }
+    , "4": { "name": "144 Dark Blue Jean", "value": "4", "hex": "2E3547", "category": 2 }
+    , "5": { "name": "15 Scandinavian Sky", "value": "14", "hex": "9498A1", "category": 2 }
+    , "6": { "name": "15451 Bristol Blue", "value": "11", "hex": "29309B", "category": 2 }
+    , "7": { "name": "166 Shell Beige", "value": "26", "hex": "C2B6B6", "category": 2 }
+    , "8":  { "name": "167 Army Green", "value": "2", "hex": "40424F", "category": 2 }
+    , "9":  { "name": "173 Hazy Green", "value": "5", "hex": "3E433F", "category": 2 }
+    , "10": { "name": "199 Yellow Cream", "value": "20", "hex": "0B0819", "category": 2 }
+    , "11": { "name": "20044 Brown Mustard", "value": "4", "hex": "60513C", "category": 2 }
+    , "12": { "name": "20060 Moss", "value": "5", "hex": "867B5D", "category": 2 }
+    , "13": { "name": "20126 Twiggy Brown", "value": "9", "hex": "877D73", "category": 2 }
+    , "14": { "name": "20134 Nugat Brown", "value": "4", "hex": "413630", "category": 2 }
+    , "15": { "name": "20177 Taupe", "value": "4", "hex": "5A4D47", "category": 2 }
+    , "16": { "name": "207 SW-Pine", "value": "6", "hex": "626753", "category": 2 }
+    , "17": { "name": "23003 Dusty Brown", "value": "17", "hex": "B3A797", "category": 2 }
+    , "18": { "name": "23013 Smokey Brown", "value": "10", "hex": "81674C", "category": 2 }
+    , "19": { "name": "24030 Earth Tan", "value": "8", "hex": "866A52", "category": 2 }
+    , "20": { "name": "24034 Stone Beige", "value": "20", "hex": "B9A992", "category": 2 }
+    , "21": { "name": "24714 Oakwood Brown", "value": "2", "hex": "63432C", "category": 2 }
+    , "22": { "name": "24735 Maroon Brown", "value": "1", "hex": "573C33", "category": 2 }
+    , "23": { "name": "24933 Cream", "value": "36", "hex": "D5BF90", "category": 2 }
+    , "24": { "name": "24937 Duranodic Brown", "value": "4", "hex": "332E2A", "category": 2 }
+    , "27": { "name": "252 Muddy Clay", "value": "4", "hex": "877D73", "category": 2 }
+    , "28": { "name": "258 Saddle Brown", "value": "2", "hex": "815634", "category": 2 }
+    , "29": { "name": "278 Light Tangerine", "value": "17", "hex": "D08242", "category": 2 }
+    , "30": { "name": "28363 Navy", "value": "7", "hex": "40424F", "category": 2 }
+    , "33": { "name": "285 Dusty Blue", "value": "1", "hex": "4A5362", "category": 2 }
+    , "34": { "name": "288 SW Ecru", "value": "29", "hex": "D0C3A1", "category": 2 }
+    , "38": { "name": "30026 Titanium Grey", "value": "19", "hex": "93979A", "category": 2 }
+    , "39": { "name": "3007 Neutral Grey", "value": "10", "hex": "736F6E", "category": 2 }
+    , "40": { "name": "30096 Gunmetal Grey", "value": "9", "hex": "595961", "category": 2 }
+    , "53": { "name": "32341 Dark Grey", "value": "1", "hex": "815634", "category": 2 }
+    , "55": { "name": "33127 Angora Grey", "value": "6", "hex": "626A6C", "category": 2 }
+    , "66": { "name": "40230 Dusty Olive", "value": "4", "hex": "515443", "category": 2 }
+    , "67": { "name": "407 Chinese Red", "value": "5", "hex": "A23016", "category": 2 }
+    , "68": { "name": "420 Straw", "value": "23", "hex": "BEB491", "category": 2 }
+    , "69": { "name": "440 Sunrise", "value": "24", "hex": "E2BC6B", "category": 2 }
+    , "70": { "name": "446 Steam", "value": "25", "hex": "BDCDDA", "category": 2 }
+    , "71": { "name": "44930 Retro Green", "value": "5", "hex": "6B6E3F", "category": 2 }
+    , "72": { "name": "45183 Dark Green", "value": "7", "hex": "1B331C", "category": 2 }
+    , "75": { "name": "50043 Aged Plum", "value": "4", "hex": "3C2C2D", "category": 2 }
+    , "76": { "name": "50075 Dusty Rose", "value": "5", "hex": "827273", "category": 2 }
+    , "77": { "name": "50951 Eggplant", "value": "4", "hex": "302341", "category": 2 }
+    , "78": { "name": "51 Medium Mahogany", "value": "4", "hex": "392E2A", "category": 2 }
+    , "79": { "name": "51051 Burgundy", "value": "4", "hex": "371A1E", "category": 2 }
+    , "80": { "name": "60972 Orange", "value": "16", "hex": "D26D35", "category": 2 }
+    , "81": { "name": "62 Baja Wood", "value": "20", "hex": "B4ABA6", "category": 2 }
+    , "82": { "name": "6341 Red Cent", "value": "8", "hex": "96543E", "category": 2 }
+    , "83": { "name": "70002 Carnival Red", "value": "2", "hex": "B71E20", "category": 2 }
+    , "84": { "name": "70253 Purple Dusk", "value": "4", "hex": "675C60", "category": 2 }
+    , "85": { "name": "71204 Deep Orchid", "value": "4", "hex": "382940", "category": 2 }
+    , "86": { "name": "80231 Apricot", "value": "13", "hex": "B07E3F", "category": 2 }
+    , "87": { "name": "82483 Yellow", "value": "53", "hex": "FFB900", "category": 2 }
+    , "88": { "name": "8991 Clay", "value": "7", "hex": "855950", "category": 2 }
+    , "89": { "name": "9013 Putnam Ivory", "value": "24", "hex": "d0bfa1", "category": 2 }
+    , "90": { "name": "91134 Alpine White", "value": "38", "hex": "ffffff", "category": 2 }
+    , "91": { "name": "91134 White", "value": "76", "hex": "ffffff", "category": 2 }
+    , "92": { "name": "91272 Light Beige", "value": "27", "hex": "CDC7BB", "category": 2 }
+    , "93": { "name": "93352 Bone White", "value": "30", "hex": "DCCBBB", "category": 2 }
+    , "94": { "name": "9414 Black", "value": "8", "hex": "000000", "category": 2 }
+    , "95": { "name": "BR-32 Brown", "value": "2", "hex": "67523F", "category": 2 }
+  }
+  , "foreground": {
+        "25": { "name": "24998 Yellow", "value": "53", "hex": "ffb900", "category": 1 }
+      , "26": { "name": "25001 Red", "value": "9", "hex": "fe0000", "category": 1 }
+      , "31": { "name": "28364 Silver Grey", "value": "59", "hex": "666054", "category": 1 }
+      , "32": { "name": "28383 Burgundy", "value": "6", "hex": "4B1201", "category": 1 }
+      , "35": { "name": "29931 Silver", "value": "85", "hex": "858585", "category": 1 }
+      , "36": { "name": "29932 Gold", "value": "77", "hex": "95671c", "category": 1 }
+      , "37": { "name": "29933 Teal", "value": "11", "hex": "1f6678", "category": 1 }
+      , "41": { "name": "311-214 Ash", "value": "74", "hex": "f0e8e5", "category": 1 }
+      , "42": { "name": "311-302 China Blue", "value": "15", "hex": "585c68", "category": 1 }
+      , "43": { "name": "311-305 Light Grey", "value": "68", "hex": "dadada", "category": 1 }
+      , "44": { "name": "311-306 Pearl Grey", "value": "49", "hex": "acaead", "category": 1 }
+      , "45": { "name": "311-307 Charcoal Grey", "value": "9", "hex": "454138", "category": 1 }
+      , "46": { "name": "311-398 Graphite", "value": "24", "hex": "636363", "category": 1 }
+      , "47": { "name": "311-801 Antique Ivory", "value": "70", "hex": "fbefd9", "category": 1 }
+      , "48": { "name": "311-903 Black Forrest Green", "value": "12", "hex": "3d4d4c", "category": 1 }
+      , "49": { "name": "31631 Brown", "value": "2", "hex": "4F392B", "category": 1 }
+      , "50": { "name": "31753 Salmon", "value": "54", "hex": "e8c4c8", "category": 1 }
+      , "51": { "name": "31898 Seafoam", "value": "39", "hex": "93c1bf", "category": 1 }
+      , "52": { "name": "32291 Rust", "value": "11", "hex": "8e4731", "category": 1 }
+      , "54": { "name": "32726 Tan", "value": "24", "hex": "958979", "category": 1 }
+      , "56": { "name": "37033 Cream", "value": "81", "hex": "FFFBF0", "category": 1 }
+      , "57": { "name": "37037 Black", "value": "8", "hex": "000000", "category": 1 }
+      , "58": { "name": "37042 White", "value": "76", "hex": "ffffff", "category": 1 }
+      , "59": { "name": "37047 Taupe", "value": "19", "hex": "847D6D", "category": 1 }
+      , "60": { "name": "37048 Azure Blue", "value": "8", "hex": "095285", "category": 1 }
+      , "61": { "name": "37050 Candlewick", "value": "46", "hex": "bfb6b1", "category": 1 }
+      , "62": { "name": "37058 Chocolate Brown", "value": "6", "hex": "342e22", "category": 1 }
+      , "63": { "name": "37060 Pine Green", "value": "10", "hex": "225d57", "category": 1 }
+      , "64": { "name": "37065 Slate", "value": "11", "hex": "484445", "category": 1 }
+      , "65": { "name": "37070 Almond", "value": "54", "hex": "ede2c4", "category": 1 }
+      , "73": { "name": "45960 Grass", "value": "32", "hex": "8ab798", "category": 1 }
+      , "74": { "name": "45964 Maui Blue", "value": "31", "hex": "81a5df", "category": 1 }
+  }
+}
+            
+ +
+ +
+ + + +

My Color Contrast Calculator

+
+
+ + diff --git a/hard/color_contrast_calculator/styles.css b/hard/color_contrast_calculator/styles.css new file mode 100644 index 0000000..1e519cc --- /dev/null +++ b/hard/color_contrast_calculator/styles.css @@ -0,0 +1,97 @@ +body { + background: #eee; + font-family: Menlo, "Courier New", monospace; + font-size: 13px; + line-height: 17px; + color: #4d4d4d; +} + +code { + background: #efefef; + padding: 2px 4px; + color: #c30; +} + +ul, ol { + padding: 0 0 0 2em; +} + +ul li { + list-style: disc; +} + +li { + line-height: 1.2em; + margin-bottom: 1.25em; +} + +p, li { + line-height: 1.75em; + margin-bottom: 1.2em; +} + +a, a:hover, a:active, a:visited { + color: #3cc; +} + +blockquote { + font-style: italic; + border-left: 10px solid #ededed; + padding-left: 2em; + margin: 20px 0; +} + + +strong { font-weight: bold; } + +#wrapper { + background: #fff; + margin: 30px auto; + width: 90%; + padding: 2.5%; +} + +#wrapper header { + border-bottom: 1px solid #ddd; + padding: 0 0 0.8em; +} + +#wrapper header h1 { + font-size: 32px; + margin: 0.5em 0 1.2em; +} +#wrapper h1 small { + font-size: 0.65em; + color: #ddd; +} + +#wrapper h1 small .difficulty { + color: #c30; + text-align: right; +} + + +#wrapper header h3 { + font-size: 16px; + color: #3cc; + margin-bottom: 1.2em; +} + +#wrapper .sample { + background: #ededed; + color: #777; + border: 1px solid #cdcdcd; + margin: 20px 0; +} + +#wrapper .sample pre { + padding: 10px 10px 0; +} + +#wrapper #output { + margin: 20px 0; + padding: 1em; + color: #3cc; +// background: #3c3c3c; +} +​ From 3a3550ca80a47ebc4f7b03a741b3198da25812cf Mon Sep 17 00:00:00 2001 From: Josh Johnson Date: Sat, 1 Dec 2012 23:30:22 -0600 Subject: [PATCH 13/13] first stab at RaphaelJS port of the calculator --- hard/color_contrast_calculator/calculator.js | 553 +++++++++++++++++++ 1 file changed, 553 insertions(+) create mode 100644 hard/color_contrast_calculator/calculator.js diff --git a/hard/color_contrast_calculator/calculator.js b/hard/color_contrast_calculator/calculator.js new file mode 100644 index 0000000..824590d --- /dev/null +++ b/hard/color_contrast_calculator/calculator.js @@ -0,0 +1,553 @@ +/*jslint plusplus: true, todo: true, white: true */ +/*global jQuery, $, Raphael */ + +/** + * jQuery version 1.8.2 + * + * DOM READY! + */ +$(document).ready(function(){ + // Put code here... + var colorsData = $("#colors").attr('data-color-values'); + var colors = $.parseJSON(colorsData); + + // console.log(colors); + + new ColorContrastCalculator({ + data: colors, + fgGridHeaderText: "Raised Text Color", + bgGridHeaderText: "Face Material", + fontFace: "TuffyRegular, Helvetica, sans-serif", + textColor: '#363636' + }); + +}); + +/** + * ColorContrastCalculator + * + * draws an interactive grid of colors with a preview area + * to help determine what foreground/background color combination + * offers the best contrast and will be compliant with the + * Americans with Disabilities Act (ADA) requirement of 70% + * contrast value. + */ +function ColorContrastCalculator(config) { + // make sure our class is called with our new arguments + if (!(this instanceof arguments.callee)) { + return new arguments.callee(arguments); + } + + // keep track of the desired scope + var self = this; + + /** + * initialize the Raphael drawing space + * and parses the data into its major components + * (i.e., color swatch grids, labels, preview) + */ + self.init = function() { + // the data of course + self.data = config.data || []; + + /** + * Raphael canvas options + */ + // element to render the Raphael canvas to + self.domID = config.renderTo || 'output'; + + // specify a definite width for the Raphael canvas; + // otherwise defaults to the width of the containing element (domID) + self.width = config.width || $("#" + self.domID).width(); + + // specify the definite height for the Raphael canvas + self.height = config.height || 540; + + // The actual Raphael canvas object + self.paper = Raphael(self.domID, self.width, self.height); + + // the width of the space between columns (global value) + self.gutter = config.gutter || 20; + + /** + * Swatch/Tile options + */ + + // width & height of the swatches/tiles + self.tileWidth = config.tileWidth || 36; + self.tileHeight = config.tileHeight || 36; + + // number color swatches/tiles per row + self.tilesPerRow = config.tilesPerRow || 10; + + // the width of the space/gutter between swatches/tiles + self.tileGutter = config.tileGutter || self.gutter * 0.5; + + // the height of the space/gutter between foreground and background grids + self.gridGutter = config.gridGutter || self.gutter * 2; + + self.fgGridHeaderText = config.fgGridHeaderText || 'Foreground Color'; + self.bgGridHeaderText = config.bgGridHeaderText || 'Background Color'; + + + /** + * Font/Text options + */ + self.fontFace = config.fontFace || "'Trade Gothic', 'Helvetice Nueue', 'Helvetica', 'Arial', sans-serif"; + self.headerFontSize = config.headerFontSize || 24; + self.gridHeaderFontSize = config.gridHeaderFontSize || self.headerFontSize; + self.sectionHeaderFontSize = config.sectionHeaderFontSize || self.headerFontSize * 0.833333; + self.textFontSize = config.textFontSize || self.headerFontSize * 0.583333; + self.textColor = config.textColor || "#222"; + + self.fontAttrs = { + 'fill': self.textColor, + 'stroke': 'transparent', + 'font-family': self.fontFace, + 'text-anchor': 'start' + }; + + /** + * Preview/Chosen color box options + */ + self.boxWidth = config.boxWidth || (self.tileWidth + self.tileGutter) * 6; + self.boxHeight = config.boxHeight || self.boxWidth / 2; + + /** + * ADA guidelines require that copy characters contrast + * with their background by at least 70%. + * + * @see http://www.access-board.gov/adaag/html/adaag.htm + */ + self.adaMinContrastValue = config.adaMinContrastValue || 70; + + + /** + * complex paths + */ + self.uncheckedBox = "M26,27.5H6c-0.829,0-1.5-0.672-1.5-1.5V6c0-0.829,0.671-1.5,1.5-1.5h20c0.828,0,1.5,0.671,1.5,1.5v20C27.5,26.828,26.828,27.5,26,27.5zM7.5,24.5h17v-17h-17V24.5z"; + + self.checkedBox = "M29.548,3.043c-1.081-0.859-2.651-0.679-3.513,0.401L16,16.066l-3.508-4.414c-0.859-1.081-2.431-1.26-3.513-0.401c-1.081,0.859-1.261,2.432-0.401,3.513l5.465,6.875c0.474,0.598,1.195,0.944,1.957,0.944c0.762,0,1.482-0.349,1.957-0.944L29.949,6.556C30.809,5.475,30.629,3.902,29.548,3.043zM24.5,24.5h-17v-17h12.756l2.385-3H6C5.171,4.5,4.5,5.171,4.5,6v20c0,0.828,0.671,1.5,1.5,1.5h20c0.828,0,1.5-0.672,1.5-1.5V12.851l-3,3.773V24.5z"; + + /** + * business time! organize the data and draw everything + */ + self.parseData(); + self.draw(); + }; + + /** + * utility function to separate out the foreground and background + * colors into their own arrays + * + * TODO: what if the foreground and background colors are an array? + */ + self.parseData = function() { + self.fgColors = []; + self.bgColors = []; + + // convert the foreground colors into an array of objects + $.each(self.data.foreground, function(i, color){ + self.fgColors.push(color); + }); + + // convert the background colors into an array of objects + $.each(self.data.background, function(i, color){ + self.bgColors.push(color); + }); + + // calculate the number of rows + self.calculateRowsNeeded(); + + // calculate the total height of all grids, headers, etc. + // so the canvas can be resized to fit + self.calculateTotalHeight(); + }; + + /** + * calculate how many rows are needed for each grid (background & foreground) + * by dividing their quantity by the self.tilesPerRow configuration value + */ + self.calculateRowsNeeded = function() { + self.fgRows = Math.ceil(self.fgColors.length / self.tilesPerRow); + self.bgRows = Math.ceil(self.bgColors.length / self.tilesPerRow); + }; + + /** + * re-calculates the height needed for the canvas to be rendered fully + * by accounting for grid headers + margins + grid rows and margins + */ + self.calculateTotalHeight = function() { + var bgGridHeight, fgGridHeight, gridHeaderHeightWithMargin; + + self.gridHeaderMargin = (self.gridGutter / 2); + + gridHeaderHeightWithMargin = self.gridHeaderFontSize + self.gridHeaderMargin; + bgGridHeight = (self.tileHeight + self.tileGutter) * self.bgRows; + fgGridHeight = (self.tileHeight + self.tileGutter) * self.fgRows; + + self.fgGridHeight = gridHeaderHeightWithMargin + fgGridHeight; + self.bgGridHeight = gridHeaderHeightWithMargin + bgGridHeight; + self.gridWidth = ((self.tileWidth + self.tileGutter) * self.tilesPerRow) + self.gridGutter; + + // set the new height of the canvas paper + self.height = self.fgGridHeight + self.gridGutter + self.bgGridHeight; + + // resize the Raphael canvas to it's new dimensions + self.paper.setSize(self.width, self.height); + }; + + /** + * utilty function responsible for drawing the grid of colors + * for foreground and background colors, chosen color values, + * and the preview area + */ + self.draw = function() { + self.drawSections(self.fgColors, self.drawForegroundColorGrid); + self.drawSections(self.bgColors, self.drawBackgroundColorGrid); + self.drawPreview(); + }; + + /** + * == drawSections + * + * pass the data onto the appropriate drawing methods + */ + self.drawSections = function(theArray, drawingCallback) { + drawingCallback(theArray); + }; + + /** + * == drawForegroundColorGrid + * + * draws the foreground header and grid of swatch colors + */ + self.drawForegroundColorGrid = function(colors) { + var gridOffset, gridHeaderYOffset, gridHeaderXOffset, gridWidth; + + gridHeaderXOffset = 0; + gridHeaderYOffset = self.gridHeaderMargin; + gridOffset = self.gridHeaderFontSize + gridHeaderYOffset; + + self.drawGridHeader(self.fgGridHeaderText, gridHeaderXOffset, gridHeaderYOffset); + self.drawColorGrid(colors, gridOffset); + self.drawChosenForegroundValues('Typeface Color:', self.gridWidth, gridOffset); + }; + + /** + * == drawBackgroundColorGrid + * + * draws the background header and grid of swatch colors + */ + self.drawBackgroundColorGrid = function(colors) { + var gridOffset, gridHeaderYOffset, gridHeaderXOffset; + + gridHeaderXOffset = 0; + gridHeaderYOffset = self.fgGridHeight + self.gridGutter; + gridOffset = gridHeaderYOffset + self.gridHeaderMargin; + + self.drawGridHeader(self.bgGridHeaderText, gridHeaderXOffset, gridHeaderYOffset); + self.drawColorGrid(colors, gridOffset); + self.drawChosenBackgroundValues('Face Material:', self.gridWidth, gridOffset); + }; + + /** + * == drawGridHeader + * + * draws the grid's header + */ + self.drawGridHeader = function(text, xOffset, yOffset) { + var label = self.paper.text(xOffset + self.tileGutter, yOffset, text); + + // foreground fill for the score # + label.attr(self.fontAttrs).attr({'font-size': self.gridHeaderFontSize}); + }; + + /** + * == drawChosenForegroundValues + * + * draws placeholder text strings for the chosen foreground color's name + * and LRV values which can be later update through the .attr() methods + * + * @param string titleText + * @param integer xOffset + * @param integer yOffset + * @return Element + */ + self.drawChosenForegroundValues = function(titleText, xOffset, yOffset){ + // draw the box + self.drawChosenColorValues(titleText, xOffset, yOffset); + + // draw the text placeholders + self.fgColorNameText = self.paper.text(xOffset, yOffset + 50, '').attr(self.fontAttrs); + self.fgColorLRVText = self.paper.text(xOffset, yOffset + 110, '').attr(self.fontAttrs); + + // update the font size + self.fgColorNameText.attr({'font-size': self.textFontSize }); + self.fgColorLRVText.attr({'font-size': self.textFontSize * 1.1 }); + }; + + /** + * == drawChosenBackgroundValues + * + * draws placeholder text strings for the chosen background color's name + * and LRV values which can be later update through the .attr() methods + * + * @param string titleText + * @param integer xOffset + * @param integer yOffset + * @return Element + */ + self.drawChosenBackgroundValues = function(titleText, xOffset, yOffset){ + // draw the box + self.drawChosenColorValues(titleText, xOffset, yOffset); + + // draw the text placeholders + self.bgColorNameText = self.paper.text(xOffset, yOffset + 50, '').attr(self.fontAttrs); + self.bgColorLRVText = self.paper.text(xOffset, yOffset + 110, '').attr(self.fontAttrs); + + // update the font size + self.bgColorNameText.attr({'font-size': self.textFontSize }); + self.bgColorLRVText.attr({'font-size': self.textFontSize * 1.1 }); + }; + + + /** + * == drawChosenColorValues + * + * draws the containing box and titles for a chosen color's name and LRV value + * + * @param string titleText + * @param integer xOffset + * @param integer yOffset + * @return Element + */ + self.drawChosenColorValues = function(titleText, xOffset, yOffset) { + var box, boxTitle, boxLrvTitle; + + // draw the containing box + box = self.paper.rect(xOffset - (self.gridGutter / 2), yOffset, self.boxWidth, self.boxHeight); + box.attr({ fill: '#f5f5f5', stroke: 'transparent' }); + box.glow({ width: 5, opacity: 0.3, color: "#ddd" }); + + // draw the titleText and LRV Value text strings + boxTitle = self.paper.text(xOffset, yOffset + 30, titleText).attr(self.fontAttrs); + boxLrvTitle = self.paper.text(xOffset, yOffset + 90, 'LRV Value:').attr(self.fontAttrs); + + boxTitle.attr({ 'font-size': self.textFontSize * 1.1 }); + boxLrvTitle.attr({ 'font-size': self.textFontSize * 1.1 }); + }; + + + /** + * == drawPreview + */ + self.drawPreview = function() { + var xOffset, yOffset, boxWidth, boxHeight, boxTitle; + + xOffset = self.gridWidth + self.boxWidth + (self.gridGutter * 2); + yOffset = self.gridHeaderMargin; + boxWidth = self.boxWidth + (self.tileHeight * 2); + boxHeight = boxWidth / 2; + + boxTitle = self.paper.text(xOffset, yOffset, 'Contrast Value:').attr(self.fontAttrs); + boxTitle.attr({'font-size': self.gridHeaderFontSize}); + + // draw the containing box + self.previewBox = self.paper.rect(xOffset, yOffset + self.gridHeaderFontSize, boxWidth, boxHeight); + self.previewBox.attr({ fill: '#f5f5f5', stroke: 'transparent' }); + self.previewBox.glow({ width: 5, opacity: 0.3, color: "#ddd" }); + + self.previewText = self.paper.text(xOffset + self.gridHeaderMargin + 60, yOffset + 110, '519'); + self.previewText.attr(self.fontAttrs); + self.previewText.attr({ 'font-size': self.gridHeaderFontSize * 5, 'font-weight': 'bold' }); + + self.contrastValueText = self.paper.text(xOffset + 180, yOffset, '').attr(self.fontAttrs); + self.contrastValueText.attr({'font-size': self.gridHeaderFontSize }); + + // move & stylize the icon indicator + self.contrastValueIcon = self.paper.path(self.uncheckedBox); + self.contrastValueIcon.translate(xOffset + 320, yOffset - 16); + self.contrastValueIcon.attr({ 'stroke': 'transparent', 'fill': "#ddd" }); + }; + + /** + * == drawColorGrid + * + * utility function responsible for solely drawing the grid by calculating + * the x and y offsets and passing that into the self.drawColorSwatch function + * + * @param array colors # array of javascript objects + * @param integer gridOffset # y-offset of where to begin drawing the grid + */ + self.drawColorGrid = function(colors, gridOffset) { + var xOffset, yOffset, rows; + + // split the array of colors into smaller arrays + // so we can draw rows of swatches + rows = self.chunk(colors, self.tilesPerRow); + + $.each(rows, function(i, row){ + $.each(row, function(j, color){ + xOffset = j * self.tileWidth + (j * self.tileGutter); + yOffset = i * self.tileHeight + (i * self.tileGutter) + gridOffset; + + self.drawColorSwatch(color, xOffset + self.tileGutter, yOffset); + }); + }); + }; + + /** + * == drawColorSwatch + * + * draws the actual color swatch at the given x and y offsets + * + * @param object color # Example: { "name": "Red", "hex": "cc3300", "value": 3 } + * @param integer xOffset + * @param integer yOffset + * @return Element + */ + self.drawColorSwatch = function(color, xOffset, yOffset) { + var swatch; + + // regular rectangle + swatch = self.paper.rect(xOffset, yOffset, self.tileWidth, self.tileHeight); + + // specify the swatch's fill, stroke, and opacity attributes + swatch.attr({ + "stroke": 'transparent', + "fill": "#" + color.hex + }); + + // add a slight drop shadow/glow effect instead of a stroke + swatch.glow({ width: 5, opacity: 0.3, color: "#aaa" }); + + swatch.data('color-name', color.name); + swatch.data('color-lrv', color.value); + swatch.data('color-hex', color.hex); + + if (color.category === 1) { + swatch.data('color-category', 'foreground'); + } else if (color.category === 2) { + swatch.data('color-category', 'background'); + } else{ + // do nothing + } + + /** + * click event + */ + swatch.click(function(){ + self.handleClickOrTouch(this); + }); + + swatch.touchstart(function(){ + self.handleClickOrTouch(this); + }); + + /** + * hover event + */ + $(swatch.node).hover( + // mouseover effect + function() { + swatch.g = swatch.glow({color: "#39c", width: 10, opacity: 0.5 }); + }, + // mouseout effect + function() { + swatch.g.remove(); + } + ); + }; + + self.handleClickOrTouch = function(colorSwatch) { + if (colorSwatch.data('color-category') === 'foreground') { + self.fgColorNameText.attr({ 'text': colorSwatch.data('color-name') }); + self.fgColorLRVText.attr({ 'text': colorSwatch.data('color-lrv') }); + self.previewText.attr({ 'fill': "#" + colorSwatch.data('color-hex') }); + self.previewText.data('lrv-value', colorSwatch.data('color-lrv')); + } + + if (colorSwatch.data('color-category') === 'background') { + self.bgColorNameText.attr({ 'text': colorSwatch.data('color-name') }); + self.bgColorLRVText.attr({ 'text': colorSwatch.data('color-lrv') }); + self.previewBox.attr({ 'fill': "#" + colorSwatch.data('color-hex') }); + self.previewBox.data('lrv-value', colorSwatch.data('color-lrv')); + } + + // update the LRV contrast value + self.updateContrastValue(); + }; + + /** + * update the contrast value with the percentage and message + */ + self.updateContrastValue = function() { + var lrvScore, lrvMessage, lrvColor; + + lrvScore = self.calculateContrastValue(); + + if (lrvScore >= self.adaMinContrastValue) { + lrvMessage = lrvScore + "%"; + lrvColor = 'green'; + + self.contrastValueIcon.attr({ 'path': self.checkedBox, 'fill': lrvColor }); + + } else if (lrvScore < self.adaMinContrastValue) { + lrvMessage = lrvScore + "%"; + lrvColor = 'red'; + + self.contrastValueIcon.attr({ 'path': self.uncheckedBox, 'fill': "#ddd" }); + + } else { + lrvMessage = ''; + self.contrastValueIcon.attr({ 'path': self.uncheckedBox, 'fill': "#ddd" }); + } + + self.contrastValueText.attr({ 'text': lrvMessage }); + }; + + + /** + * calculate the contrast value + */ + self.calculateContrastValue = function() { + var fgVal, bgVal, contrast, lrvScore, lrvValue; + + fgVal = self.previewText.data('lrv-value') * 1000; + bgVal = self.previewBox.data('lrv-value') * 1000; + + if (fgVal > bgVal) { + contrast = (bgVal / fgVal); + lrvValue = (contrast * 100) - 100; + lrvScore = lrvValue < 0 ? Math.round(lrvValue * -1) : Math.round(lrvValue); + } else if (fgVal < bgVal) { + contrast = (fgVal / bgVal); + lrvValue = (contrast * 100) - 100; + lrvScore = lrvValue < 0 ? Math.round(lrvValue * -1) : Math.round(lrvValue); + } else { + lrvScore = undefined; + } + + return lrvScore; + }; + + /** + * == chunk + * + * utility function to split an array into smaller arrays + * + * @see http://stackoverflow.com/a/11764168/633432 + */ + self.chunk = function(arr, len) { + var chunks = [], i = 0, n = arr.length; + + while (i < n) { + chunks.push(arr.slice(i, i += len)); + } + return chunks; + }; + + // finally, initialize our Color Contrast Calculator + self.init(); +}