diff --git a/geocamUtil/static/external/js/web_socket.js b/geocamUtil/static/external/js/web_socket.js
deleted file mode 100644
index bed899c..0000000
--- a/geocamUtil/static/external/js/web_socket.js
+++ /dev/null
@@ -1,349 +0,0 @@
-// Copyright: Hiroshi Ichikawa
-// License: New BSD License
-// Reference: http://dev.w3.org/html5/websockets/
-// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol
-
-(function() {
-
- if (window.WebSocket) return;
-
- var console = window.console;
- if (!console || !console.log || !console.error) {
- console = {log: function(){ }, error: function(){ }};
- }
-
- if (!swfobject.hasFlashPlayerVersion("10.0.0")) {
- console.error("Flash Player >= 10.0.0 is required.");
- return;
- }
- if (location.protocol == "file:") {
- console.error(
- "WARNING: web-socket-js doesn't work in file:///... URL " +
- "unless you set Flash Security Settings properly. " +
- "Open the page via Web server i.e. http://...");
- }
-
- /**
- * This class represents a faux web socket.
- * @param {string} url
- * @param {array or string} protocols
- * @param {string} proxyHost
- * @param {int} proxyPort
- * @param {string} headers
- */
- WebSocket = function(url, protocols, proxyHost, proxyPort, headers) {
- var self = this;
- self.__id = WebSocket.__nextId++;
- WebSocket.__instances[self.__id] = self;
- self.readyState = WebSocket.CONNECTING;
- self.bufferedAmount = 0;
- self.__events = {};
- if (!protocols) {
- protocols = [];
- } else if (typeof protocols == "string") {
- protocols = [protocols];
- }
- // Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc.
- // Otherwise, when onopen fires immediately, onopen is called before it is set.
- setTimeout(function() {
- WebSocket.__addTask(function() {
- WebSocket.__flash.create(
- self.__id, url, protocols, proxyHost || null, proxyPort || 0, headers || null);
- });
- }, 0);
- };
-
- /**
- * Send data to the web socket.
- * @param {string} data The data to send to the socket.
- * @return {boolean} True for success, false for failure.
- */
- WebSocket.prototype.send = function(data) {
- if (this.readyState == WebSocket.CONNECTING) {
- throw "INVALID_STATE_ERR: Web Socket connection has not been established";
- }
- // We use encodeURIComponent() here, because FABridge doesn't work if
- // the argument includes some characters. We don't use escape() here
- // because of this:
- // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape_and_unescape_Functions
- // But it looks decodeURIComponent(encodeURIComponent(s)) doesn't
- // preserve all Unicode characters either e.g. "\uffff" in Firefox.
- // Note by wtritch: Hopefully this will not be necessary using ExternalInterface. Will require
- // additional testing.
- var result = WebSocket.__flash.send(this.__id, encodeURIComponent(data));
- if (result < 0) { // success
- return true;
- } else {
- this.bufferedAmount += result;
- return false;
- }
- };
-
- /**
- * Close this web socket gracefully.
- */
- WebSocket.prototype.close = function() {
- if (this.readyState == WebSocket.CLOSED || this.readyState == WebSocket.CLOSING) {
- return;
- }
- this.readyState = WebSocket.CLOSING;
- WebSocket.__flash.close(this.__id);
- };
-
- /**
- * Implementation of {@link DOM 2 EventTarget Interface}
- *
- * @param {string} type
- * @param {function} listener
- * @param {boolean} useCapture
- * @return void
- */
- WebSocket.prototype.addEventListener = function(type, listener, useCapture) {
- if (!(type in this.__events)) {
- this.__events[type] = [];
- }
- this.__events[type].push(listener);
- };
-
- /**
- * Implementation of {@link DOM 2 EventTarget Interface}
- *
- * @param {string} type
- * @param {function} listener
- * @param {boolean} useCapture
- * @return void
- */
- WebSocket.prototype.removeEventListener = function(type, listener, useCapture) {
- if (!(type in this.__events)) return;
- var events = this.__events[type];
- for (var i = events.length - 1; i >= 0; --i) {
- if (events[i] === listener) {
- events.splice(i, 1);
- break;
- }
- }
- };
-
- /**
- * Implementation of {@link DOM 2 EventTarget Interface}
- *
- * @param {Event} event
- * @return void
- */
- WebSocket.prototype.dispatchEvent = function(event) {
- var events = this.__events[event.type] || [];
- for (var i = 0; i < events.length; ++i) {
- events[i](event);
- }
- var handler = this["on" + event.type];
- if (handler) handler(event);
- };
-
- /**
- * Handles an event from Flash.
- * @param {Object} flashEvent
- */
- WebSocket.prototype.__handleEvent = function(flashEvent) {
- if ("readyState" in flashEvent) {
- this.readyState = flashEvent.readyState;
- }
- if ("protocol" in flashEvent) {
- this.protocol = flashEvent.protocol;
- }
-
- var jsEvent;
- if (flashEvent.type == "open" || flashEvent.type == "error") {
- jsEvent = this.__createSimpleEvent(flashEvent.type);
- } else if (flashEvent.type == "close") {
- // TODO implement jsEvent.wasClean
- jsEvent = this.__createSimpleEvent("close");
- } else if (flashEvent.type == "message") {
- var data = decodeURIComponent(flashEvent.message);
- jsEvent = this.__createMessageEvent("message", data);
- } else {
- throw "unknown event type: " + flashEvent.type;
- }
-
- this.dispatchEvent(jsEvent);
- };
-
- WebSocket.prototype.__createSimpleEvent = function(type) {
- if (document.createEvent && window.Event) {
- var event = document.createEvent("Event");
- event.initEvent(type, false, false);
- return event;
- } else {
- return {type: type, bubbles: false, cancelable: false};
- }
- };
-
- WebSocket.prototype.__createMessageEvent = function(type, data) {
- if (document.createEvent && window.MessageEvent && !window.opera) {
- var event = document.createEvent("MessageEvent");
- event.initMessageEvent("message", false, false, data, null, null, window, null);
- return event;
- } else {
- // IE and Opera, the latter one truncates the data parameter after any 0x00 bytes.
- return {type: type, data: data, bubbles: false, cancelable: false};
- }
- };
-
- /**
- * Define the WebSocket readyState enumeration.
- */
- WebSocket.CONNECTING = 0;
- WebSocket.OPEN = 1;
- WebSocket.CLOSING = 2;
- WebSocket.CLOSED = 3;
-
- WebSocket.__flash = null;
- WebSocket.__instances = {};
- WebSocket.__tasks = [];
- WebSocket.__nextId = 0;
-
- /**
- * Load a new flash security policy file.
- * @param {string} url
- */
- WebSocket.loadFlashPolicyFile = function(url){
- WebSocket.__addTask(function() {
- WebSocket.__flash.loadManualPolicyFile(url);
- });
- };
-
- /**
- * Loads WebSocketMain.swf and creates WebSocketMain object in Flash.
- */
- WebSocket.__initialize = function() {
- if (WebSocket.__flash) return;
-
- if (WebSocket.__swfLocation) {
- // For backword compatibility.
- window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation;
- }
- if (!window.WEB_SOCKET_SWF_LOCATION) {
- console.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf");
- return;
- }
- var container = document.createElement("div");
- container.id = "webSocketContainer";
- // Hides Flash box. We cannot use display: none or visibility: hidden because it prevents
- // Flash from loading at least in IE. So we move it out of the screen at (-100, -100).
- // But this even doesn't work with Flash Lite (e.g. in Droid Incredible). So with Flash
- // Lite, we put it at (0, 0). This shows 1x1 box visible at left-top corner but this is
- // the best we can do as far as we know now.
- container.style.position = "absolute";
- if (WebSocket.__isFlashLite()) {
- container.style.left = "0px";
- container.style.top = "0px";
- } else {
- container.style.left = "-100px";
- container.style.top = "-100px";
- }
- var holder = document.createElement("div");
- holder.id = "webSocketFlash";
- container.appendChild(holder);
- document.body.appendChild(container);
- // See this article for hasPriority:
- // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html
- swfobject.embedSWF(
- WEB_SOCKET_SWF_LOCATION,
- "webSocketFlash",
- "1" /* width */,
- "1" /* height */,
- "10.0.0" /* SWF version */,
- null,
- null,
- {hasPriority: true, swliveconnect : true, allowScriptAccess: "always"},
- null,
- function(e) {
- if (!e.success) {
- console.error("[WebSocket] swfobject.embedSWF failed");
- }
- });
- };
-
- /**
- * Called by Flash to notify JS that it's fully loaded and ready
- * for communication.
- */
- WebSocket.__onFlashInitialized = function() {
- // We need to set a timeout here to avoid round-trip calls
- // to flash during the initialization process.
- setTimeout(function() {
- WebSocket.__flash = document.getElementById("webSocketFlash");
- WebSocket.__flash.setCallerUrl(location.href);
- WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);
- for (var i = 0; i < WebSocket.__tasks.length; ++i) {
- WebSocket.__tasks[i]();
- }
- WebSocket.__tasks = [];
- }, 0);
- };
-
- /**
- * Called by Flash to notify WebSockets events are fired.
- */
- WebSocket.__onFlashEvent = function() {
- setTimeout(function() {
- try {
- // Gets events using receiveEvents() instead of getting it from event object
- // of Flash event. This is to make sure to keep message order.
- // It seems sometimes Flash events don't arrive in the same order as they are sent.
- var events = WebSocket.__flash.receiveEvents();
- for (var i = 0; i < events.length; ++i) {
- WebSocket.__instances[events[i].webSocketId].__handleEvent(events[i]);
- }
- } catch (e) {
- console.error(e);
- }
- }, 0);
- return true;
- };
-
- // Called by Flash.
- WebSocket.__log = function(message) {
- console.log(decodeURIComponent(message));
- };
-
- // Called by Flash.
- WebSocket.__error = function(message) {
- console.error(decodeURIComponent(message));
- };
-
- WebSocket.__addTask = function(task) {
- if (WebSocket.__flash) {
- task();
- } else {
- WebSocket.__tasks.push(task);
- }
- };
-
- /**
- * Test if the browser is running flash lite.
- * @return {boolean} True if flash lite is running, false otherwise.
- */
- WebSocket.__isFlashLite = function() {
- if (!window.navigator || !window.navigator.mimeTypes) {
- return false;
- }
- var mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"];
- if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) {
- return false;
- }
- return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false;
- };
-
- if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) {
- if (window.addEventListener) {
- window.addEventListener("load", function(){
- WebSocket.__initialize();
- }, false);
- } else {
- window.attachEvent("onload", function(){
- WebSocket.__initialize();
- });
- }
- }
-
-})();
diff --git a/geocamUtil/static/external/swf/WebSocketMain.swf b/geocamUtil/static/external/swf/WebSocketMain.swf
deleted file mode 100644
index 6a06584..0000000
Binary files a/geocamUtil/static/external/swf/WebSocketMain.swf and /dev/null differ
diff --git a/geocamUtil/static/gumby/sass/extensions/modular-scale/lib/modular-scale.rb b/geocamUtil/static/gumby/sass/extensions/modular-scale/lib/modular-scale.rb
new file mode 100755
index 0000000..57fb90c
--- /dev/null
+++ b/geocamUtil/static/gumby/sass/extensions/modular-scale/lib/modular-scale.rb
@@ -0,0 +1,128 @@
+# All gems that are required for this extension to work should go here.
+# These are the requires you would normally put in your config.rb file
+# By default, you should always included Compass. Do not include your
+# extension.
+require 'compass'
+
+# This tells Compass what your Compass extension is called, and where to find
+# its files
+extension_path = File.expand_path(File.join(File.dirname(__FILE__), ".."))
+Compass::Frameworks.register('modular-scale', :path => extension_path)
+
+# Version and date of version for your Compass extension.
+# Replace ModularScale with the name of your extension
+# Letters, numbers, and underscores only
+# Version is a number. If a version contains alphas, it will be created as
+# a prerelease version
+# Date is in the form of YYYY-MM-DD
+module ModularScale
+ VERSION = "2.0.6"
+ DATE = "2013-12-20"
+end
+
+# This is where any custom SassScript should be placed. The functions will be
+# available on require of your extension without the need for users to import
+# any partials. Uncomment below.
+
+module Sass::Script::Functions
+
+ # Let MS know that extra functionality is avalible
+ def ms_gem_installed()
+ Sass::Script::Bool.new(true)
+ end
+
+ def ms_gem_func(value, bases, ratios)
+
+ # Convert to native ruby things
+ rvalue = value.value.to_i
+
+ if bases.class == Sass::Script::Number
+ bases = [] << bases
+ else
+ bases = [*bases.value]
+ end
+ if ratios.class == Sass::Script::Number
+ ratios = [] << ratios
+ else
+ ratios = [*ratios.value]
+ end
+
+ # Convert items in arrays to floating point numbers
+ rbases = []
+ rratios = []
+ bases.each do |num|
+ rbases << num.value.to_f
+ end
+ ratios.each do |num|
+ rratios << num.value.to_f
+ end
+
+
+ # Blank array for return
+ r = [rbases[0]]
+
+ # loop through all possibilities
+ # NOTE THIS IS NOT FULLY FUNCTIONAL YET
+ # ONLY LOOPS THROUGH SOME/MOST OF THE POSSIBILITES
+
+ rratios.each do |ratio|
+ rbases.each do |base|
+
+ base_counter = 0
+
+ # Seed list with an initial value
+ r << base
+
+ # Find values on a positive scale
+ if rvalue >= 0
+ # Find higher values on the scale
+ i = 0;
+ while ((ratio ** i) * base) >= (rbases[0])
+ r << (ratio ** i) * base
+ i = i - 1;
+ end
+
+ # Find lower possible values on the scale
+ i = 0;
+ while ((ratio ** i) * base) <= ((ratio ** (rvalue + 1)) * base)
+ r << (ratio ** i) * base
+ i = i + 1;
+ end
+
+ else
+
+ # Find lower values on the scale
+ i = 0;
+ while ((ratio ** i) * base) <= (rbases[0])
+ r << (ratio ** i) * base
+ i = i + 1;
+ end
+
+ # Find higher possible values on the scale
+ i = 0;
+ while ((ratio ** i) * base) >= ((ratio ** (rvalue - 1)) * base)
+ r << (ratio ** i) * base
+ i = i - 1;
+ end
+ end
+
+ end
+ end
+
+ # Sort and trim
+ r.sort!
+ r.uniq!
+
+
+ if rvalue < 0
+ r = r.keep_if { |a| a <= rbases[0] }
+ # Final value
+ r = r[(rvalue - 1)]
+ else
+ r = r[rvalue]
+ end
+
+
+ Sass::Script::Number.new(r)
+ end
+end
\ No newline at end of file
diff --git a/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/_modular-scale-tests.scss b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/_modular-scale-tests.scss
new file mode 100755
index 0000000..0d8a734
--- /dev/null
+++ b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/_modular-scale-tests.scss
@@ -0,0 +1,74 @@
+@if "#{ms(2, 16, $minor-sixth)}" != "40.96" {
+ @debug "";
+ @warn "function ms(): FAIL!";
+ @debug "function ms(2, 16, $minor-sixth)";
+ @debug "Result: #{ms(2, 16, $minor-sixth)}";
+ @debug "Intended: 40.96";
+ @debug "";
+}@else {
+ @warn "function ms(+): pass";
+}
+
+@if "#{ms(-2, 16, $minor-sixth)}" != "6.25" {
+ @debug "";
+ @warn "function ms(): FAIL!";
+ @debug "function ms(-2, 16, $minor-sixth)";
+ @debug "Result: #{ms(-2, 16, $minor-sixth)}";
+ @debug "Intended: 6.25";
+ @debug "";
+}@else {
+ @warn "function ms(-): pass";
+}
+
+@if ms(2, 14 18, $major-second) != 15.75 {
+ @debug "";
+ @warn "function ms() multi-base: FAIL!";
+ @debug "function ms(2, 14 18, $major-second)";
+ @debug "Result: #{ms(2, 14 18, $major-second)}";
+ @debug "Intended: 15.75";
+ @debug "";
+}@else {
+ @warn "function ms(+) multi-base: pass";
+}
+
+@if ms(-1, 14 18, $major-third) != 11.52 {
+ @debug "";
+ @warn "function ms() multi-base: FAIL!";
+ @debug "function ms(-1, 14 18, $major-third)";
+ @debug "Result: #{ms(-1, 14 18, $major-third)}";
+ @debug "Intended: 11.52";
+ @debug "";
+}@else {
+ @warn "function ms(-) multi-base: pass";
+}
+
+@if "#{ms(-4, 12, $major-tenth $octave)}" != "1.92" {
+ @debug "";
+ @warn "function ms() multi-ratio: FAIL!";
+ @debug "function ms(-4, 12, $major-tenth $octave)";
+ @debug "Result: #{ms(-4, 12, $major-tenth $octave)}";
+ @debug "Intended: 1.92";
+ @debug "";
+}@else {
+ @warn "function ms(+) multi-ratio: pass";
+}
+
+@if ms(-4, 12, $major-tenth $octave) != 1.92 {
+ @debug "";
+ @warn "function ms() multi-ratio: FAIL!";
+ @debug "function ms(-4, 12, $major-tenth $octave)";
+ @debug "Result: #{ms(-4, 12, $major-tenth $octave)}";
+ @debug "Intended: 1.92";
+ @debug "";
+}@else {
+ @warn "function ms(-) multi-ratio: pass";
+}
+
+@if ms-list(-3, 3, 10 16, $major-third) != (6.5536 8 8.192 10 10.24 12.5 12.8) {
+ @debug "function ms-list(): FAIL!";
+ @warn "function ms-list(-3, 3, 10 16, $major-third)";
+ @debug "Result: (#{ms-list(-3, 3, 10 16, $major-third)})";
+ @debug "Intended: (6.5536 8 8.192 10 10.24 12.5 12.8)";
+}@else {
+ @warn "function ms-list(): pass";
+}
\ No newline at end of file
diff --git a/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/_modular-scale.scss b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/_modular-scale.scss
new file mode 100755
index 0000000..c7d40f6
--- /dev/null
+++ b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/_modular-scale.scss
@@ -0,0 +1,17 @@
+@import "modular-scale/ratios";
+
+$ms-base: 1em !default;
+$ms-ratio: $golden !default;
+$ms-range: null !default;
+
+@import "modular-scale/tests";
+
+@import "modular-scale/pow";
+@import "modular-scale/calc";
+@import "modular-scale/generate-list";
+@import "modular-scale/sort-list";
+@import "modular-scale/round-px";
+@import "modular-scale/function";
+@import "modular-scale/function-list";
+
+@import "modular-scale/respond";
\ No newline at end of file
diff --git a/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_calc.scss b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_calc.scss
new file mode 100755
index 0000000..60620ee
--- /dev/null
+++ b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_calc.scss
@@ -0,0 +1,17 @@
+@function ms-calc($Value, $Base: $ms-base, $Ratio: $ms-ratio) {
+
+ // If pow exists use it.
+ // It supports non-interger values!
+ @if $MS-pow-exists {
+
+ // The formula for figuring out modular scales is:
+ // (r^v)*b
+ @return pow($Ratio, $Value) * $Base;
+ }
+
+ // If not, use ms-pow().
+ // Not as fast or capable of non-integer exponents.
+ @else {
+ @return ms-pow($Ratio, $Value) * $Base;
+ }
+}
\ No newline at end of file
diff --git a/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_function-list.scss b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_function-list.scss
new file mode 100755
index 0000000..7aa1ba7
--- /dev/null
+++ b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_function-list.scss
@@ -0,0 +1,68 @@
+// Outputs a list of values instead of a single value
+@function ms-list($Start: 0, $End: 0, $Bases: $ms-base, $Ratios: $ms-ratio) {
+
+ // Seed results
+ $Positive-return: ();
+ $Negitive-return: ();
+ $Return: ();
+
+ @if $End >= 0 {
+ // Generate a list of all possible values
+ $Positive-return: ms-generate-list($End, $Bases, $Ratios);
+
+ // Sort the generated lists
+ $Positive-return: ms-sort-list($Positive-return);
+
+ // Trim list
+ $Trim-list: ();
+ // If the starting value is a positive number
+ // trim the positive return from that
+ @if $Start >= 0 {
+ @for $i from ($Start + 1) through $End + 1 {
+ $Trim-list: join($Trim-list, nth($Positive-return, $i));
+ }
+ }
+ // If not, then include everything up to the end.
+ @else {
+ @for $i from 1 through $End + 1 {
+ $Trim-list: join($Trim-list, nth($Positive-return, $i));
+ }
+ }
+ $Positive-return: $Trim-list;
+ }
+
+ // Generate a negitive list
+ @if $Start < 0 {
+ // Generate a list of all possible values
+ $Negitive-return: ms-generate-list($Start, $Bases, $Ratios);
+
+ // Sort the generated lists
+ $Negitive-return: ms-sort-list($Negitive-return);
+
+ // Reverse negitive list results.
+ $MS-new-return: ();
+ @each $i in $Negitive-return {
+ $MS-new-return: join($i, $MS-new-return);
+ }
+ $Negitive-return: $MS-new-return;
+
+ // Trim list
+ $Trim-list: ();
+ @if $End < 0 {
+ @for $i from abs($End) through (abs($Start) + 2) {
+ $Trim-list: join(nth($Negitive-return, $i), $Trim-list);
+ }
+ }
+ @else {
+ @for $i from 2 through (abs($Start) + 1) {
+ $Trim-list: join(nth($Negitive-return, $i), $Trim-list);
+ }
+ }
+ $Negitive-return: $Trim-list;
+ }
+
+ // Join both positive and negitive possibilities.
+ $Return: join($Negitive-return, $Positive-return);
+
+ @return $Return;
+}
diff --git a/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_function.scss b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_function.scss
new file mode 100755
index 0000000..ac00423
--- /dev/null
+++ b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_function.scss
@@ -0,0 +1,55 @@
+// The main function that brings it all together
+@function ms($Value: 0, $Bases: $ms-base, $Ratios: $ms-ratio) {
+
+ // If no multi-base or multi-ratio stuff is going on
+ // then just retrn the basic calculaiton
+ @if length($Bases) == 1 and length($Ratios) == 1 {
+ @return ms-round-px(ms-calc($Value, $Bases, $Ratios));
+ }
+
+ // Do calculations directly in Ruby when avalible
+ @if $MS-gem-exists {
+
+ // Remove units from bases
+ $Unit: nth($Bases, 1) * 0 + 1; // Extracts the unit from the base
+ $Unitless-Bases: ();
+ @each $Base in $Bases {
+ $Base: $Base/$Unit;
+ $Unitless-Bases: join($Unitless-Bases, $Base);
+ }
+
+ // Calculate natively in Ruby
+ @return ms-round-px(ms-gem-func($Value, $Unitless-Bases, $Ratios) * $Unit);
+ }
+
+ // Generate a list of all possible values
+ $Return: ms-generate-list($Value, $Bases, $Ratios);
+
+ // Sort the generated lists
+ $Return: ms-sort-list($Return);
+
+ // Reverse list if its negitive.
+ @if $Value < 0 {
+ $MS-new-return: ();
+ @each $i in $Return {
+ $MS-new-return: join($i, $MS-new-return);
+ }
+ $Return: $MS-new-return;
+ }
+
+ // Normalize value for counting from 1
+ // Because CSS counts things from 1
+ // So Sass does as well
+ // So I get to write fun stuff like this
+ $Value: abs($Value) + 1;
+
+ // Find the correct value in the list
+ $Return: nth($Return, $Value);
+
+ @return ms-round-px($Return);
+}
+
+// Same function, different name, for good measure.
+@function modular-scale($Value: 0, $Bases: $ms-base, $Ratios: $ms-ratio) {
+ @return ms($Value, $Bases, $Ratios);
+}
\ No newline at end of file
diff --git a/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_generate-list.scss b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_generate-list.scss
new file mode 100755
index 0000000..a46d210
--- /dev/null
+++ b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_generate-list.scss
@@ -0,0 +1,103 @@
+@function ms-reverse-list($list) {
+ @if length($list) > 1 {
+ @if nth($list, 1) > nth($list, length($list)) {
+ $MS-reversed-list: ();
+ @each $Value in $list {
+ $MS-reversed-list: join($Value, $MS-reversed-list);
+ }
+ @return $MS-reversed-list;
+ }
+ }
+ @return $list;
+}
+
+
+@function ms-generate-list($Value: 0, $Bases: $ms-base, $Ratios: $ms-ratio) {
+
+ // Create blank lists
+ $MS-list: ();
+ $MS-base-list: ();
+
+ // Loop through each ratio AND each base
+ // to generate all possibilities.
+ @each $Ratio in $Ratios {
+ @each $Base in $Bases {
+
+ // Set base variables
+ $MS-base-list: ();
+ $Base-counter: 0;
+
+ // Seed list with an initial value
+ $MS-base-list: $Base;
+
+ // Find values on a positive scale
+ @if $Value >= 0 {
+
+ // Find lower values on the scale
+ $Base-counter: -1;
+ @while ms-calc($Base-counter, $Base, $Ratio) >= nth($Bases, 1) {
+ $MS-base-list: join($MS-base-list, ms-calc($Base-counter, $Base, $Ratio));
+ $Base-counter: $Base-counter - 1;
+ }
+
+ // Ensure the list is smallest to largest
+ $MS-base-list: ms-reverse-list($MS-base-list);
+
+ // Find higher possible values on the scale
+ $Base-counter: 1;
+ @while ms-calc($Base-counter, $Base, $Ratio) <= ms-calc($Value, nth($Bases, 1), $Ratio) {
+ $MS-base-list: join($MS-base-list, ms-calc($Base-counter, $Base, $Ratio));
+ $Base-counter: $Base-counter + 1;
+ }
+ }
+
+ // Find values on a negitive scale
+ @else {
+
+ // Find lower values on the scale
+ $Base-counter: 1;
+ @while ms-calc($Base-counter, $Base, $Ratio) <= nth($Bases, 1) {
+ $MS-base-list: join($MS-base-list, ms-calc($Base-counter, $Base, $Ratio));
+ $Base-counter: $Base-counter + 1;
+ }
+
+ // Ensure the list is smallest to largest
+ $MS-base-list: ms-reverse-list($MS-base-list);
+
+ // Find higher possible values on the scale
+ $Base-counter: -1;
+ @while ms-calc($Base-counter, $Base, $Ratio) >= ms-calc($Value, nth($Bases, 1), $Ratio) {
+ $MS-calc: ms-calc($Base-counter, $Base, $Ratio);
+ // detect if the value excedes the main base value
+ @if $MS-calc < nth($Bases, 1) {
+ $MS-base-list: join($MS-base-list, $MS-calc);
+ }
+ $Base-counter: $Base-counter - 1;
+ }
+
+ // Trim outlier base.
+ @if length($Bases) > 1 {
+ @for $i from 2 through length($Bases) {
+ @if nth($MS-base-list, 1) > nth($Bases, 1) {
+ $MS-new-list: ();
+ @for $i from 2 through length($MS-base-list) {
+ $MS-new-list: join($MS-new-list, nth($MS-base-list, $i));
+ }
+ $MS-base-list: $MS-new-list;
+ }
+ }
+ }
+ }
+
+ // reverse list if its largest to smallest
+ $MS-base-list: ms-reverse-list($MS-base-list);
+
+ // Add new possibilities to the master list
+ $MS-list: append($MS-list, $MS-base-list, comma);
+
+ }
+ }
+
+ // After all the possibilities are found, output a master list
+ @return $MS-list;
+}
\ No newline at end of file
diff --git a/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_pow.scss b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_pow.scss
new file mode 100755
index 0000000..3c503ab
--- /dev/null
+++ b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_pow.scss
@@ -0,0 +1,40 @@
+// If a native exponent function doesnt exist
+// this one is needed.
+@function ms-pow($Base, $Exponent) {
+
+ // Find and remove unit.
+ // Avoids messyness with unit calculations
+ $Unit: $Base * 0 + 1;
+ $Base: $Base/$Unit;
+
+ // This function doesnt support non-interger exponents.
+ // Warn the user about why this is breaking.
+ @if round($Exponent) != $Exponent {
+ @warn "Unfortunately, you need Compass to use non-integer exponents";
+ }
+
+ // Set up the loop, priming the return with the base.
+ $Return: $Base;
+
+ // If the number is positive, multiply it.
+ @if $Exponent > 0 {
+ // Basic feedback loop as exponents
+ // are recursivley multiplied numbers.
+ @for $i from 1 to $Exponent {
+ $Return: $Return * $Base;
+ }
+ }
+
+ // If the number is 0 or negitive
+ // divide instead of multiply.
+ @else {
+ // Libsass doesnt allow negitive values in loops
+ @for $i from (-1 + 1) to (abs($Exponent) + 1) {
+ $Return: $Return / $Base;
+ }
+ }
+
+ // Return is now compounded redy to be returned.
+ // Add the unit back onto the number.
+ @return $Return * $Unit;
+}
\ No newline at end of file
diff --git a/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_ratios.scss b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_ratios.scss
new file mode 100755
index 0000000..8b80828
--- /dev/null
+++ b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_ratios.scss
@@ -0,0 +1,20 @@
+// Golden ratio
+$phi : 1.618034 ;
+$golden : $phi ;
+
+$double-octave : 4 ;
+$major-twelfth : 3 ;
+$major-eleventh : 2.666666667 ;
+$major-tenth : 2.5 ;
+$octave : 2 ;
+$major-seventh : 1.875 ;
+$minor-seventh : 1.777777778 ;
+$major-sixth : 1.666666667 ;
+$minor-sixth : 1.6 ;
+$fifth : 1.5 ;
+$augmented-fourth : 1.41421 ;
+$fourth : 1.333333333 ;
+$major-third : 1.25 ;
+$minor-third : 1.2 ;
+$major-second : 1.125 ;
+$minor-second : 1.066666667 ;
\ No newline at end of file
diff --git a/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_respond.scss b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_respond.scss
new file mode 100755
index 0000000..41c8dcf
--- /dev/null
+++ b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_respond.scss
@@ -0,0 +1,16 @@
+@mixin ms-respond($property, $value, $range: $ms-range, $base: $ms-base) {
+ @if $ms-range == null {
+ #{$property}: ms($value,$base,$ms-ratio);
+ } @else {
+ @for $i from 1 through length($range) {
+ @debug nth($range,$i);
+ @if $i == 1 {
+ #{$property}: ms($value,$base,nth(nth($range,$i),1));
+ } @else {
+ @media (min-width: nth(nth($range,$i),2)) {
+ #{$property}: ms($value,$base,nth(nth($range,$i),1));
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_round-px.scss b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_round-px.scss
new file mode 100755
index 0000000..10d51d9
--- /dev/null
+++ b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_round-px.scss
@@ -0,0 +1,6 @@
+@function ms-round-px($Result) {
+ @if unit($Result) == 'px' {
+ @return round($Result);
+ }
+ @return $Result;
+}
\ No newline at end of file
diff --git a/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_sort-list.scss b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_sort-list.scss
new file mode 100755
index 0000000..80d4d53
--- /dev/null
+++ b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_sort-list.scss
@@ -0,0 +1,93 @@
+// List sorting via a modified merge-sort algorythmn
+// http://en.wikipedia.org/wiki/Merge_sort
+
+@function ms-merge($A, $B) {
+
+ $Return: ();
+
+ // Some empty lists get passed through
+ // so just pass the other list throguh
+ @if length($A) == 0 {
+ @return $B;
+ }
+
+ // If lists fit next to each other, just merge them
+ // This helps performance skipping the need to check each value
+ @if nth($A, length($A)) < nth($B, 1) {
+ @return join($A, $B);
+ }
+ @if nth($B, length($B)) < nth($A, 1) {
+ @return join($B, $A);
+ }
+
+ // Counters start at 1
+ $A-counter: 1;
+ $B-counter: 1;
+
+ // Start looping through all numbers in array
+ @while $A-counter <= length($A) and $B-counter <= length($B) {
+
+ // Check if the A value is smaller
+ // Uses or equal to avoid duplicate numbers
+ @if nth($A, $A-counter) <= nth($B, $B-counter) {
+ $Return: join($Return, nth($A, $A-counter));
+ $A-counter: $A-counter + 1;
+ }
+
+ // Check if the B value is smaller
+ @elseif nth($A, $A-counter) > nth($B, $B-counter) {
+ $Return: join($Return, nth($B, $B-counter));
+ $B-counter: $B-counter + 1;
+ }
+ }
+
+ // Run through remainder values in the list
+ @while $A-counter <= length($A) {
+ $Current: nth($A, $A-counter);
+ @if $Current != nth($Return, length($Return)) {
+ $Return: join($Return, $Current);
+ }
+ $A-counter: $A-counter + 1;
+ }
+ @while $B-counter <= length($B) {
+ $Current: nth($B, $B-counter);
+ @if $Current != nth($Return, length($Return)) {
+ $Return: join($Return, $Current);
+ }
+ $B-counter: $B-counter + 1;
+ }
+
+ // Done! return is now sorted and complete
+ @return $Return;
+}
+
+
+
+// Pull it all together
+@function ms-sort-list($Lists) {
+
+ $Return: ();
+
+ @each $List in $Lists {
+ @if $Return == () {
+ $Return: $List;
+ }
+ @else {
+ $Return: ms-merge($List, $Return);
+ }
+ }
+
+ // final cleanup of repeated items
+ $Last: null;
+ $New-list: ();
+ @each $Item in $Return {
+ @if $Item != $Last {
+ $New-list: join($New-list, $Item);
+ }
+ $Last: $Item;
+ }
+ $Return: $New-list;
+
+
+ @return $Return;
+}
\ No newline at end of file
diff --git a/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_tests.scss b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_tests.scss
new file mode 100755
index 0000000..d64a99d
--- /dev/null
+++ b/geocamUtil/static/gumby/sass/extensions/modular-scale/stylesheets/modular-scale/_tests.scss
@@ -0,0 +1,22 @@
+// Feature testing
+
+
+// Test if the pow() function exists
+@function ms-pow-exists() {
+ @if pow(4, 2) == 16 {
+ @return true;
+ }
+ @return false;
+}
+
+$MS-pow-exists: ms-pow-exists();
+
+// Test if MS was installed via the gem
+@function ms-gem-exists() {
+ @if ms-gem-installed() == true {
+ @return true;
+ }
+ @return false;
+}
+
+$MS-gem-exists: ms-gem-exists();
\ No newline at end of file