[gnome-code-assistance] Update distributed sass to 3.4.9



commit c11fed7f4766d826adbfb45492f498a2f5275c3e
Author: Jesse van den Kieboom <jessevdk gmail com>
Date:   Sat Jan 10 13:46:34 2015 +0100

    Update distributed sass to 3.4.9

 backends/css/app.rb                                |    2 +-
 backends/css/deps.mf                               |  901 +++---
 backends/css/gems/sass-3.2.12/CONTRIBUTING         |    3 -
 backends/css/gems/sass-3.2.12/MIT-LICENSE          |   20 -
 backends/css/gems/sass-3.2.12/README.md            |  201 -
 backends/css/gems/sass-3.2.12/Rakefile             |  347 --
 backends/css/gems/sass-3.2.12/VERSION              |    1 -
 backends/css/gems/sass-3.2.12/VERSION_DATE         |    1 -
 backends/css/gems/sass-3.2.12/VERSION_NAME         |    1 -
 backends/css/gems/sass-3.2.12/bin/sass             |    9 -
 backends/css/gems/sass-3.2.12/bin/sass-convert     |    8 -
 backends/css/gems/sass-3.2.12/bin/scss             |    9 -
 backends/css/gems/sass-3.2.12/lib/sass.rb          |   95 -
 .../gems/sass-3.2.12/lib/sass/cache_stores/base.rb |   88 -
 .../sass-3.2.12/lib/sass/cache_stores/chain.rb     |   33 -
 .../lib/sass/cache_stores/filesystem.rb            |   60 -
 .../sass-3.2.12/lib/sass/cache_stores/memory.rb    |   47 -
 .../gems/sass-3.2.12/lib/sass/cache_stores/null.rb |   25 -
 .../css/gems/sass-3.2.12/lib/sass/callbacks.rb     |   66 -
 backends/css/gems/sass-3.2.12/lib/sass/css.rb      |  409 --
 backends/css/gems/sass-3.2.12/lib/sass/engine.rb   |  928 -----
 .../css/gems/sass-3.2.12/lib/sass/environment.rb   |  101 -
 backends/css/gems/sass-3.2.12/lib/sass/error.rb    |  201 -
 backends/css/gems/sass-3.2.12/lib/sass/exec.rb     |  707 ----
 .../gems/sass-3.2.12/lib/sass/importers/base.rb    |  139 -
 .../sass-3.2.12/lib/sass/importers/filesystem.rb   |  190 -
 backends/css/gems/sass-3.2.12/lib/sass/logger.rb   |   15 -
 .../css/gems/sass-3.2.12/lib/sass/logger/base.rb   |   32 -
 .../gems/sass-3.2.12/lib/sass/logger/log_level.rb  |   49 -
 backends/css/gems/sass-3.2.12/lib/sass/media.rb    |  213 --
 backends/css/gems/sass-3.2.12/lib/sass/plugin.rb   |  132 -
 .../gems/sass-3.2.12/lib/sass/plugin/compiler.rb   |  406 --
 .../sass-3.2.12/lib/sass/plugin/configuration.rb   |  123 -
 .../css/gems/sass-3.2.12/lib/sass/plugin/merb.rb   |   48 -
 .../lib/sass/plugin/staleness_checker.rb           |  199 -
 backends/css/gems/sass-3.2.12/lib/sass/railtie.rb  |    9 -
 backends/css/gems/sass-3.2.12/lib/sass/repl.rb     |   57 -
 backends/css/gems/sass-3.2.12/lib/sass/script.rb   |   39 -
 .../gems/sass-3.2.12/lib/sass/script/arg_list.rb   |   52 -
 .../css/gems/sass-3.2.12/lib/sass/script/bool.rb   |   18 -
 .../css/gems/sass-3.2.12/lib/sass/script/color.rb  |  606 ---
 .../gems/sass-3.2.12/lib/sass/script/css_lexer.rb  |   29 -
 .../gems/sass-3.2.12/lib/sass/script/css_parser.rb |   31 -
 .../gems/sass-3.2.12/lib/sass/script/funcall.rb    |  237 --
 .../gems/sass-3.2.12/lib/sass/script/functions.rb  | 1543 --------
 .../sass-3.2.12/lib/sass/script/interpolation.rb   |   79 -
 .../css/gems/sass-3.2.12/lib/sass/script/lexer.rb  |  348 --
 .../css/gems/sass-3.2.12/lib/sass/script/list.rb   |   85 -
 .../gems/sass-3.2.12/lib/sass/script/literal.rb    |  221 --
 .../css/gems/sass-3.2.12/lib/sass/script/node.rb   |   99 -
 .../css/gems/sass-3.2.12/lib/sass/script/null.rb   |   37 -
 .../css/gems/sass-3.2.12/lib/sass/script/number.rb |  453 ---
 .../gems/sass-3.2.12/lib/sass/script/operation.rb  |  110 -
 .../css/gems/sass-3.2.12/lib/sass/script/parser.rb |  495 ---
 .../css/gems/sass-3.2.12/lib/sass/script/string.rb |   51 -
 .../lib/sass/script/string_interpolation.rb        |  103 -
 .../sass-3.2.12/lib/sass/script/unary_operation.rb |   69 -
 .../gems/sass-3.2.12/lib/sass/script/variable.rb   |   58 -
 .../gems/sass-3.2.12/lib/sass/scss/css_parser.rb   |   36 -
 .../css/gems/sass-3.2.12/lib/sass/scss/parser.rb   | 1179 ------
 backends/css/gems/sass-3.2.12/lib/sass/scss/rx.rb  |  133 -
 .../sass-3.2.12/lib/sass/scss/static_parser.rb     |   54 -
 backends/css/gems/sass-3.2.12/lib/sass/selector.rb |  452 ---
 .../lib/sass/selector/abstract_sequence.rb         |   94 -
 .../lib/sass/selector/comma_sequence.rb            |   92 -
 .../gems/sass-3.2.12/lib/sass/selector/sequence.rb |  507 ---
 .../gems/sass-3.2.12/lib/sass/selector/simple.rb   |  119 -
 .../lib/sass/selector/simple_sequence.rb           |  212 --
 backends/css/gems/sass-3.2.12/lib/sass/shared.rb   |   76 -
 backends/css/gems/sass-3.2.12/lib/sass/supports.rb |  229 --
 .../gems/sass-3.2.12/lib/sass/tree/charset_node.rb |   22 -
 .../gems/sass-3.2.12/lib/sass/tree/comment_node.rb |   82 -
 .../sass-3.2.12/lib/sass/tree/css_import_node.rb   |   60 -
 .../gems/sass-3.2.12/lib/sass/tree/debug_node.rb   |   18 -
 .../sass-3.2.12/lib/sass/tree/directive_node.rb    |   42 -
 .../gems/sass-3.2.12/lib/sass/tree/each_node.rb    |   24 -
 .../gems/sass-3.2.12/lib/sass/tree/extend_node.rb  |   36 -
 .../css/gems/sass-3.2.12/lib/sass/tree/for_node.rb |   36 -
 .../sass-3.2.12/lib/sass/tree/function_node.rb     |   34 -
 .../css/gems/sass-3.2.12/lib/sass/tree/if_node.rb  |   52 -
 .../gems/sass-3.2.12/lib/sass/tree/import_node.rb  |   75 -
 .../gems/sass-3.2.12/lib/sass/tree/media_node.rb   |   58 -
 .../sass-3.2.12/lib/sass/tree/mixin_def_node.rb    |   38 -
 .../gems/sass-3.2.12/lib/sass/tree/mixin_node.rb   |   39 -
 .../css/gems/sass-3.2.12/lib/sass/tree/node.rb     |  196 -
 .../gems/sass-3.2.12/lib/sass/tree/prop_node.rb    |  152 -
 .../gems/sass-3.2.12/lib/sass/tree/return_node.rb  |   18 -
 .../gems/sass-3.2.12/lib/sass/tree/root_node.rb    |   28 -
 .../gems/sass-3.2.12/lib/sass/tree/rule_node.rb    |  132 -
 .../sass-3.2.12/lib/sass/tree/supports_node.rb     |   51 -
 .../gems/sass-3.2.12/lib/sass/tree/trace_node.rb   |   32 -
 .../sass-3.2.12/lib/sass/tree/variable_node.rb     |   30 -
 .../sass-3.2.12/lib/sass/tree/visitors/base.rb     |   75 -
 .../lib/sass/tree/visitors/check_nesting.rb        |  147 -
 .../sass-3.2.12/lib/sass/tree/visitors/convert.rb  |  316 --
 .../sass-3.2.12/lib/sass/tree/visitors/cssize.rb   |  229 --
 .../lib/sass/tree/visitors/deep_copy.rb            |  102 -
 .../sass-3.2.12/lib/sass/tree/visitors/extend.rb   |   68 -
 .../sass-3.2.12/lib/sass/tree/visitors/perform.rb  |  446 ---
 .../lib/sass/tree/visitors/set_options.rb          |  125 -
 .../sass-3.2.12/lib/sass/tree/visitors/to_css.rb   |  228 --
 .../gems/sass-3.2.12/lib/sass/tree/warn_node.rb    |   18 -
 .../gems/sass-3.2.12/lib/sass/tree/while_node.rb   |   18 -
 backends/css/gems/sass-3.2.12/lib/sass/util.rb     |  930 -----
 .../lib/sass/util/multibyte_string_scanner.rb      |  155 -
 .../gems/sass-3.2.12/lib/sass/util/subset_map.rb   |  109 -
 .../css/gems/sass-3.2.12/lib/sass/util/test.rb     |   10 -
 backends/css/gems/sass-3.2.12/lib/sass/version.rb  |  126 -
 backends/css/gems/sass-3.2.12/test/Gemfile         |    3 -
 backends/css/gems/sass-3.2.12/test/Gemfile.lock    |   10 -
 .../css/gems/sass-3.2.12/test/sass/cache_test.rb   |   89 -
 .../gems/sass-3.2.12/test/sass/callbacks_test.rb   |   61 -
 .../gems/sass-3.2.12/test/sass/conversion_test.rb  | 1760 ---------
 .../gems/sass-3.2.12/test/sass/css2sass_test.rb    |  439 ---
 .../css/gems/sass-3.2.12/test/sass/engine_test.rb  | 3243 ----------------
 .../css/gems/sass-3.2.12/test/sass/exec_test.rb    |   86 -
 .../css/gems/sass-3.2.12/test/sass/extend_test.rb  | 1482 --------
 .../gems/sass-3.2.12/test/sass/functions_test.rb   | 1139 ------
 .../gems/sass-3.2.12/test/sass/importer_test.rb    |  192 -
 .../css/gems/sass-3.2.12/test/sass/logger_test.rb  |   58 -
 .../test/sass/more_results/more_import.css         |   29 -
 .../css/gems/sass-3.2.12/test/sass/plugin_test.rb  |  550 ---
 .../gems/sass-3.2.12/test/sass/results/compact.css |    5 -
 .../gems/sass-3.2.12/test/sass/results/complex.css |   86 -
 .../sass-3.2.12/test/sass/results/expanded.css     |   19 -
 .../gems/sass-3.2.12/test/sass/results/import.css  |   31 -
 .../test/sass/results/import_charset_ibm866.css    |    5 -
 .../gems/sass-3.2.12/test/sass/results/mixins.css  |   95 -
 .../gems/sass-3.2.12/test/sass/results/nested.css  |   22 -
 .../sass-3.2.12/test/sass/results/parent_ref.css   |   13 -
 .../gems/sass-3.2.12/test/sass/results/script.css  |   16 -
 .../sass-3.2.12/test/sass/results/scss_import.css  |   31 -
 .../test/sass/script_conversion_test.rb            |  299 --
 .../css/gems/sass-3.2.12/test/sass/script_test.rb  |  591 ---
 .../gems/sass-3.2.12/test/sass/scss/css_test.rb    | 1093 ------
 .../css/gems/sass-3.2.12/test/sass/scss/rx_test.rb |  156 -
 .../gems/sass-3.2.12/test/sass/scss/scss_test.rb   | 2043 ----------
 .../test/sass/templates/scss_import.scss           |   11 -
 .../css/gems/sass-3.2.12/test/sass/test_helper.rb  |    8 -
 .../sass/util/multibyte_string_scanner_test.rb     |  147 -
 .../sass-3.2.12/test/sass/util/subset_map_test.rb  |   91 -
 .../css/gems/sass-3.2.12/test/sass/util_test.rb    |  361 --
 backends/css/gems/sass-3.2.12/test/test_helper.rb  |   80 -
 .../gems/sass-3.2.12/vendor/listen/CHANGELOG.md    |  228 --
 .../css/gems/sass-3.2.12/vendor/listen/Gemfile     |   30 -
 .../css/gems/sass-3.2.12/vendor/listen/README.md   |  315 --
 .../css/gems/sass-3.2.12/vendor/listen/Rakefile    |   47 -
 .../gems/sass-3.2.12/vendor/listen/lib/listen.rb   |   40 -
 .../vendor/listen/lib/listen/adapter.rb            |  214 --
 .../vendor/listen/lib/listen/adapters/bsd.rb       |  112 -
 .../vendor/listen/lib/listen/adapters/darwin.rb    |   85 -
 .../vendor/listen/lib/listen/adapters/linux.rb     |  113 -
 .../vendor/listen/lib/listen/adapters/polling.rb   |   67 -
 .../vendor/listen/lib/listen/adapters/windows.rb   |   87 -
 .../vendor/listen/lib/listen/dependency_manager.rb |  126 -
 .../vendor/listen/lib/listen/directory_record.rb   |  371 --
 .../vendor/listen/lib/listen/listener.rb           |  225 --
 .../vendor/listen/lib/listen/multi_listener.rb     |  143 -
 .../vendor/listen/lib/listen/turnstile.rb          |   28 -
 .../vendor/listen/lib/listen/version.rb            |    3 -
 .../gems/sass-3.2.12/vendor/listen/listen.gemspec  |   22 -
 .../vendor/listen/spec/listen/adapter_spec.rb      |  183 -
 .../listen/spec/listen/adapters/polling_spec.rb    |   68 -
 .../listen/spec/listen/dependency_manager_spec.rb  |  107 -
 .../listen/spec/listen/directory_record_spec.rb    | 1225 ------
 .../vendor/listen/spec/listen/listener_spec.rb     |  169 -
 .../listen/spec/listen/multi_listener_spec.rb      |  174 -
 .../sass-3.2.12/vendor/listen/spec/listen_spec.rb  |   73 -
 .../sass-3.2.12/vendor/listen/spec/spec_helper.rb  |   21 -
 .../vendor/listen/spec/support/adapter_helper.rb   |  629 ---
 .../listen/spec/support/directory_record_helper.rb |   55 -
 .../vendor/listen/spec/support/listeners_helper.rb |  156 -
 .../css/gems/{sass-3.2.12 => sass-3.4.9}/.yardopts |    0
 backends/css/gems/sass-3.4.9/CONTRIBUTING          |    3 +
 backends/css/gems/sass-3.4.9/MIT-LICENSE           |   20 +
 backends/css/gems/sass-3.4.9/README.md             |  221 ++
 .../css/gems/{sass-3.2.12 => sass-3.4.9}/REVISION  |    0
 backends/css/gems/sass-3.4.9/Rakefile              |  370 ++
 backends/css/gems/sass-3.4.9/VERSION               |    1 +
 backends/css/gems/sass-3.4.9/VERSION_DATE          |    1 +
 backends/css/gems/sass-3.4.9/VERSION_NAME          |    1 +
 backends/css/gems/sass-3.4.9/bin/sass              |   13 +
 backends/css/gems/sass-3.4.9/bin/sass-convert      |   12 +
 backends/css/gems/sass-3.4.9/bin/scss              |   13 +
 .../extra/update_watch.rb                          |    0
 .../css/gems/{sass-3.2.12 => sass-3.4.9}/init.rb   |    0
 backends/css/gems/sass-3.4.9/lib/sass.rb           |  102 +
 .../lib/sass/cache_stores.rb                       |    0
 .../gems/sass-3.4.9/lib/sass/cache_stores/base.rb  |   88 +
 .../gems/sass-3.4.9/lib/sass/cache_stores/chain.rb |   34 +
 .../sass-3.4.9/lib/sass/cache_stores/filesystem.rb |   60 +
 .../sass-3.4.9/lib/sass/cache_stores/memory.rb     |   47 +
 .../gems/sass-3.4.9/lib/sass/cache_stores/null.rb  |   25 +
 backends/css/gems/sass-3.4.9/lib/sass/callbacks.rb |   67 +
 backends/css/gems/sass-3.4.9/lib/sass/css.rb       |  407 ++
 backends/css/gems/sass-3.4.9/lib/sass/engine.rb    | 1182 ++++++
 .../css/gems/sass-3.4.9/lib/sass/environment.rb    |  208 +
 backends/css/gems/sass-3.4.9/lib/sass/error.rb     |  198 +
 backends/css/gems/sass-3.4.9/lib/sass/exec.rb      |    9 +
 backends/css/gems/sass-3.4.9/lib/sass/exec/base.rb |  199 +
 .../gems/sass-3.4.9/lib/sass/exec/sass_convert.rb  |  269 ++
 .../css/gems/sass-3.4.9/lib/sass/exec/sass_scss.rb |  444 +++
 backends/css/gems/sass-3.4.9/lib/sass/features.rb  |   47 +
 .../lib/sass/importers.rb                          |    0
 .../css/gems/sass-3.4.9/lib/sass/importers/base.rb |  182 +
 .../sass-3.4.9/lib/sass/importers/filesystem.rb    |  217 ++
 backends/css/gems/sass-3.4.9/lib/sass/logger.rb    |   12 +
 .../css/gems/sass-3.4.9/lib/sass/logger/base.rb    |   30 +
 .../gems/sass-3.4.9/lib/sass/logger/log_level.rb   |   45 +
 backends/css/gems/sass-3.4.9/lib/sass/media.rb     |  210 +
 backends/css/gems/sass-3.4.9/lib/sass/plugin.rb    |  133 +
 .../gems/sass-3.4.9/lib/sass/plugin/compiler.rb    |  571 +++
 .../sass-3.4.9/lib/sass/plugin/configuration.rb    |  118 +
 .../lib/sass/plugin/generic.rb                     |    0
 .../css/gems/sass-3.4.9/lib/sass/plugin/merb.rb    |   48 +
 .../lib/sass/plugin/rack.rb                        |    0
 .../lib/sass/plugin/rails.rb                       |    0
 .../lib/sass/plugin/staleness_checker.rb           |  199 +
 backends/css/gems/sass-3.4.9/lib/sass/railtie.rb   |   10 +
 backends/css/gems/sass-3.4.9/lib/sass/repl.rb      |   57 +
 .../{sass-3.2.12 => sass-3.4.9}/lib/sass/root.rb   |    0
 backends/css/gems/sass-3.4.9/lib/sass/script.rb    |   66 +
 .../gems/sass-3.4.9/lib/sass/script/css_lexer.rb   |   33 +
 .../gems/sass-3.4.9/lib/sass/script/css_parser.rb  |   34 +
 .../gems/sass-3.4.9/lib/sass/script/functions.rb   | 2646 +++++++++++++
 .../css/gems/sass-3.4.9/lib/sass/script/lexer.rb   |  453 +++
 .../css/gems/sass-3.4.9/lib/sass/script/parser.rb  |  638 ++++
 .../css/gems/sass-3.4.9/lib/sass/script/tree.rb    |   16 +
 .../sass-3.4.9/lib/sass/script/tree/funcall.rb     |  306 ++
 .../lib/sass/script/tree/interpolation.rb          |  118 +
 .../lib/sass/script/tree/list_literal.rb           |   77 +
 .../sass-3.4.9/lib/sass/script/tree/literal.rb     |   45 +
 .../sass-3.4.9/lib/sass/script/tree/map_literal.rb |   64 +
 .../gems/sass-3.4.9/lib/sass/script/tree/node.rb   |  109 +
 .../sass-3.4.9/lib/sass/script/tree/operation.rb   |  115 +
 .../sass-3.4.9/lib/sass/script/tree/selector.rb    |   26 +
 .../lib/sass/script/tree/string_interpolation.rb   |  104 +
 .../lib/sass/script/tree/unary_operation.rb        |   69 +
 .../sass-3.4.9/lib/sass/script/tree/variable.rb    |   57 +
 .../css/gems/sass-3.4.9/lib/sass/script/value.rb   |   11 +
 .../sass-3.4.9/lib/sass/script/value/arg_list.rb   |   36 +
 .../gems/sass-3.4.9/lib/sass/script/value/base.rb  |  240 ++
 .../gems/sass-3.4.9/lib/sass/script/value/bool.rb  |   35 +
 .../gems/sass-3.4.9/lib/sass/script/value/color.rb |  680 ++++
 .../sass-3.4.9/lib/sass/script/value/helpers.rb    |  262 ++
 .../gems/sass-3.4.9/lib/sass/script/value/list.rb  |  113 +
 .../gems/sass-3.4.9/lib/sass/script/value/map.rb   |   70 +
 .../gems/sass-3.4.9/lib/sass/script/value/null.rb  |   44 +
 .../sass-3.4.9/lib/sass/script/value/number.rb     |  530 +++
 .../sass-3.4.9/lib/sass/script/value/string.rb     |   97 +
 .../{sass-3.2.12 => sass-3.4.9}/lib/sass/scss.rb   |    0
 .../gems/sass-3.4.9/lib/sass/scss/css_parser.rb    |   42 +
 .../css/gems/sass-3.4.9/lib/sass/scss/parser.rb    | 1211 ++++++
 backends/css/gems/sass-3.4.9/lib/sass/scss/rx.rb   |  141 +
 .../lib/sass/scss/script_lexer.rb                  |    0
 .../lib/sass/scss/script_parser.rb                 |    0
 .../gems/sass-3.4.9/lib/sass/scss/static_parser.rb |  368 ++
 backends/css/gems/sass-3.4.9/lib/sass/selector.rb  |  326 ++
 .../lib/sass/selector/abstract_sequence.rb         |  109 +
 .../sass-3.4.9/lib/sass/selector/comma_sequence.rb |  177 +
 .../gems/sass-3.4.9/lib/sass/selector/pseudo.rb    |  266 ++
 .../gems/sass-3.4.9/lib/sass/selector/sequence.rb  |  618 +++
 .../gems/sass-3.4.9/lib/sass/selector/simple.rb    |  117 +
 .../lib/sass/selector/simple_sequence.rb           |  344 ++
 backends/css/gems/sass-3.4.9/lib/sass/shared.rb    |   76 +
 .../css/gems/sass-3.4.9/lib/sass/source/map.rb     |  211 +
 .../gems/sass-3.4.9/lib/sass/source/position.rb    |   39 +
 .../css/gems/sass-3.4.9/lib/sass/source/range.rb   |   41 +
 backends/css/gems/sass-3.4.9/lib/sass/stack.rb     |  120 +
 backends/css/gems/sass-3.4.9/lib/sass/supports.rb  |  227 ++
 .../gems/sass-3.4.9/lib/sass/tree/at_root_node.rb  |   83 +
 .../gems/sass-3.4.9/lib/sass/tree/charset_node.rb  |   22 +
 .../gems/sass-3.4.9/lib/sass/tree/comment_node.rb  |   82 +
 .../lib/sass/tree/content_node.rb                  |    0
 .../sass-3.4.9/lib/sass/tree/css_import_node.rb    |   60 +
 .../gems/sass-3.4.9/lib/sass/tree/debug_node.rb    |   18 +
 .../sass-3.4.9/lib/sass/tree/directive_node.rb     |   59 +
 .../css/gems/sass-3.4.9/lib/sass/tree/each_node.rb |   24 +
 .../gems/sass-3.4.9/lib/sass/tree/error_node.rb    |   18 +
 .../gems/sass-3.4.9/lib/sass/tree/extend_node.rb   |   43 +
 .../css/gems/sass-3.4.9/lib/sass/tree/for_node.rb  |   36 +
 .../gems/sass-3.4.9/lib/sass/tree/function_node.rb |   39 +
 .../css/gems/sass-3.4.9/lib/sass/tree/if_node.rb   |   52 +
 .../gems/sass-3.4.9/lib/sass/tree/import_node.rb   |   74 +
 .../sass-3.4.9/lib/sass/tree/keyframe_rule_node.rb |   15 +
 .../gems/sass-3.4.9/lib/sass/tree/media_node.rb    |   48 +
 .../sass-3.4.9/lib/sass/tree/mixin_def_node.rb     |   38 +
 .../gems/sass-3.4.9/lib/sass/tree/mixin_node.rb    |   52 +
 backends/css/gems/sass-3.4.9/lib/sass/tree/node.rb |  238 ++
 .../css/gems/sass-3.4.9/lib/sass/tree/prop_node.rb |  171 +
 .../gems/sass-3.4.9/lib/sass/tree/return_node.rb   |   19 +
 .../css/gems/sass-3.4.9/lib/sass/tree/root_node.rb |   44 +
 .../css/gems/sass-3.4.9/lib/sass/tree/rule_node.rb |  145 +
 .../gems/sass-3.4.9/lib/sass/tree/supports_node.rb |   38 +
 .../gems/sass-3.4.9/lib/sass/tree/trace_node.rb    |   33 +
 .../gems/sass-3.4.9/lib/sass/tree/variable_node.rb |   36 +
 .../gems/sass-3.4.9/lib/sass/tree/visitors/base.rb |   72 +
 .../lib/sass/tree/visitors/check_nesting.rb        |  177 +
 .../sass-3.4.9/lib/sass/tree/visitors/convert.rb   |  334 ++
 .../sass-3.4.9/lib/sass/tree/visitors/cssize.rb    |  373 ++
 .../sass-3.4.9/lib/sass/tree/visitors/deep_copy.rb |  107 +
 .../sass-3.4.9/lib/sass/tree/visitors/extend.rb    |   68 +
 .../sass-3.4.9/lib/sass/tree/visitors/perform.rb   |  547 +++
 .../lib/sass/tree/visitors/set_options.rb          |  139 +
 .../sass-3.4.9/lib/sass/tree/visitors/to_css.rb    |  381 ++
 .../css/gems/sass-3.4.9/lib/sass/tree/warn_node.rb |   18 +
 .../gems/sass-3.4.9/lib/sass/tree/while_node.rb    |   18 +
 backends/css/gems/sass-3.4.9/lib/sass/util.rb      | 1376 +++++++
 .../lib/sass/util/cross_platform_random.rb         |   19 +
 .../lib/sass/util/multibyte_string_scanner.rb      |  157 +
 .../sass-3.4.9/lib/sass/util/normalized_map.rb     |  130 +
 .../gems/sass-3.4.9/lib/sass/util/ordered_hash.rb  |  192 +
 .../gems/sass-3.4.9/lib/sass/util/subset_map.rb    |  110 +
 backends/css/gems/sass-3.4.9/lib/sass/util/test.rb |    9 +
 backends/css/gems/sass-3.4.9/lib/sass/version.rb   |  124 +
 .../gems/{sass-3.2.12 => sass-3.4.9}/rails/init.rb |    0
 .../css/gems/sass-3.4.9/test/sass/cache_test.rb    |  131 +
 .../gems/sass-3.4.9/test/sass/callbacks_test.rb    |   61 +
 .../css/gems/sass-3.4.9/test/sass/compiler_test.rb |  236 ++
 .../gems/sass-3.4.9/test/sass/conversion_test.rb   | 2069 ++++++++++
 .../css/gems/sass-3.4.9/test/sass/css2sass_test.rb |  477 +++
 .../test/sass/data/hsl-rgb.txt                     |    0
 .../css/gems/sass-3.4.9/test/sass/encoding_test.rb |  219 ++
 .../css/gems/sass-3.4.9/test/sass/engine_test.rb   | 3301 ++++++++++++++++
 .../css/gems/sass-3.4.9/test/sass/exec_test.rb     |   86 +
 .../css/gems/sass-3.4.9/test/sass/extend_test.rb   | 1687 ++++++++
 .../test_staleness_check_across_importers.css      |    0
 .../test_staleness_check_across_importers.scss     |    0
 .../gems/sass-3.4.9/test/sass/functions_test.rb    | 1954 ++++++++++
 .../css/gems/sass-3.4.9/test/sass/importer_test.rb |  421 ++
 .../css/gems/sass-3.4.9/test/sass/logger_test.rb   |   58 +
 .../test/sass/mock_importer.rb                     |    0
 .../test/sass/more_results/more1.css               |    0
 .../sass/more_results/more1_with_line_comments.css |    0
 .../test/sass/more_results/more_import.css         |   29 +
 .../test/sass/more_templates/_more_partial.sass    |    0
 .../test/sass/more_templates/more1.sass            |    0
 .../test/sass/more_templates/more_import.sass      |    0
 .../css/gems/sass-3.4.9/test/sass/plugin_test.rb   |  556 +++
 .../test/sass/results/alt.css                      |    0
 .../test/sass/results/basic.css                    |    0
 .../test/sass/results/cached_import_option.css     |    0
 .../gems/sass-3.4.9/test/sass/results/compact.css  |    5 +
 .../gems/sass-3.4.9/test/sass/results/complex.css  |   86 +
 .../test/sass/results/compressed.css               |    0
 .../gems/sass-3.4.9/test/sass/results/expanded.css |   19 +
 .../test/sass/results/filename_fn.css              |    0
 .../test/sass/results/if.css                       |    0
 .../gems/sass-3.4.9/test/sass/results/import.css   |   31 +
 .../test/sass/results/import_charset.css           |    0
 .../test/sass/results/import_charset_1_8.css       |    0
 .../test/sass/results/import_charset_ibm866.css}   |    0
 .../test/sass/results/import_content.css           |    0
 .../test/sass/results/line_numbers.css             |    0
 .../gems/sass-3.4.9/test/sass/results/mixins.css   |   95 +
 .../test/sass/results/multiline.css                |    0
 .../gems/sass-3.4.9/test/sass/results/nested.css   |   22 +
 .../test/sass/results/options.css                  |    0
 .../sass-3.4.9/test/sass/results/parent_ref.css    |   13 +
 .../gems/sass-3.4.9/test/sass/results/script.css   |   16 +
 .../sass-3.4.9/test/sass/results/scss_import.css   |   31 +
 .../test/sass/results/scss_importee.css            |    0
 .../results/subdir/nested_subdir/nested_subdir.css |    0
 .../test/sass/results/subdir/subdir.css            |    0
 .../test/sass/results/units.css                    |    0
 .../test/sass/results/warn.css                     |    0
 .../test/sass/results/warn_imported.css            |    0
 .../sass-3.4.9/test/sass/script_conversion_test.rb |  333 ++
 .../css/gems/sass-3.4.9/test/sass/script_test.rb   | 1170 ++++++
 .../css/gems/sass-3.4.9/test/sass/scss/css_test.rb | 1256 ++++++
 .../css/gems/sass-3.4.9/test/sass/scss/rx_test.rb  |  156 +
 .../gems/sass-3.4.9/test/sass/scss/scss_test.rb    | 4008 ++++++++++++++++++++
 .../test/sass/scss/test_helper.rb                  |    0
 .../gems/sass-3.4.9/test/sass/source_map_test.rb   |  977 +++++
 .../sass-3.4.9/test/sass/superselector_test.rb     |  210 +
 .../templates/_cached_import_option_partial.scss   |    0
 .../test/sass/templates/_double_import_loop2.sass  |    0
 .../test/sass/templates/_filename_fn_import.scss   |    0
 .../sass/templates/_imported_charset_ibm866.sass   |    0
 .../sass/templates/_imported_charset_utf8.sass     |    0
 .../test/sass/templates/_imported_content.sass     |    0
 .../test/sass/templates/_partial.sass              |    0
 .../templates/_same_name_different_partiality.scss |    0
 .../test/sass/templates/alt.sass                   |    0
 .../test/sass/templates/basic.sass                 |    0
 .../test/sass/templates/bork1.sass                 |    0
 .../test/sass/templates/bork2.sass                 |    0
 .../test/sass/templates/bork3.sass                 |    0
 .../test/sass/templates/bork4.sass                 |    0
 .../test/sass/templates/bork5.sass                 |    0
 .../test/sass/templates/cached_import_option.scss  |    0
 .../test/sass/templates/compact.sass               |    0
 .../test/sass/templates/complex.sass               |    0
 .../test/sass/templates/compressed.sass            |    0
 .../test/sass/templates/double_import_loop1.sass   |    0
 .../test/sass/templates/expanded.sass              |    0
 .../test/sass/templates/filename_fn.scss           |    0
 .../test/sass/templates/if.sass                    |    0
 .../test/sass/templates/import.sass                |    0
 .../test/sass/templates/import_charset.sass        |    0
 .../test/sass/templates/import_charset_1_8.sass    |    0
 .../test/sass/templates/import_charset_ibm866.sass |    0
 .../test/sass/templates/import_content.sass        |    0
 .../test/sass/templates/importee.less              |    0
 .../test/sass/templates/importee.sass              |    0
 .../test/sass/templates/line_numbers.sass          |    0
 .../test/sass/templates/mixin_bork.sass            |    0
 .../test/sass/templates/mixins.sass                |    0
 .../test/sass/templates/multiline.sass             |    0
 .../test/sass/templates/nested.sass                |    0
 .../test/sass/templates/nested_bork1.sass          |    0
 .../test/sass/templates/nested_bork2.sass          |    0
 .../test/sass/templates/nested_bork3.sass          |    0
 .../test/sass/templates/nested_bork4.sass          |    0
 .../test/sass/templates/nested_import.sass         |    0
 .../test/sass/templates/nested_mixin_bork.sass     |    0
 .../test/sass/templates/options.sass               |    0
 .../test/sass/templates/parent_ref.sass            |    0
 .../sass/templates/same_name_different_ext.sass    |    0
 .../sass/templates/same_name_different_ext.scss    |    0
 .../templates/same_name_different_partiality.scss  |    0
 .../test/sass/templates/script.sass                |    0
 .../test/sass/templates/scss_import.scss           |   12 +
 .../test/sass/templates/scss_importee.scss         |    0
 .../test/sass/templates/single_import_loop.sass    |    0
 .../test/sass/templates/subdir/import_up1.scss     |    1 +
 .../test/sass/templates/subdir/import_up2.scss     |    1 +
 .../subdir/nested_subdir/_nested_partial.sass      |    0
 .../subdir/nested_subdir/nested_subdir.sass        |    0
 .../test/sass/templates/subdir/subdir.sass         |    0
 .../test/sass/templates/units.sass                 |    0
 .../test/sass/templates/warn.sass                  |    0
 .../test/sass/templates/warn_imported.sass         |    0
 .../css/gems/sass-3.4.9/test/sass/test_helper.rb   |    8 +
 .../sass/util/multibyte_string_scanner_test.rb     |  147 +
 .../test/sass/util/normalized_map_test.rb          |   51 +
 .../sass-3.4.9/test/sass/util/subset_map_test.rb   |   91 +
 .../css/gems/sass-3.4.9/test/sass/util_test.rb     |  471 +++
 .../sass-3.4.9/test/sass/value_helpers_test.rb     |  179 +
 backends/css/gems/sass-3.4.9/test/test_helper.rb   |  109 +
 .../css/gems/sass-3.4.9/vendor/listen/CHANGELOG.md |    1 +
 .../vendor/listen/CONTRIBUTING.md                  |    0
 backends/css/gems/sass-3.4.9/vendor/listen/Gemfile |   20 +
 .../vendor/listen/Guardfile                        |    0
 .../vendor/listen/LICENSE                          |    0
 .../css/gems/sass-3.4.9/vendor/listen/README.md    |  349 ++
 .../css/gems/sass-3.4.9/vendor/listen/Rakefile     |    5 +
 .../vendor/listen/Vagrantfile                      |    0
 .../gems/sass-3.4.9/vendor/listen/lib/listen.rb    |   54 +
 .../sass-3.4.9/vendor/listen/lib/listen/adapter.rb |  327 ++
 .../vendor/listen/lib/listen/adapters/bsd.rb       |   75 +
 .../vendor/listen/lib/listen/adapters/darwin.rb    |   48 +
 .../vendor/listen/lib/listen/adapters/linux.rb     |   81 +
 .../vendor/listen/lib/listen/adapters/polling.rb   |   58 +
 .../vendor/listen/lib/listen/adapters/windows.rb   |   91 +
 .../vendor/listen/lib/listen/directory_record.rb   |  406 ++
 .../vendor/listen/lib/listen/listener.rb           |  323 ++
 .../vendor/listen/lib/listen/turnstile.rb          |   32 +
 .../sass-3.4.9/vendor/listen/lib/listen/version.rb |    3 +
 .../gems/sass-3.4.9/vendor/listen/listen.gemspec   |   28 +
 .../vendor/listen/spec/listen/adapter_spec.rb      |  149 +
 .../vendor/listen/spec/listen/adapters/bsd_spec.rb |    0
 .../listen/spec/listen/adapters/darwin_spec.rb     |    0
 .../listen/spec/listen/adapters/linux_spec.rb      |    0
 .../listen/spec/listen/adapters/polling_spec.rb    |   68 +
 .../listen/spec/listen/adapters/windows_spec.rb    |    0
 .../listen/spec/listen/directory_record_spec.rb    | 1250 ++++++
 .../vendor/listen/spec/listen/listener_spec.rb     |  258 ++
 .../vendor/listen/spec/listen/turnstile_spec.rb    |    0
 .../sass-3.4.9/vendor/listen/spec/listen_spec.rb   |   67 +
 .../sass-3.4.9/vendor/listen/spec/spec_helper.rb   |   25 +
 .../vendor/listen/spec/support/adapter_helper.rb   |  666 ++++
 .../listen/spec/support/directory_record_helper.rb |   57 +
 .../vendor/listen/spec/support/fixtures_helper.rb  |    0
 .../vendor/listen/spec/support/listeners_helper.rb |  179 +
 .../vendor/listen/spec/support/platform_helper.rb  |    0
 476 files changed, 49113 insertions(+), 37166 deletions(-)
---
diff --git a/backends/css/app.rb b/backends/css/app.rb
index 021cc79..fbc0292 100644
--- a/backends/css/app.rb
+++ b/backends/css/app.rb
@@ -17,7 +17,7 @@
 
 require 'gnome/codeassistance/transport'
 
-oursass = File.join(File.dirname(__FILE__), 'gems', 'sass-3.2.12', 'init.rb')
+oursass = File.join(File.dirname(__FILE__), 'gems', 'sass-3.4.9', 'init.rb')
 
 if FileTest.exist?(oursass)
     require oursass
diff --git a/backends/css/deps.mf b/backends/css/deps.mf
index b0ee082..e2bad40 100644
--- a/backends/css/deps.mf
+++ b/backends/css/deps.mf
@@ -1,436 +1,477 @@
 if RUBY_SASS
 else
-csssass_gems_sass_3_2_12_test_sass_results_subdirdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/test/sass/results/subdir
-csssass_gems_sass_3_2_12_test_sass_results_subdir_DATA = \
-       backends/css/gems/sass-3.2.12/test/sass/results/subdir/subdir.css
-
-csssass_gems_sass_3_2_12_lib_sass_tree_visitorsdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/lib/sass/tree/visitors
-csssass_gems_sass_3_2_12_lib_sass_tree_visitors_DATA = \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/visitors/base.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/visitors/check_nesting.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/visitors/convert.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/visitors/cssize.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/visitors/deep_copy.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/visitors/extend.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/visitors/perform.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/visitors/set_options.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/visitors/to_css.rb
-
-csssass_gems_sass_3_2_12_test_sass_scssdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/test/sass/scss
-csssass_gems_sass_3_2_12_test_sass_scss_DATA = \
-       backends/css/gems/sass-3.2.12/test/sass/scss/css_test.rb \
-       backends/css/gems/sass-3.2.12/test/sass/scss/rx_test.rb \
-       backends/css/gems/sass-3.2.12/test/sass/scss/scss_test.rb \
-       backends/css/gems/sass-3.2.12/test/sass/scss/test_helper.rb
-
-csssass_gems_sass_3_2_12_test_sassdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/test/sass
-csssass_gems_sass_3_2_12_test_sass_DATA = \
-       backends/css/gems/sass-3.2.12/test/sass/cache_test.rb \
-       backends/css/gems/sass-3.2.12/test/sass/callbacks_test.rb \
-       backends/css/gems/sass-3.2.12/test/sass/conversion_test.rb \
-       backends/css/gems/sass-3.2.12/test/sass/css2sass_test.rb \
-       backends/css/gems/sass-3.2.12/test/sass/engine_test.rb \
-       backends/css/gems/sass-3.2.12/test/sass/exec_test.rb \
-       backends/css/gems/sass-3.2.12/test/sass/extend_test.rb \
-       backends/css/gems/sass-3.2.12/test/sass/functions_test.rb \
-       backends/css/gems/sass-3.2.12/test/sass/importer_test.rb \
-       backends/css/gems/sass-3.2.12/test/sass/logger_test.rb \
-       backends/css/gems/sass-3.2.12/test/sass/mock_importer.rb \
-       backends/css/gems/sass-3.2.12/test/sass/plugin_test.rb \
-       backends/css/gems/sass-3.2.12/test/sass/script_conversion_test.rb \
-       backends/css/gems/sass-3.2.12/test/sass/script_test.rb \
-       backends/css/gems/sass-3.2.12/test/sass/test_helper.rb \
-       backends/css/gems/sass-3.2.12/test/sass/util_test.rb
-
-csssass_gems_sass_3_2_12_vendor_listen_spec_listen_adaptersdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/vendor/listen/spec/listen/adapters
-csssass_gems_sass_3_2_12_vendor_listen_spec_listen_adapters_DATA = \
-       backends/css/gems/sass-3.2.12/vendor/listen/spec/listen/adapters/bsd_spec.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/spec/listen/adapters/darwin_spec.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/spec/listen/adapters/linux_spec.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/spec/listen/adapters/polling_spec.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/spec/listen/adapters/windows_spec.rb
-
-csssass_gems_sass_3_2_12_test_sass_templates_subdir_nested_subdirdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/test/sass/templates/subdir/nested_subdir
-csssass_gems_sass_3_2_12_test_sass_templates_subdir_nested_subdir_DATA = \
-       backends/css/gems/sass-3.2.12/test/sass/templates/subdir/nested_subdir/_nested_partial.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/subdir/nested_subdir/nested_subdir.sass
-
-csssass_gems_sass_3_2_12dir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12
-csssass_gems_sass_3_2_12_DATA = \
-       backends/css/gems/sass-3.2.12/.yardopts \
-       backends/css/gems/sass-3.2.12/CONTRIBUTING \
-       backends/css/gems/sass-3.2.12/MIT-LICENSE \
-       backends/css/gems/sass-3.2.12/README.md \
-       backends/css/gems/sass-3.2.12/REVISION \
-       backends/css/gems/sass-3.2.12/Rakefile \
-       backends/css/gems/sass-3.2.12/VERSION \
-       backends/css/gems/sass-3.2.12/VERSION_DATE \
-       backends/css/gems/sass-3.2.12/VERSION_NAME \
-       backends/css/gems/sass-3.2.12/init.rb
-
-csssass_gems_sass_3_2_12_test_sass_templates_subdirdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/test/sass/templates/subdir
-csssass_gems_sass_3_2_12_test_sass_templates_subdir_DATA = \
-       backends/css/gems/sass-3.2.12/test/sass/templates/subdir/subdir.sass
-
-csssass_gems_sass_3_2_12_test_sass_datadir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/test/sass/data
-csssass_gems_sass_3_2_12_test_sass_data_DATA = \
-       backends/css/gems/sass-3.2.12/test/sass/data/hsl-rgb.txt
-
-csssass_gems_sass_3_2_12_vendor_listen_spec_supportdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/vendor/listen/spec/support
-csssass_gems_sass_3_2_12_vendor_listen_spec_support_DATA = \
-       backends/css/gems/sass-3.2.12/vendor/listen/spec/support/adapter_helper.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/spec/support/directory_record_helper.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/spec/support/fixtures_helper.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/spec/support/listeners_helper.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/spec/support/platform_helper.rb
-
-csssass_gems_sass_3_2_12_libdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/lib
-csssass_gems_sass_3_2_12_lib_DATA = \
-       backends/css/gems/sass-3.2.12/lib/sass.rb
-
-csssass_gems_sass_3_2_12_lib_sass_scriptdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/lib/sass/script
-csssass_gems_sass_3_2_12_lib_sass_script_DATA = \
-       backends/css/gems/sass-3.2.12/lib/sass/script/arg_list.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/script/bool.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/script/color.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/script/css_lexer.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/script/css_parser.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/script/funcall.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/script/functions.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/script/interpolation.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/script/lexer.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/script/list.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/script/literal.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/script/node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/script/null.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/script/number.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/script/operation.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/script/parser.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/script/string.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/script/string_interpolation.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/script/unary_operation.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/script/variable.rb
-
-csssass_gems_sass_3_2_12_vendor_listen_lib_listendir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/vendor/listen/lib/listen
-csssass_gems_sass_3_2_12_vendor_listen_lib_listen_DATA = \
-       backends/css/gems/sass-3.2.12/vendor/listen/lib/listen/adapter.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/lib/listen/dependency_manager.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/lib/listen/directory_record.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/lib/listen/listener.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/lib/listen/multi_listener.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/lib/listen/turnstile.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/lib/listen/version.rb
-
-csssass_gems_sass_3_2_12_vendor_listendir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/vendor/listen
-csssass_gems_sass_3_2_12_vendor_listen_DATA = \
-       backends/css/gems/sass-3.2.12/vendor/listen/CHANGELOG.md \
-       backends/css/gems/sass-3.2.12/vendor/listen/CONTRIBUTING.md \
-       backends/css/gems/sass-3.2.12/vendor/listen/Gemfile \
-       backends/css/gems/sass-3.2.12/vendor/listen/Guardfile \
-       backends/css/gems/sass-3.2.12/vendor/listen/LICENSE \
-       backends/css/gems/sass-3.2.12/vendor/listen/README.md \
-       backends/css/gems/sass-3.2.12/vendor/listen/Rakefile \
-       backends/css/gems/sass-3.2.12/vendor/listen/Vagrantfile \
-       backends/css/gems/sass-3.2.12/vendor/listen/listen.gemspec
-
-csssass_gems_sass_3_2_12_test_sass_templatesdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/test/sass/templates
-csssass_gems_sass_3_2_12_test_sass_templates_DATA = \
-       backends/css/gems/sass-3.2.12/test/sass/templates/_cached_import_option_partial.scss \
-       backends/css/gems/sass-3.2.12/test/sass/templates/_double_import_loop2.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/_filename_fn_import.scss \
-       backends/css/gems/sass-3.2.12/test/sass/templates/_imported_charset_ibm866.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/_imported_charset_utf8.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/_imported_content.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/_partial.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/_same_name_different_partiality.scss \
-       backends/css/gems/sass-3.2.12/test/sass/templates/alt.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/basic.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/bork1.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/bork2.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/bork3.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/bork4.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/bork5.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/cached_import_option.scss \
-       backends/css/gems/sass-3.2.12/test/sass/templates/compact.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/complex.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/compressed.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/double_import_loop1.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/expanded.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/filename_fn.scss \
-       backends/css/gems/sass-3.2.12/test/sass/templates/if.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/import.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/import_charset.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/import_charset_1_8.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/import_charset_ibm866.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/import_content.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/importee.less \
-       backends/css/gems/sass-3.2.12/test/sass/templates/importee.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/line_numbers.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/mixin_bork.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/mixins.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/multiline.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/nested.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/nested_bork1.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/nested_bork2.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/nested_bork3.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/nested_bork4.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/nested_import.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/nested_mixin_bork.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/options.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/parent_ref.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/same_name_different_ext.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/same_name_different_ext.scss \
-       backends/css/gems/sass-3.2.12/test/sass/templates/same_name_different_partiality.scss \
-       backends/css/gems/sass-3.2.12/test/sass/templates/script.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/scss_import.scss \
-       backends/css/gems/sass-3.2.12/test/sass/templates/scss_importee.scss \
-       backends/css/gems/sass-3.2.12/test/sass/templates/single_import_loop.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/units.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/warn.sass \
-       backends/css/gems/sass-3.2.12/test/sass/templates/warn_imported.sass
-
-csssass_gems_sass_3_2_12_railsdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/rails
-csssass_gems_sass_3_2_12_rails_DATA = \
-       backends/css/gems/sass-3.2.12/rails/init.rb
-
-csssass_gems_sass_3_2_12_vendor_listen_specdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/vendor/listen/spec
-csssass_gems_sass_3_2_12_vendor_listen_spec_DATA = \
-       backends/css/gems/sass-3.2.12/vendor/listen/spec/listen_spec.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/spec/spec_helper.rb
-
-csssass_gems_sass_3_2_12_extradir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/extra
-csssass_gems_sass_3_2_12_extra_DATA = \
-       backends/css/gems/sass-3.2.12/extra/update_watch.rb
-
-csssass_gems_sass_3_2_12_test_sass_more_resultsdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/test/sass/more_results
-csssass_gems_sass_3_2_12_test_sass_more_results_DATA = \
-       backends/css/gems/sass-3.2.12/test/sass/more_results/more1.css \
-       backends/css/gems/sass-3.2.12/test/sass/more_results/more1_with_line_comments.css \
-       backends/css/gems/sass-3.2.12/test/sass/more_results/more_import.css
-
-csssass_gems_sass_3_2_12_vendor_listen_spec_listendir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/vendor/listen/spec/listen
-csssass_gems_sass_3_2_12_vendor_listen_spec_listen_DATA = \
-       backends/css/gems/sass-3.2.12/vendor/listen/spec/listen/adapter_spec.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/spec/listen/dependency_manager_spec.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/spec/listen/directory_record_spec.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/spec/listen/listener_spec.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/spec/listen/multi_listener_spec.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/spec/listen/turnstile_spec.rb
-
-csssass_gems_sass_3_2_12_test_sass_utildir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/test/sass/util
-csssass_gems_sass_3_2_12_test_sass_util_DATA = \
-       backends/css/gems/sass-3.2.12/test/sass/util/multibyte_string_scanner_test.rb \
-       backends/css/gems/sass-3.2.12/test/sass/util/subset_map_test.rb
-
-csssass_gems_sass_3_2_12_test_sass_resultsdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/test/sass/results
-csssass_gems_sass_3_2_12_test_sass_results_DATA = \
-       backends/css/gems/sass-3.2.12/test/sass/results/alt.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/basic.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/cached_import_option.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/compact.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/complex.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/compressed.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/expanded.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/filename_fn.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/if.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/import.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/import_charset.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/import_charset_1_8.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/import_charset_ibm866.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/import_content.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/line_numbers.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/mixins.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/multiline.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/nested.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/options.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/parent_ref.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/script.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/scss_import.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/scss_importee.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/units.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/warn.css \
-       backends/css/gems/sass-3.2.12/test/sass/results/warn_imported.css
-
-csssass_gems_sass_3_2_12_lib_sass_treedir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/lib/sass/tree
-csssass_gems_sass_3_2_12_lib_sass_tree_DATA = \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/charset_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/comment_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/content_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/css_import_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/debug_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/directive_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/each_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/extend_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/for_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/function_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/if_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/import_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/media_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/mixin_def_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/mixin_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/prop_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/return_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/root_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/rule_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/supports_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/trace_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/variable_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/warn_node.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/tree/while_node.rb
-
-csssass_gems_sass_3_2_12_test_sass_results_subdir_nested_subdirdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/test/sass/results/subdir/nested_subdir
-csssass_gems_sass_3_2_12_test_sass_results_subdir_nested_subdir_DATA = \
-       backends/css/gems/sass-3.2.12/test/sass/results/subdir/nested_subdir/nested_subdir.css
-
-csssass_gems_sass_3_2_12_lib_sass_cache_storesdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/lib/sass/cache_stores
-csssass_gems_sass_3_2_12_lib_sass_cache_stores_DATA = \
-       backends/css/gems/sass-3.2.12/lib/sass/cache_stores/base.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/cache_stores/chain.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/cache_stores/filesystem.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/cache_stores/memory.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/cache_stores/null.rb
-
-csssass_gems_sass_3_2_12_lib_sass_utildir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/lib/sass/util
-csssass_gems_sass_3_2_12_lib_sass_util_DATA = \
-       backends/css/gems/sass-3.2.12/lib/sass/util/multibyte_string_scanner.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/util/subset_map.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/util/test.rb
-
-csssass_gems_sass_3_2_12_lib_sass_loggerdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/lib/sass/logger
-csssass_gems_sass_3_2_12_lib_sass_logger_DATA = \
-       backends/css/gems/sass-3.2.12/lib/sass/logger/base.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/logger/log_level.rb
-
-csssass_gems_sass_3_2_12_test_sass_more_templatesdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/test/sass/more_templates
-csssass_gems_sass_3_2_12_test_sass_more_templates_DATA = \
-       backends/css/gems/sass-3.2.12/test/sass/more_templates/_more_partial.sass \
-       backends/css/gems/sass-3.2.12/test/sass/more_templates/more1.sass \
-       backends/css/gems/sass-3.2.12/test/sass/more_templates/more_import.sass
-
-csssass_gems_sass_3_2_12_bindir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/bin
-csssass_gems_sass_3_2_12_bin_DATA = \
-       backends/css/gems/sass-3.2.12/bin/sass \
-       backends/css/gems/sass-3.2.12/bin/sass-convert \
-       backends/css/gems/sass-3.2.12/bin/scss
-
-csssass_gems_sass_3_2_12_lib_sass_importersdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/lib/sass/importers
-csssass_gems_sass_3_2_12_lib_sass_importers_DATA = \
-       backends/css/gems/sass-3.2.12/lib/sass/importers/base.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/importers/filesystem.rb
-
-csssass_gems_sass_3_2_12_lib_sass_scssdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/lib/sass/scss
-csssass_gems_sass_3_2_12_lib_sass_scss_DATA = \
-       backends/css/gems/sass-3.2.12/lib/sass/scss/css_parser.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/scss/parser.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/scss/rx.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/scss/script_lexer.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/scss/script_parser.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/scss/static_parser.rb
-
-csssass_gems_sass_3_2_12_lib_sass_plugindir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/lib/sass/plugin
-csssass_gems_sass_3_2_12_lib_sass_plugin_DATA = \
-       backends/css/gems/sass-3.2.12/lib/sass/plugin/compiler.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/plugin/configuration.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/plugin/generic.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/plugin/merb.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/plugin/rack.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/plugin/rails.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/plugin/staleness_checker.rb
-
-csssass_gems_sass_3_2_12_vendor_listen_lib_listen_adaptersdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/vendor/listen/lib/listen/adapters
-csssass_gems_sass_3_2_12_vendor_listen_lib_listen_adapters_DATA = \
-       backends/css/gems/sass-3.2.12/vendor/listen/lib/listen/adapters/bsd.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/lib/listen/adapters/darwin.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/lib/listen/adapters/linux.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/lib/listen/adapters/polling.rb \
-       backends/css/gems/sass-3.2.12/vendor/listen/lib/listen/adapters/windows.rb
-
-csssass_gems_sass_3_2_12_lib_sass_selectordir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/lib/sass/selector
-csssass_gems_sass_3_2_12_lib_sass_selector_DATA = \
-       backends/css/gems/sass-3.2.12/lib/sass/selector/abstract_sequence.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/selector/comma_sequence.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/selector/sequence.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/selector/simple.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/selector/simple_sequence.rb
-
-csssass_gems_sass_3_2_12_lib_sassdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/lib/sass
-csssass_gems_sass_3_2_12_lib_sass_DATA = \
-       backends/css/gems/sass-3.2.12/lib/sass/cache_stores.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/callbacks.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/css.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/engine.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/environment.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/error.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/exec.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/importers.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/logger.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/media.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/plugin.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/railtie.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/repl.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/root.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/script.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/scss.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/selector.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/shared.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/supports.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/util.rb \
-       backends/css/gems/sass-3.2.12/lib/sass/version.rb
-
-csssass_gems_sass_3_2_12_test_sass_fixturesdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/test/sass/fixtures
-csssass_gems_sass_3_2_12_test_sass_fixtures_DATA = \
-       backends/css/gems/sass-3.2.12/test/sass/fixtures/test_staleness_check_across_importers.css \
-       backends/css/gems/sass-3.2.12/test/sass/fixtures/test_staleness_check_across_importers.scss
-
-csssass_gems_sass_3_2_12_testdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/test
-csssass_gems_sass_3_2_12_test_DATA = \
-       backends/css/gems/sass-3.2.12/test/Gemfile \
-       backends/css/gems/sass-3.2.12/test/Gemfile.lock \
-       backends/css/gems/sass-3.2.12/test/test_helper.rb
-
-csssass_gems_sass_3_2_12_vendor_listen_libdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.2.12/vendor/listen/lib
-csssass_gems_sass_3_2_12_vendor_listen_lib_DATA = \
-       backends/css/gems/sass-3.2.12/vendor/listen/lib/listen.rb
+csssass_gems_sass_3_4_9dir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9
+csssass_gems_sass_3_4_9_DATA = \
+       backends/css/gems/sass-3.4.9/.yardopts \
+       backends/css/gems/sass-3.4.9/CONTRIBUTING \
+       backends/css/gems/sass-3.4.9/MIT-LICENSE \
+       backends/css/gems/sass-3.4.9/README.md \
+       backends/css/gems/sass-3.4.9/REVISION \
+       backends/css/gems/sass-3.4.9/Rakefile \
+       backends/css/gems/sass-3.4.9/VERSION \
+       backends/css/gems/sass-3.4.9/VERSION_DATE \
+       backends/css/gems/sass-3.4.9/VERSION_NAME \
+       backends/css/gems/sass-3.4.9/init.rb
+
+csssass_gems_sass_3_4_9_test_sass_more_resultsdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/test/sass/more_results
+csssass_gems_sass_3_4_9_test_sass_more_results_DATA = \
+       backends/css/gems/sass-3.4.9/test/sass/more_results/more1.css \
+       backends/css/gems/sass-3.4.9/test/sass/more_results/more1_with_line_comments.css \
+       backends/css/gems/sass-3.4.9/test/sass/more_results/more_import.css
+
+csssass_gems_sass_3_4_9_vendor_listen_spec_listen_adaptersdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/vendor/listen/spec/listen/adapters
+csssass_gems_sass_3_4_9_vendor_listen_spec_listen_adapters_DATA = \
+       backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/adapters/bsd_spec.rb \
+       backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/adapters/darwin_spec.rb \
+       backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/adapters/linux_spec.rb \
+       backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/adapters/polling_spec.rb \
+       backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/adapters/windows_spec.rb
+
+csssass_gems_sass_3_4_9_lib_sass_loggerdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/lib/sass/logger
+csssass_gems_sass_3_4_9_lib_sass_logger_DATA = \
+       backends/css/gems/sass-3.4.9/lib/sass/logger/base.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/logger/log_level.rb
+
+csssass_gems_sass_3_4_9_lib_sass_script_treedir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/lib/sass/script/tree
+csssass_gems_sass_3_4_9_lib_sass_script_tree_DATA = \
+       backends/css/gems/sass-3.4.9/lib/sass/script/tree/funcall.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/tree/interpolation.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/tree/list_literal.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/tree/literal.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/tree/map_literal.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/tree/node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/tree/operation.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/tree/selector.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/tree/string_interpolation.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/tree/unary_operation.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/tree/variable.rb
+
+csssass_gems_sass_3_4_9_lib_sass_script_valuedir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/lib/sass/script/value
+csssass_gems_sass_3_4_9_lib_sass_script_value_DATA = \
+       backends/css/gems/sass-3.4.9/lib/sass/script/value/arg_list.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/value/base.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/value/bool.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/value/color.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/value/helpers.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/value/list.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/value/map.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/value/null.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/value/number.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/value/string.rb
+
+csssass_gems_sass_3_4_9_lib_sass_plugindir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/lib/sass/plugin
+csssass_gems_sass_3_4_9_lib_sass_plugin_DATA = \
+       backends/css/gems/sass-3.4.9/lib/sass/plugin/compiler.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/plugin/configuration.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/plugin/generic.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/plugin/merb.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/plugin/rack.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/plugin/rails.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/plugin/staleness_checker.rb
+
+csssass_gems_sass_3_4_9_testdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/test
+csssass_gems_sass_3_4_9_test_DATA = \
+       backends/css/gems/sass-3.4.9/test/test_helper.rb
+
+csssass_gems_sass_3_4_9_bindir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/bin
+csssass_gems_sass_3_4_9_bin_DATA = \
+       backends/css/gems/sass-3.4.9/bin/sass \
+       backends/css/gems/sass-3.4.9/bin/sass-convert \
+       backends/css/gems/sass-3.4.9/bin/scss
+
+csssass_gems_sass_3_4_9_test_sass_datadir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/test/sass/data
+csssass_gems_sass_3_4_9_test_sass_data_DATA = \
+       backends/css/gems/sass-3.4.9/test/sass/data/hsl-rgb.txt
+
+csssass_gems_sass_3_4_9_lib_sass_scssdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/lib/sass/scss
+csssass_gems_sass_3_4_9_lib_sass_scss_DATA = \
+       backends/css/gems/sass-3.4.9/lib/sass/scss/css_parser.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/scss/parser.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/scss/rx.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/scss/script_lexer.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/scss/script_parser.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/scss/static_parser.rb
+
+csssass_gems_sass_3_4_9_lib_sassdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/lib/sass
+csssass_gems_sass_3_4_9_lib_sass_DATA = \
+       backends/css/gems/sass-3.4.9/lib/sass/cache_stores.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/callbacks.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/css.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/engine.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/environment.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/error.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/exec.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/features.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/importers.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/logger.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/media.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/plugin.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/railtie.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/repl.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/root.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/scss.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/selector.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/shared.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/stack.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/supports.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/util.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/version.rb
+
+csssass_gems_sass_3_4_9_test_sass_templatesdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/test/sass/templates
+csssass_gems_sass_3_4_9_test_sass_templates_DATA = \
+       backends/css/gems/sass-3.4.9/test/sass/templates/_cached_import_option_partial.scss \
+       backends/css/gems/sass-3.4.9/test/sass/templates/_double_import_loop2.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/_filename_fn_import.scss \
+       backends/css/gems/sass-3.4.9/test/sass/templates/_imported_charset_ibm866.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/_imported_charset_utf8.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/_imported_content.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/_partial.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/_same_name_different_partiality.scss \
+       backends/css/gems/sass-3.4.9/test/sass/templates/alt.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/basic.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/bork1.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/bork2.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/bork3.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/bork4.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/bork5.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/cached_import_option.scss \
+       backends/css/gems/sass-3.4.9/test/sass/templates/compact.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/complex.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/compressed.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/double_import_loop1.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/expanded.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/filename_fn.scss \
+       backends/css/gems/sass-3.4.9/test/sass/templates/if.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/import.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/import_charset.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/import_charset_1_8.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/import_charset_ibm866.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/import_content.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/importee.less \
+       backends/css/gems/sass-3.4.9/test/sass/templates/importee.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/line_numbers.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/mixin_bork.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/mixins.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/multiline.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/nested.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/nested_bork1.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/nested_bork2.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/nested_bork3.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/nested_bork4.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/nested_import.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/nested_mixin_bork.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/options.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/parent_ref.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/same_name_different_ext.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/same_name_different_ext.scss \
+       backends/css/gems/sass-3.4.9/test/sass/templates/same_name_different_partiality.scss \
+       backends/css/gems/sass-3.4.9/test/sass/templates/script.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/scss_import.scss \
+       backends/css/gems/sass-3.4.9/test/sass/templates/scss_importee.scss \
+       backends/css/gems/sass-3.4.9/test/sass/templates/single_import_loop.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/units.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/warn.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/warn_imported.sass
+
+csssass_gems_sass_3_4_9_vendor_listen_lib_listendir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/vendor/listen/lib/listen
+csssass_gems_sass_3_4_9_vendor_listen_lib_listen_DATA = \
+       backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapter.rb \
+       backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/directory_record.rb \
+       backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/listener.rb \
+       backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/turnstile.rb \
+       backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/version.rb
+
+csssass_gems_sass_3_4_9_lib_sass_cache_storesdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/lib/sass/cache_stores
+csssass_gems_sass_3_4_9_lib_sass_cache_stores_DATA = \
+       backends/css/gems/sass-3.4.9/lib/sass/cache_stores/base.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/cache_stores/chain.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/cache_stores/filesystem.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/cache_stores/memory.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/cache_stores/null.rb
+
+csssass_gems_sass_3_4_9_lib_sass_tree_visitorsdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/lib/sass/tree/visitors
+csssass_gems_sass_3_4_9_lib_sass_tree_visitors_DATA = \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/base.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/check_nesting.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/convert.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/cssize.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/deep_copy.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/extend.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/perform.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/set_options.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/to_css.rb
+
+csssass_gems_sass_3_4_9_test_sass_templates_subdir_nested_subdirdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/test/sass/templates/subdir/nested_subdir
+csssass_gems_sass_3_4_9_test_sass_templates_subdir_nested_subdir_DATA = \
+       backends/css/gems/sass-3.4.9/test/sass/templates/subdir/nested_subdir/_nested_partial.sass \
+       backends/css/gems/sass-3.4.9/test/sass/templates/subdir/nested_subdir/nested_subdir.sass
+
+csssass_gems_sass_3_4_9_test_sass_resultsdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/test/sass/results
+csssass_gems_sass_3_4_9_test_sass_results_DATA = \
+       backends/css/gems/sass-3.4.9/test/sass/results/alt.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/basic.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/cached_import_option.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/compact.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/complex.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/compressed.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/expanded.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/filename_fn.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/if.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/import.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/import_charset.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/import_charset_1_8.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/import_charset_ibm866.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/import_content.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/line_numbers.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/mixins.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/multiline.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/nested.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/options.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/parent_ref.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/script.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/scss_import.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/scss_importee.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/units.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/warn.css \
+       backends/css/gems/sass-3.4.9/test/sass/results/warn_imported.css
+
+csssass_gems_sass_3_4_9_lib_sass_execdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/lib/sass/exec
+csssass_gems_sass_3_4_9_lib_sass_exec_DATA = \
+       backends/css/gems/sass-3.4.9/lib/sass/exec/base.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/exec/sass_convert.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/exec/sass_scss.rb
+
+csssass_gems_sass_3_4_9_test_sass_scssdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/test/sass/scss
+csssass_gems_sass_3_4_9_test_sass_scss_DATA = \
+       backends/css/gems/sass-3.4.9/test/sass/scss/css_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/scss/rx_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/scss/scss_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/scss/test_helper.rb
+
+csssass_gems_sass_3_4_9_railsdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/rails
+csssass_gems_sass_3_4_9_rails_DATA = \
+       backends/css/gems/sass-3.4.9/rails/init.rb
+
+csssass_gems_sass_3_4_9_vendor_listen_specdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/vendor/listen/spec
+csssass_gems_sass_3_4_9_vendor_listen_spec_DATA = \
+       backends/css/gems/sass-3.4.9/vendor/listen/spec/listen_spec.rb \
+       backends/css/gems/sass-3.4.9/vendor/listen/spec/spec_helper.rb
+
+csssass_gems_sass_3_4_9_lib_sass_utildir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/lib/sass/util
+csssass_gems_sass_3_4_9_lib_sass_util_DATA = \
+       backends/css/gems/sass-3.4.9/lib/sass/util/cross_platform_random.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/util/multibyte_string_scanner.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/util/normalized_map.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/util/ordered_hash.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/util/subset_map.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/util/test.rb
+
+csssass_gems_sass_3_4_9_test_sassdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/test/sass
+csssass_gems_sass_3_4_9_test_sass_DATA = \
+       backends/css/gems/sass-3.4.9/test/sass/cache_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/callbacks_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/compiler_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/conversion_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/css2sass_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/encoding_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/engine_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/exec_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/extend_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/functions_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/importer_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/logger_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/mock_importer.rb \
+       backends/css/gems/sass-3.4.9/test/sass/plugin_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/script_conversion_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/script_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/source_map_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/superselector_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/test_helper.rb \
+       backends/css/gems/sass-3.4.9/test/sass/util_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/value_helpers_test.rb
+
+csssass_gems_sass_3_4_9_libdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/lib
+csssass_gems_sass_3_4_9_lib_DATA = \
+       backends/css/gems/sass-3.4.9/lib/sass.rb
+
+csssass_gems_sass_3_4_9_vendor_listendir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/vendor/listen
+csssass_gems_sass_3_4_9_vendor_listen_DATA = \
+       backends/css/gems/sass-3.4.9/vendor/listen/CHANGELOG.md \
+       backends/css/gems/sass-3.4.9/vendor/listen/CONTRIBUTING.md \
+       backends/css/gems/sass-3.4.9/vendor/listen/Gemfile \
+       backends/css/gems/sass-3.4.9/vendor/listen/Guardfile \
+       backends/css/gems/sass-3.4.9/vendor/listen/LICENSE \
+       backends/css/gems/sass-3.4.9/vendor/listen/README.md \
+       backends/css/gems/sass-3.4.9/vendor/listen/Rakefile \
+       backends/css/gems/sass-3.4.9/vendor/listen/Vagrantfile \
+       backends/css/gems/sass-3.4.9/vendor/listen/listen.gemspec
+
+csssass_gems_sass_3_4_9_lib_sass_treedir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/lib/sass/tree
+csssass_gems_sass_3_4_9_lib_sass_tree_DATA = \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/at_root_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/charset_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/comment_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/content_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/css_import_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/debug_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/directive_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/each_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/error_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/extend_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/for_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/function_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/if_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/import_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/keyframe_rule_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/media_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/mixin_def_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/mixin_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/prop_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/return_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/root_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/rule_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/supports_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/trace_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/variable_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/warn_node.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/tree/while_node.rb
+
+csssass_gems_sass_3_4_9_lib_sass_sourcedir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/lib/sass/source
+csssass_gems_sass_3_4_9_lib_sass_source_DATA = \
+       backends/css/gems/sass-3.4.9/lib/sass/source/map.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/source/position.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/source/range.rb
+
+csssass_gems_sass_3_4_9_test_sass_utildir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/test/sass/util
+csssass_gems_sass_3_4_9_test_sass_util_DATA = \
+       backends/css/gems/sass-3.4.9/test/sass/util/multibyte_string_scanner_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/util/normalized_map_test.rb \
+       backends/css/gems/sass-3.4.9/test/sass/util/subset_map_test.rb
+
+csssass_gems_sass_3_4_9_test_sass_templates_subdirdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/test/sass/templates/subdir
+csssass_gems_sass_3_4_9_test_sass_templates_subdir_DATA = \
+       backends/css/gems/sass-3.4.9/test/sass/templates/subdir/import_up1.scss \
+       backends/css/gems/sass-3.4.9/test/sass/templates/subdir/import_up2.scss \
+       backends/css/gems/sass-3.4.9/test/sass/templates/subdir/subdir.sass
+
+csssass_gems_sass_3_4_9_test_sass_fixturesdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/test/sass/fixtures
+csssass_gems_sass_3_4_9_test_sass_fixtures_DATA = \
+       backends/css/gems/sass-3.4.9/test/sass/fixtures/test_staleness_check_across_importers.css \
+       backends/css/gems/sass-3.4.9/test/sass/fixtures/test_staleness_check_across_importers.scss
+
+csssass_gems_sass_3_4_9_extradir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/extra
+csssass_gems_sass_3_4_9_extra_DATA = \
+       backends/css/gems/sass-3.4.9/extra/update_watch.rb
+
+csssass_gems_sass_3_4_9_test_sass_more_templatesdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/test/sass/more_templates
+csssass_gems_sass_3_4_9_test_sass_more_templates_DATA = \
+       backends/css/gems/sass-3.4.9/test/sass/more_templates/_more_partial.sass \
+       backends/css/gems/sass-3.4.9/test/sass/more_templates/more1.sass \
+       backends/css/gems/sass-3.4.9/test/sass/more_templates/more_import.sass
+
+csssass_gems_sass_3_4_9_vendor_listen_libdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/vendor/listen/lib
+csssass_gems_sass_3_4_9_vendor_listen_lib_DATA = \
+       backends/css/gems/sass-3.4.9/vendor/listen/lib/listen.rb
+
+csssass_gems_sass_3_4_9_test_sass_results_subdirdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/test/sass/results/subdir
+csssass_gems_sass_3_4_9_test_sass_results_subdir_DATA = \
+       backends/css/gems/sass-3.4.9/test/sass/results/subdir/subdir.css
+
+csssass_gems_sass_3_4_9_lib_sass_scriptdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/lib/sass/script
+csssass_gems_sass_3_4_9_lib_sass_script_DATA = \
+       backends/css/gems/sass-3.4.9/lib/sass/script/css_lexer.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/css_parser.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/functions.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/lexer.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/parser.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/tree.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/script/value.rb
+
+csssass_gems_sass_3_4_9_lib_sass_importersdir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/lib/sass/importers
+csssass_gems_sass_3_4_9_lib_sass_importers_DATA = \
+       backends/css/gems/sass-3.4.9/lib/sass/importers/base.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/importers/filesystem.rb
+
+csssass_gems_sass_3_4_9_vendor_listen_spec_listendir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/vendor/listen/spec/listen
+csssass_gems_sass_3_4_9_vendor_listen_spec_listen_DATA = \
+       backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/adapter_spec.rb \
+       backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/directory_record_spec.rb \
+       backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/listener_spec.rb \
+       backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/turnstile_spec.rb
+
+csssass_gems_sass_3_4_9_test_sass_results_subdir_nested_subdirdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/test/sass/results/subdir/nested_subdir
+csssass_gems_sass_3_4_9_test_sass_results_subdir_nested_subdir_DATA = \
+       backends/css/gems/sass-3.4.9/test/sass/results/subdir/nested_subdir/nested_subdir.css
+
+csssass_gems_sass_3_4_9_vendor_listen_spec_supportdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/vendor/listen/spec/support
+csssass_gems_sass_3_4_9_vendor_listen_spec_support_DATA = \
+       backends/css/gems/sass-3.4.9/vendor/listen/spec/support/adapter_helper.rb \
+       backends/css/gems/sass-3.4.9/vendor/listen/spec/support/directory_record_helper.rb \
+       backends/css/gems/sass-3.4.9/vendor/listen/spec/support/fixtures_helper.rb \
+       backends/css/gems/sass-3.4.9/vendor/listen/spec/support/listeners_helper.rb \
+       backends/css/gems/sass-3.4.9/vendor/listen/spec/support/platform_helper.rb
+
+csssass_gems_sass_3_4_9_lib_sass_selectordir = $(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/lib/sass/selector
+csssass_gems_sass_3_4_9_lib_sass_selector_DATA = \
+       backends/css/gems/sass-3.4.9/lib/sass/selector/abstract_sequence.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/selector/comma_sequence.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/selector/pseudo.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/selector/sequence.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/selector/simple.rb \
+       backends/css/gems/sass-3.4.9/lib/sass/selector/simple_sequence.rb
+
+csssass_gems_sass_3_4_9_vendor_listen_lib_listen_adaptersdir = 
$(GCA_RBBACKENDS_DIR)/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapters
+csssass_gems_sass_3_4_9_vendor_listen_lib_listen_adapters_DATA = \
+       backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapters/bsd.rb \
+       backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapters/darwin.rb \
+       backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapters/linux.rb \
+       backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapters/polling.rb \
+       backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapters/windows.rb
 
 endif
 
 EXTRA_DIST += \
-       $(csssass_gems_sass_3_2_12_test_sass_results_subdir_DATA) \
-       $(csssass_gems_sass_3_2_12_lib_sass_tree_visitors_DATA) \
-       $(csssass_gems_sass_3_2_12_test_sass_scss_DATA) \
-       $(csssass_gems_sass_3_2_12_test_sass_DATA) \
-       $(csssass_gems_sass_3_2_12_vendor_listen_spec_listen_adapters_DATA) \
-       $(csssass_gems_sass_3_2_12_test_sass_templates_subdir_nested_subdir_DATA) \
-       $(csssass_gems_sass_3_2_12_DATA) \
-       $(csssass_gems_sass_3_2_12_test_sass_templates_subdir_DATA) \
-       $(csssass_gems_sass_3_2_12_test_sass_data_DATA) \
-       $(csssass_gems_sass_3_2_12_vendor_listen_spec_support_DATA) \
-       $(csssass_gems_sass_3_2_12_lib_DATA) \
-       $(csssass_gems_sass_3_2_12_lib_sass_script_DATA) \
-       $(csssass_gems_sass_3_2_12_vendor_listen_lib_listen_DATA) \
-       $(csssass_gems_sass_3_2_12_vendor_listen_DATA) \
-       $(csssass_gems_sass_3_2_12_test_sass_templates_DATA) \
-       $(csssass_gems_sass_3_2_12_rails_DATA) \
-       $(csssass_gems_sass_3_2_12_vendor_listen_spec_DATA) \
-       $(csssass_gems_sass_3_2_12_extra_DATA) \
-       $(csssass_gems_sass_3_2_12_test_sass_more_results_DATA) \
-       $(csssass_gems_sass_3_2_12_vendor_listen_spec_listen_DATA) \
-       $(csssass_gems_sass_3_2_12_test_sass_util_DATA) \
-       $(csssass_gems_sass_3_2_12_test_sass_results_DATA) \
-       $(csssass_gems_sass_3_2_12_lib_sass_tree_DATA) \
-       $(csssass_gems_sass_3_2_12_test_sass_results_subdir_nested_subdir_DATA) \
-       $(csssass_gems_sass_3_2_12_lib_sass_cache_stores_DATA) \
-       $(csssass_gems_sass_3_2_12_lib_sass_util_DATA) \
-       $(csssass_gems_sass_3_2_12_lib_sass_logger_DATA) \
-       $(csssass_gems_sass_3_2_12_test_sass_more_templates_DATA) \
-       $(csssass_gems_sass_3_2_12_bin_DATA) \
-       $(csssass_gems_sass_3_2_12_lib_sass_importers_DATA) \
-       $(csssass_gems_sass_3_2_12_lib_sass_scss_DATA) \
-       $(csssass_gems_sass_3_2_12_lib_sass_plugin_DATA) \
-       $(csssass_gems_sass_3_2_12_vendor_listen_lib_listen_adapters_DATA) \
-       $(csssass_gems_sass_3_2_12_lib_sass_selector_DATA) \
-       $(csssass_gems_sass_3_2_12_lib_sass_DATA) \
-       $(csssass_gems_sass_3_2_12_test_sass_fixtures_DATA) \
-       $(csssass_gems_sass_3_2_12_test_DATA) \
-       $(csssass_gems_sass_3_2_12_vendor_listen_lib_DATA)
+       $(csssass_gems_sass_3_4_9_DATA) \
+       $(csssass_gems_sass_3_4_9_test_sass_more_results_DATA) \
+       $(csssass_gems_sass_3_4_9_vendor_listen_spec_listen_adapters_DATA) \
+       $(csssass_gems_sass_3_4_9_lib_sass_logger_DATA) \
+       $(csssass_gems_sass_3_4_9_lib_sass_script_tree_DATA) \
+       $(csssass_gems_sass_3_4_9_lib_sass_script_value_DATA) \
+       $(csssass_gems_sass_3_4_9_lib_sass_plugin_DATA) \
+       $(csssass_gems_sass_3_4_9_test_DATA) \
+       $(csssass_gems_sass_3_4_9_bin_DATA) \
+       $(csssass_gems_sass_3_4_9_test_sass_data_DATA) \
+       $(csssass_gems_sass_3_4_9_lib_sass_scss_DATA) \
+       $(csssass_gems_sass_3_4_9_lib_sass_DATA) \
+       $(csssass_gems_sass_3_4_9_test_sass_templates_DATA) \
+       $(csssass_gems_sass_3_4_9_vendor_listen_lib_listen_DATA) \
+       $(csssass_gems_sass_3_4_9_lib_sass_cache_stores_DATA) \
+       $(csssass_gems_sass_3_4_9_lib_sass_tree_visitors_DATA) \
+       $(csssass_gems_sass_3_4_9_test_sass_templates_subdir_nested_subdir_DATA) \
+       $(csssass_gems_sass_3_4_9_test_sass_results_DATA) \
+       $(csssass_gems_sass_3_4_9_lib_sass_exec_DATA) \
+       $(csssass_gems_sass_3_4_9_test_sass_scss_DATA) \
+       $(csssass_gems_sass_3_4_9_rails_DATA) \
+       $(csssass_gems_sass_3_4_9_vendor_listen_spec_DATA) \
+       $(csssass_gems_sass_3_4_9_lib_sass_util_DATA) \
+       $(csssass_gems_sass_3_4_9_test_sass_DATA) \
+       $(csssass_gems_sass_3_4_9_lib_DATA) \
+       $(csssass_gems_sass_3_4_9_vendor_listen_DATA) \
+       $(csssass_gems_sass_3_4_9_lib_sass_tree_DATA) \
+       $(csssass_gems_sass_3_4_9_lib_sass_source_DATA) \
+       $(csssass_gems_sass_3_4_9_test_sass_util_DATA) \
+       $(csssass_gems_sass_3_4_9_test_sass_templates_subdir_DATA) \
+       $(csssass_gems_sass_3_4_9_test_sass_fixtures_DATA) \
+       $(csssass_gems_sass_3_4_9_extra_DATA) \
+       $(csssass_gems_sass_3_4_9_test_sass_more_templates_DATA) \
+       $(csssass_gems_sass_3_4_9_vendor_listen_lib_DATA) \
+       $(csssass_gems_sass_3_4_9_test_sass_results_subdir_DATA) \
+       $(csssass_gems_sass_3_4_9_lib_sass_script_DATA) \
+       $(csssass_gems_sass_3_4_9_lib_sass_importers_DATA) \
+       $(csssass_gems_sass_3_4_9_vendor_listen_spec_listen_DATA) \
+       $(csssass_gems_sass_3_4_9_test_sass_results_subdir_nested_subdir_DATA) \
+       $(csssass_gems_sass_3_4_9_vendor_listen_spec_support_DATA) \
+       $(csssass_gems_sass_3_4_9_lib_sass_selector_DATA) \
+       $(csssass_gems_sass_3_4_9_vendor_listen_lib_listen_adapters_DATA)
diff --git a/backends/css/gems/sass-3.2.12/.yardopts b/backends/css/gems/sass-3.4.9/.yardopts
similarity index 100%
rename from backends/css/gems/sass-3.2.12/.yardopts
rename to backends/css/gems/sass-3.4.9/.yardopts
diff --git a/backends/css/gems/sass-3.4.9/CONTRIBUTING b/backends/css/gems/sass-3.4.9/CONTRIBUTING
new file mode 100644
index 0000000..f76d92d
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/CONTRIBUTING
@@ -0,0 +1,3 @@
+Contributions are welcomed. Please see the following sites for guidelines:
+
+  http://sass-lang.com/community#Contribute
diff --git a/backends/css/gems/sass-3.4.9/MIT-LICENSE b/backends/css/gems/sass-3.4.9/MIT-LICENSE
new file mode 100644
index 0000000..9854495
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2006-2014 Hampton Catlin, Natalie Weizenbaum, and Chris Eppstein
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/backends/css/gems/sass-3.4.9/README.md b/backends/css/gems/sass-3.4.9/README.md
new file mode 100644
index 0000000..c4fee13
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/README.md
@@ -0,0 +1,221 @@
+# Sass [![Gem Version](https://badge.fury.io/rb/sass.png)](http://badge.fury.io/rb/sass) [![Inline 
docs](http://inch-ci.org/github/sass/sass.svg)](http://inch-ci.org/github/sass/sass)
+
+**Sass makes CSS fun again**. Sass is an extension of CSS3,
+adding nested rules, variables, mixins, selector inheritance, and more.
+It's translated to well-formatted, standard CSS
+using the command line tool or a web-framework plugin.
+
+Sass has two syntaxes. The new main syntax (as of Sass 3)
+is known as "SCSS" (for "Sassy CSS"),
+and is a superset of CSS3's syntax.
+This means that every valid CSS3 stylesheet is valid SCSS as well.
+SCSS files use the extension `.scss`.
+
+The second, older syntax is known as the indented syntax (or just "Sass").
+Inspired by Haml's terseness, it's intended for people
+who prefer conciseness over similarity to CSS.
+Instead of brackets and semicolons,
+it uses the indentation of lines to specify blocks.
+Although no longer the primary syntax,
+the indented syntax will continue to be supported.
+Files in the indented syntax use the extension `.sass`.
+
+## Using
+
+Sass can be used from the command line
+or as part of a web framework.
+The first step is to install the gem:
+
+    gem install sass
+
+After you convert some CSS to Sass, you can run
+
+    sass style.scss
+
+to compile it back to CSS.
+For more information on these commands, check out
+
+    sass --help
+
+To install Sass in Rails 2,
+just add `config.gem "sass"` to `config/environment.rb`.
+In Rails 3, add `gem "sass"` to your Gemfile instead.
+`.sass` or `.scss` files should be placed in `public/stylesheets/sass`,
+where they'll be automatically compiled
+to corresponding CSS files in `public/stylesheets` when needed
+(the Sass template directory is customizable...
+see [the Sass reference](http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#template_location-option) 
for details).
+
+Sass can also be used with any Rack-enabled web framework.
+To do so, just add
+
+```ruby
+require 'sass/plugin/rack'
+use Sass::Plugin::Rack
+```
+
+to `config.ru`.
+Then any Sass files in `public/stylesheets/sass`
+will be compiled into CSS files in `public/stylesheets` on every request.
+
+To use Sass programmatically,
+check out the [YARD documentation](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#using_sass).
+
+## Formatting
+
+Sass is an extension of CSS
+that adds power and elegance to the basic language.
+It allows you to use [variables][vars], [nested rules][nested],
+[mixins][mixins], [inline imports][imports],
+and more, all with a fully CSS-compatible syntax.
+Sass helps keep large stylesheets well-organized,
+and get small stylesheets up and running quickly,
+particularly with the help of
+[the Compass style library](http://compass-style.org).
+
+[vars]:    http://sass-lang.com/documentation/file.SASS_REFERENCE.html#variables_
+[nested]:  http://sass-lang.com/documentation/file.SASS_REFERENCE.html#nested_rules
+[mixins]:  http://sass-lang.com/documentation/file.SASS_REFERENCE.html#mixins
+[imports]: http://sass-lang.com/documentation/file.SASS_REFERENCE.html#import
+
+Sass has two syntaxes.
+The one presented here, known as "SCSS" (for "Sassy CSS"),
+is fully CSS-compatible.
+The other (older) syntax, known as the indented syntax or just "Sass",
+is whitespace-sensitive and indentation-based.
+For more information, see the [reference documentation][syntax].
+
+[syntax]: http://sass-lang.com/documentation/file.SASS_REFERENCE.html#syntax
+
+To run the following examples and see the CSS they produce,
+put them in a file called `test.scss` and run `sass test.scss`.
+
+### Nesting
+
+Sass avoids repetition by nesting selectors within one another.
+The same thing works for properties.
+
+```scss
+table.hl {
+  margin: 2em 0;
+  td.ln { text-align: right; }
+}
+
+li {
+  font: {
+    family: serif;
+    weight: bold;
+    size: 1.2em;
+  }
+}
+```
+
+### Variables
+
+Use the same color all over the place?
+Need to do some math with height and width and text size?
+Sass supports variables, math operations, and many useful functions.
+
+```scss
+$blue: #3bbfce;
+$margin: 16px;
+
+.content_navigation {
+  border-color: $blue;
+  color: darken($blue, 10%);
+}
+
+.border {
+  padding: $margin / 2;
+  margin: $margin / 2;
+  border-color: $blue;
+}
+```
+
+### Mixins
+
+Even more powerful than variables,
+mixins allow you to re-use whole chunks of CSS,
+properties or selectors.
+You can even give them arguments. 
+
+```scss
+ mixin table-scaffolding {
+  th {
+    text-align: center;
+    font-weight: bold;
+  }
+  td, th { padding: 2px; }
+}
+
+ mixin left($dist) {
+  float: left;
+  margin-left: $dist;
+}
+
+#data {
+  @include left(10px);
+  @include table-scaffolding;
+}
+```
+
+A comprehensive list of features is available
+in the [Sass reference](http://sass-lang.com/documentation/file.SASS_REFERENCE.html).
+
+## Executables
+
+The Sass gem includes several executables that are useful
+for dealing with Sass from the command line.
+
+### `sass`
+
+The `sass` executable transforms a source Sass file into CSS.
+See `sass --help` for further information and options.
+
+### `sass-convert`
+
+The `sass-convert` executable converts between CSS, Sass, and SCSS.
+When converting from CSS to Sass or SCSS,
+nesting is applied where appropriate.
+See `sass-convert --help` for further information and options.
+
+### Running locally
+
+To run the Sass executables from a source checkout instead of from rubygems:
+
+```
+$ cd <SASS_CHECKOUT_DIRECTORY>
+$ bundle
+$ bundle exec sass ...
+$ bundle exec scss ...
+$ bundle exec sass-convert ...
+```
+
+## Authors
+
+Sass was envisioned by [Hampton Catlin](http://www.hamptoncatlin.com)
+(@hcatlin). However, Hampton doesn't even know his way around the code anymore
+and now occasionally consults on the language issues. Hampton lives in San
+Francisco, California and works as VP of Technology
+at [Moovweb](http://www.moovweb.com/).
+
+[Natalie Weizenbaum](http://nex-3.com) is the primary developer and architect of
+Sass. Her hard work has kept the project alive by endlessly answering forum
+posts, fixing bugs, refactoring, finding speed improvements, writing
+documentation, implementing new features, and getting Hampton coffee (a fitting
+task for a girl genius). Natalie lives in Seattle, Washington and works on
+[Dart](http://dartlang.org) application libraries at Google.
+
+[Chris Eppstein](http://acts-as-architect.blogspot.com) is a core contributor to
+Sass and the creator of Compass, the first Sass-based framework. Chris focuses
+on making Sass more powerful, easy to use, and on ways to speed its adoption
+through the web development community. Chris lives in San Jose, California with
+his wife and daughter. He is an Engineer for
+[LinkedIn.com](http://linkedin.com), where one of his responsibilities is to
+maintain Sass & Compass.
+
+If you use this software, you must pay Hampton a compliment. And buy Natalie
+some candy. Maybe pet a kitten. Yeah. Pet that kitty.
+
+Beyond that, the implementation is licensed under the MIT License.
+Okay, fine, I guess that means compliments aren't __required__.
diff --git a/backends/css/gems/sass-3.2.12/REVISION b/backends/css/gems/sass-3.4.9/REVISION
similarity index 100%
rename from backends/css/gems/sass-3.2.12/REVISION
rename to backends/css/gems/sass-3.4.9/REVISION
diff --git a/backends/css/gems/sass-3.4.9/Rakefile b/backends/css/gems/sass-3.4.9/Rakefile
new file mode 100644
index 0000000..07d076f
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/Rakefile
@@ -0,0 +1,370 @@
+require 'rubygems/package'
+
+# ----- Utility Functions -----
+
+def scope(path)
+  File.join(File.dirname(__FILE__), path)
+end
+
+# ----- Default: Testing ------
+
+task :default => :test
+
+require 'rake/testtask'
+
+Rake::TestTask.new do |t|
+  t.libs << 'test'
+  test_files = FileList[scope('test/**/*_test.rb')]
+  test_files.exclude(scope('test/rails/*'))
+  test_files.exclude(scope('test/plugins/*'))
+  t.test_files = test_files
+  t.verbose = true
+end
+
+# ----- Code Style Enforcement -----
+
+if RUBY_VERSION !~ /^(1\.8)/ && (ENV.has_key?("RUBOCOP") && ENV["RUBOCOP"] == "true" || 
!(ENV.has_key?("RUBOCOP") || ENV.has_key?("TEST")))
+  require 'rubocop/rake_task'
+  Rubocop::RakeTask.new do |t|
+    t.patterns = FileList["lib/**/*"]
+  end
+else
+  task :rubocop do
+    puts "Skipping rubocop style check."
+    if !ENV.has_key?("RUBOCOP")
+      puts "Passing this check is required in order for your patch to be accepted."
+      puts "Use ruby 1.9 or greater and then run the style check with: rake rubocop"
+    end
+  end
+end
+
+task :test => :rubocop
+
+# ----- Packaging -----
+
+# Don't use Rake::GemPackageTast because we want prerequisites to run
+# before we load the gemspec.
+desc "Build all the packages."
+task :package => [:revision_file, :date_file, :submodules, :permissions] do
+  version = get_version
+  File.open(scope('VERSION'), 'w') {|f| f.puts(version)}
+  load scope('sass.gemspec')
+  Gem::Package.build(SASS_GEMSPEC)
+  sh %{git checkout VERSION}
+
+  pkg = "#{SASS_GEMSPEC.name}-#{SASS_GEMSPEC.version}"
+  mkdir_p "pkg"
+  verbose(true) {mv "#{pkg}.gem", "pkg/#{pkg}.gem"}
+
+  sh %{rm -f pkg/#{pkg}.tar.gz}
+  verbose(false) {SASS_GEMSPEC.files.each {|f| sh %{tar rf pkg/#{pkg}.tar #{f}}}}
+  sh %{gzip pkg/#{pkg}.tar}
+end
+
+task :permissions do
+  sh %{chmod -R a+rx bin}
+  sh %{chmod -R a+r .}
+  require 'shellwords'
+  Dir.glob('test/**/*_test.rb') do |file|
+    next if file =~ %r{^test/haml/spec/}
+    sh %{chmod a+rx #{file}}
+  end
+end
+
+task :revision_file do
+  require scope('lib/sass')
+
+  release = Rake.application.top_level_tasks.include?('release') || File.exist?(scope('EDGE_GEM_VERSION'))
+  if Sass.version[:rev] && !release
+    File.open(scope('REVISION'), 'w') { |f| f.puts Sass.version[:rev] }
+  elsif release
+    File.open(scope('REVISION'), 'w') { |f| f.puts "(release)" }
+  else
+    File.open(scope('REVISION'), 'w') { |f| f.puts "(unknown)" }
+  end
+end
+
+task :date_file do
+  File.open(scope('VERSION_DATE'), 'w') do |f|
+    f.puts Time.now.utc.strftime('%d %B %Y %T %Z')
+  end
+end
+
+# We also need to get rid of this file after packaging.
+at_exit do
+  File.delete(scope('REVISION')) rescue nil
+  File.delete(scope('VERSION_DATE')) rescue nil
+end
+
+desc "Install Sass as a gem. Use SUDO=1 to install with sudo."
+task :install => [:package] do
+  gem  = RUBY_PLATFORM =~ /java/  ? 'jgem' : 'gem' 
+  sh %{#{'sudo ' if ENV["SUDO"]}#{gem} install --no-ri pkg/sass-#{get_version}}
+end
+
+desc "Release a new Sass package to RubyGems.org."
+task :release => [:check_release, :package] do
+  name = File.read(scope("VERSION_NAME")).strip
+  version = File.read(scope("VERSION")).strip
+  sh %{gem push pkg/sass-#{version}.gem}
+end
+
+# Ensures that the VERSION file has been updated for a new release.
+task :check_release do
+  version = File.read(scope("VERSION")).strip
+  raise "There have been changes since current version (#{version})" if changed_since?(version)
+  raise "VERSION_NAME must not be 'Bleeding Edge'" if File.read(scope("VERSION_NAME")) == "Bleeding Edge"
+end
+
+# Reads a password from the command line.
+#
+# @param name [String] The prompt to use to read the password
+def read_password(prompt)
+  require 'readline'
+  system "stty -echo"
+  Readline.readline("#{prompt}: ").strip
+ensure
+  system "stty echo"
+  puts
+end
+
+# Returns whether or not the repository, or specific files,
+# has/have changed since a given revision.
+#
+# @param rev [String] The revision to check against
+# @param files [Array<String>] The files to check.
+#   If this is empty, checks the entire repository
+def changed_since?(rev, *files)
+  IO.popen("git diff --exit-code #{rev} #{files.join(' ')}") {}
+  return !$?.success?
+end
+
+task :submodules do
+  if File.exist?(File.dirname(__FILE__) + "/.git")
+    sh %{git submodule sync}
+    sh %{git submodule update --init}
+  elsif !File.exist?(File.dirname(__FILE__) + "/vendor/listen/lib")
+    warn <<WARN
+WARNING: vendor/listen doesn't exist, and this isn't a git repository so
+I can't get it automatically!
+WARN
+  end
+end
+
+task :release_edge do
+  ensure_git_cleanup do
+    puts "#{'=' * 50} Running rake release_edge"
+
+    sh %{git checkout master}
+    sh %{git reset --hard origin/master}
+    sh %{rake package}
+    version = get_version
+    if version.include?('.rc.')
+      puts "#{'=' * 20} Not releasing edge gem for RC version"
+      next
+    end
+
+    sh %{gem push pkg/sass-#{version}.gem}
+  end
+end
+
+# Get the version string. If this is being installed from Git,
+# this includes the proper prerelease version.
+def get_version
+  written_version = File.read(scope('VERSION').strip)
+  return written_version unless File.exist?(scope('.git'))
+
+  # Get the current master branch version
+  version = written_version.split('.')
+  version.map! {|n| n =~ /^[0-9]+$/ ? n.to_i : n}
+  return written_version unless version.size == 5 && version[3] == "alpha" # prerelease
+
+  return written_version if (commit_count = `git log --pretty=oneline HEAD ^stable | wc -l`).empty?
+  version[4] = commit_count.strip
+  version.join('.')
+end
+
+task :watch_for_update do
+  sh %{ruby extra/update_watch.rb}
+end
+
+# ----- Documentation -----
+
+task :rdoc do
+  puts '=' * 100, <<END, '=' * 100
+Sass uses the YARD documentation system (http://github.com/lsegal/yard).
+Install the yard gem and then run "rake doc".
+END
+end
+
+begin
+  require 'yard'
+
+  namespace :doc do
+    task :sass do
+      require scope('lib/sass')
+      Dir[scope("yard/default/**/*.sass")].each do |sass|
+        File.open(sass.gsub(/sass$/, 'css'), 'w') do |f|
+          f.write(Sass::Engine.new(File.read(sass)).render)
+        end
+      end
+    end
+
+    desc "List all undocumented methods and classes."
+    task :undocumented do
+      opts = ENV["YARD_OPTS"] || ""
+      ENV["YARD_OPTS"] = opts.dup + <<OPTS
+ --list --tag comment --hide-tag comment --query "
+  object.docstring.blank? &&
+  !(object.type == :method && object.is_alias?)"
+OPTS
+      Rake::Task['yard'].execute
+    end
+  end
+
+  YARD::Rake::YardocTask.new do |t|
+    t.files = FileList.new(scope('lib/**/*.rb')) do |list|
+      list.exclude('lib/sass/plugin/merb.rb')
+      list.exclude('lib/sass/plugin/rails.rb')
+    end.to_a
+    t.options << '--incremental' if Rake.application.top_level_tasks.include?('redoc')
+    t.options += FileList.new(scope('yard/*.rb')).to_a.map {|f| ['-e', f]}.flatten
+    files = FileList.new(scope('doc-src/*')).to_a.sort_by {|s| s.size} + %w[MIT-LICENSE VERSION]
+    t.options << '--files' << files.join(',')
+    t.options << '--template-path' << scope('yard')
+    t.options << '--title' << ENV["YARD_TITLE"] if ENV["YARD_TITLE"]
+
+    t.before = lambda do
+      if ENV["YARD_OPTS"]
+        require 'shellwords'
+        t.options.concat(Shellwords.shellwords(ENV["YARD_OPTS"]))
+      end
+    end
+  end
+  Rake::Task['yard'].prerequisites.insert(0, 'doc:sass')
+  Rake::Task['yard'].instance_variable_set('@comment', nil)
+
+  desc "Generate Documentation"
+  task :doc => :yard
+  task :redoc => :yard
+rescue LoadError
+  desc "Generate Documentation"
+  task :doc => :rdoc
+  task :yard => :rdoc
+end
+
+task :pages do
+  ensure_git_cleanup do
+    puts "#{'=' * 50} Running rake pages"
+    sh %{git checkout sass-pages}
+    sh %{git reset --hard origin/sass-pages}
+
+    Dir.chdir("/var/www/sass-pages") do
+      sh %{git fetch origin}
+
+      sh %{git checkout stable}
+      sh %{git reset --hard origin/stable}
+
+      sh %{git checkout sass-pages}
+      sh %{git reset --hard origin/sass-pages}
+      sh %{rake build --trace}
+      sh %{mkdir -p tmp}
+      sh %{touch tmp/restart.txt}
+    end
+  end
+end
+
+# ----- Coverage -----
+
+begin
+  require 'rcov/rcovtask'
+
+  Rcov::RcovTask.new do |t|
+    t.test_files = FileList[scope('test/**/*_test.rb')]
+    t.rcov_opts << '-x' << '"^\/"'
+    if ENV['NON_NATIVE']
+      t.rcov_opts << "--no-rcovrt"
+    end
+    t.verbose = true
+  end
+rescue LoadError; end
+
+# ----- Profiling -----
+
+begin
+  require 'ruby-prof'
+
+  desc <<END
+Run a profile of sass.
+  TIMES=n sets the number of runs. Defaults to 1000.
+  FILE=str sets the file to profile. Defaults to 'complex'.
+  OUTPUT=str sets the ruby-prof output format.
+    Can be Flat, CallInfo, or Graph. Defaults to Flat. Defaults to Flat.
+END
+  task :profile do
+    times  = (ENV['TIMES'] || '1000').to_i
+    file   = ENV['FILE']
+
+    require 'lib/sass'
+
+    file = File.read(scope("test/sass/templates/#{file || 'complex'}.sass"))
+    result = RubyProf.profile { times.times { Sass::Engine.new(file).render } }
+
+    RubyProf.const_get("#{(ENV['OUTPUT'] || 'Flat').capitalize}Printer").new(result).print 
+  end
+rescue LoadError; end
+
+# ----- Handling Updates -----
+
+def email_on_error
+  yield
+rescue Exception => e
+  IO.popen("sendmail nex342 gmail com", "w") do |sm|
+    sm << "From: nex3 nex-3 com\n" <<
+      "To: nex342 gmail com\n" <<
+      "Subject: Exception when running rake #{Rake.application.top_level_tasks.join(', ')}\n" <<
+      e.message << "\n\n" <<
+      e.backtrace.join("\n")
+  end
+ensure
+  raise e if e
+end
+
+def ensure_git_cleanup
+  email_on_error {yield}
+ensure
+  sh %{git reset --hard HEAD}
+  sh %{git clean -xdf}
+  sh %{git checkout master}
+end
+
+task :handle_update do
+  email_on_error do
+    unless ENV["REF"] =~ %r{^refs/heads/(master|stable|sass-pages)$}
+      puts "#{'=' * 20} Ignoring rake handle_update REF=#{ENV["REF"].inspect}"
+      next
+    end
+    branch = $1
+
+    puts
+    puts
+    puts '=' * 150
+    puts "Running rake handle_update REF=#{ENV["REF"].inspect}"
+
+    sh %{git fetch origin}
+    sh %{git checkout stable}
+    sh %{git reset --hard origin/stable}
+    sh %{git checkout master}
+    sh %{git reset --hard origin/master}
+
+    case branch
+    when "master"
+      sh %{rake release_edge --trace}
+    when "stable", "sass-pages"
+      sh %{rake pages --trace}
+    end
+
+    puts 'Done running handle_update'
+    puts '=' * 150
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/VERSION b/backends/css/gems/sass-3.4.9/VERSION
new file mode 100644
index 0000000..7bcbb38
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/VERSION
@@ -0,0 +1 @@
+3.4.9
diff --git a/backends/css/gems/sass-3.4.9/VERSION_DATE b/backends/css/gems/sass-3.4.9/VERSION_DATE
new file mode 100644
index 0000000..6df282b
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/VERSION_DATE
@@ -0,0 +1 @@
+25 November 2014 01:40:45 UTC
diff --git a/backends/css/gems/sass-3.4.9/VERSION_NAME b/backends/css/gems/sass-3.4.9/VERSION_NAME
new file mode 100644
index 0000000..6dc9b26
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/VERSION_NAME
@@ -0,0 +1 @@
+Selective Steve
diff --git a/backends/css/gems/sass-3.4.9/bin/sass b/backends/css/gems/sass-3.4.9/bin/sass
new file mode 100755
index 0000000..62d6d0c
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/bin/sass
@@ -0,0 +1,13 @@
+#!/usr/bin/env ruby
+# The command line Sass parser.
+
+THIS_FILE = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
+begin
+  require File.dirname(THIS_FILE) + '/../lib/sass'
+rescue LoadError
+  require 'sass'
+end
+require 'sass/exec'
+
+opts = Sass::Exec::SassScss.new(ARGV, :sass)
+opts.parse!
diff --git a/backends/css/gems/sass-3.4.9/bin/sass-convert b/backends/css/gems/sass-3.4.9/bin/sass-convert
new file mode 100755
index 0000000..b276253
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/bin/sass-convert
@@ -0,0 +1,12 @@
+#!/usr/bin/env ruby
+
+THIS_FILE = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
+begin
+  require File.dirname(THIS_FILE) + '/../lib/sass'
+rescue LoadError
+  require 'sass'
+end
+require 'sass/exec'
+
+opts = Sass::Exec::SassConvert.new(ARGV)
+opts.parse!
diff --git a/backends/css/gems/sass-3.4.9/bin/scss b/backends/css/gems/sass-3.4.9/bin/scss
new file mode 100755
index 0000000..ce3c4ad
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/bin/scss
@@ -0,0 +1,13 @@
+#!/usr/bin/env ruby
+# The command line Sass parser.
+
+THIS_FILE = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
+begin
+  require File.dirname(THIS_FILE) + '/../lib/sass'
+rescue LoadError
+  require 'sass'
+end
+require 'sass/exec'
+
+opts = Sass::Exec::SassScss.new(ARGV, :scss)
+opts.parse!
diff --git a/backends/css/gems/sass-3.2.12/extra/update_watch.rb 
b/backends/css/gems/sass-3.4.9/extra/update_watch.rb
similarity index 100%
rename from backends/css/gems/sass-3.2.12/extra/update_watch.rb
rename to backends/css/gems/sass-3.4.9/extra/update_watch.rb
diff --git a/backends/css/gems/sass-3.2.12/init.rb b/backends/css/gems/sass-3.4.9/init.rb
similarity index 100%
rename from backends/css/gems/sass-3.2.12/init.rb
rename to backends/css/gems/sass-3.4.9/init.rb
diff --git a/backends/css/gems/sass-3.4.9/lib/sass.rb b/backends/css/gems/sass-3.4.9/lib/sass.rb
new file mode 100644
index 0000000..c4def2d
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass.rb
@@ -0,0 +1,102 @@
+dir = File.dirname(__FILE__)
+$LOAD_PATH.unshift dir unless $LOAD_PATH.include?(dir)
+
+require 'sass/version'
+
+# The module that contains everything Sass-related:
+#
+# * {Sass::Engine} is the class used to render Sass/SCSS within Ruby code.
+# * {Sass::Plugin} is interfaces with web frameworks (Rails and Merb in particular).
+# * {Sass::SyntaxError} is raised when Sass encounters an error.
+# * {Sass::CSS} handles conversion of CSS to Sass.
+#
+# Also see the {file:SASS_REFERENCE.md full Sass reference}.
+module Sass
+  class << self
+    # @private
+    attr_accessor :tests_running
+  end
+
+  # The global load paths for Sass files. This is meant for plugins and
+  # libraries to register the paths to their Sass stylesheets to that they may
+  # be ` imported`  This load path is used by every instance of {Sass::Engine}.
+  # They are lower-precedence than any load paths passed in via the
+  # {file:SASS_REFERENCE.md#load_paths-option `:load_paths` option}.
+  #
+  # If the `SASS_PATH` environment variable is set,
+  # the initial value of `load_paths` will be initialized based on that.
+  # The variable should be a colon-separated list of path names
+  # (semicolon-separated on Windows).
+  #
+  # Note that files on the global load path are never compiled to CSS
+  # themselves, even if they aren't partials. They exist only to be imported.
+  #
+  # @example
+  #   Sass.load_paths << File.dirname(__FILE__ + '/sass')
+  # @return [Array<String, Pathname, Sass::Importers::Base>]
+  def self.load_paths
+    @load_paths ||= if ENV['SASS_PATH']
+                      ENV['SASS_PATH'].split(Sass::Util.windows? ? ';' : ':')
+                    else
+                      []
+                    end
+  end
+
+  # Compile a Sass or SCSS string to CSS.
+  # Defaults to SCSS.
+  #
+  # @param contents [String] The contents of the Sass file.
+  # @param options [{Symbol => Object}] An options hash;
+  #   see {file:SASS_REFERENCE.md#sass_options the Sass options documentation}
+  # @raise [Sass::SyntaxError] if there's an error in the document
+  # @raise [Encoding::UndefinedConversionError] if the source encoding
+  #   cannot be converted to UTF-8
+  # @raise [ArgumentError] if the document uses an unknown encoding with ` charset`
+  def self.compile(contents, options = {})
+    options[:syntax] ||= :scss
+    Engine.new(contents, options).to_css
+  end
+
+  # Compile a file on disk to CSS.
+  #
+  # @raise [Sass::SyntaxError] if there's an error in the document
+  # @raise [Encoding::UndefinedConversionError] if the source encoding
+  #   cannot be converted to UTF-8
+  # @raise [ArgumentError] if the document uses an unknown encoding with ` charset`
+  #
+  # @overload compile_file(filename, options = {})
+  #   Return the compiled CSS rather than writing it to a file.
+  #
+  #   @param filename [String] The path to the Sass, SCSS, or CSS file on disk.
+  #   @param options [{Symbol => Object}] An options hash;
+  #     see {file:SASS_REFERENCE.md#sass_options the Sass options documentation}
+  #   @return [String] The compiled CSS.
+  #
+  # @overload compile_file(filename, css_filename, options = {})
+  #   Write the compiled CSS to a file.
+  #
+  #   @param filename [String] The path to the Sass, SCSS, or CSS file on disk.
+  #   @param options [{Symbol => Object}] An options hash;
+  #     see {file:SASS_REFERENCE.md#sass_options the Sass options documentation}
+  #   @param css_filename [String] The location to which to write the compiled CSS.
+  def self.compile_file(filename, *args)
+    options = args.last.is_a?(Hash) ? args.pop : {}
+    css_filename = args.shift
+    result = Sass::Engine.for_file(filename, options).render
+    if css_filename
+      options[:css_filename] ||= css_filename
+      open(css_filename, "w") {|css_file| css_file.write(result)}
+      nil
+    else
+      result
+    end
+  end
+end
+
+require 'sass/logger'
+require 'sass/util'
+
+require 'sass/engine'
+require 'sass/plugin' if defined?(Merb::Plugins)
+require 'sass/railtie'
+require 'sass/features'
diff --git a/backends/css/gems/sass-3.2.12/lib/sass/cache_stores.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/cache_stores.rb
similarity index 100%
rename from backends/css/gems/sass-3.2.12/lib/sass/cache_stores.rb
rename to backends/css/gems/sass-3.4.9/lib/sass/cache_stores.rb
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/cache_stores/base.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/cache_stores/base.rb
new file mode 100644
index 0000000..e239666
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/cache_stores/base.rb
@@ -0,0 +1,88 @@
+module Sass
+  module CacheStores
+    # An abstract base class for backends for the Sass cache.
+    # Any key-value store can act as such a backend;
+    # it just needs to implement the
+    # \{#_store} and \{#_retrieve} methods.
+    #
+    # To use a cache store with Sass,
+    # use the {file:SASS_REFERENCE.md#cache_store-option `:cache_store` option}.
+    #
+    # @abstract
+    class Base
+      # Store cached contents for later retrieval
+      # Must be implemented by all CacheStore subclasses
+      #
+      # Note: cache contents contain binary data.
+      #
+      # @param key [String] The key to store the contents under
+      # @param version [String] The current sass version.
+      #                Cached contents must not be retrieved across different versions of sass.
+      # @param sha [String] The sha of the sass source.
+      #                Cached contents must not be retrieved if the sha has changed.
+      # @param contents [String] The contents to store.
+      def _store(key, version, sha, contents)
+        raise "#{self.class} must implement #_store."
+      end
+
+      # Retrieved cached contents.
+      # Must be implemented by all subclasses.
+      #
+      # Note: if the key exists but the sha or version have changed,
+      # then the key may be deleted by the cache store, if it wants to do so.
+      #
+      # @param key [String] The key to retrieve
+      # @param version [String] The current sass version.
+      #                Cached contents must not be retrieved across different versions of sass.
+      # @param sha [String] The sha of the sass source.
+      #                Cached contents must not be retrieved if the sha has changed.
+      # @return [String] The contents that were previously stored.
+      # @return [NilClass] when the cache key is not found or the version or sha have changed.
+      def _retrieve(key, version, sha)
+        raise "#{self.class} must implement #_retrieve."
+      end
+
+      # Store a {Sass::Tree::RootNode}.
+      #
+      # @param key [String] The key to store it under.
+      # @param sha [String] The checksum for the contents that are being stored.
+      # @param root [Object] The root node to cache.
+      def store(key, sha, root)
+        _store(key, Sass::VERSION, sha, Marshal.dump(root))
+      rescue TypeError, LoadError => e
+        Sass::Util.sass_warn "Warning. Error encountered while saving cache #{path_to(key)}: #{e}"
+        nil
+      end
+
+      # Retrieve a {Sass::Tree::RootNode}.
+      #
+      # @param key [String] The key the root element was stored under.
+      # @param sha [String] The checksum of the root element's content.
+      # @return [Object] The cached object.
+      def retrieve(key, sha)
+        contents = _retrieve(key, Sass::VERSION, sha)
+        Marshal.load(contents) if contents
+      rescue EOFError, TypeError, ArgumentError, LoadError => e
+        Sass::Util.sass_warn "Warning. Error encountered while reading cache #{path_to(key)}: #{e}"
+        nil
+      end
+
+      # Return the key for the sass file.
+      #
+      # The `(sass_dirname, sass_basename)` pair
+      # should uniquely identify the Sass document,
+      # but otherwise there are no restrictions on their content.
+      #
+      # @param sass_dirname [String]
+      #   The fully-expanded location of the Sass file.
+      #   This corresponds to the directory name on a filesystem.
+      # @param sass_basename [String] The name of the Sass file that is being referenced.
+      #   This corresponds to the basename on a filesystem.
+      def key(sass_dirname, sass_basename)
+        dir = Digest::SHA1.hexdigest(sass_dirname)
+        filename = "#{sass_basename}c"
+        "#{dir}/#{filename}"
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/cache_stores/chain.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/cache_stores/chain.rb
new file mode 100644
index 0000000..914c111
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/cache_stores/chain.rb
@@ -0,0 +1,34 @@
+module Sass
+  module CacheStores
+    # A meta-cache that chains multiple caches together.
+    # Specifically:
+    #
+    # * All `#store`s are passed to all caches.
+    # * `#retrieve`s are passed to each cache until one has a hit.
+    # * When one cache has a hit, the value is `#store`d in all earlier caches.
+    class Chain < Base
+      # Create a new cache chaining the given caches.
+      #
+      # @param caches [Array<Sass::CacheStores::Base>] The caches to chain.
+      def initialize(*caches)
+        @caches = caches
+      end
+
+      # @see Base#store
+      def store(key, sha, obj)
+        @caches.each {|c| c.store(key, sha, obj)}
+      end
+
+      # @see Base#retrieve
+      def retrieve(key, sha)
+        @caches.each_with_index do |c, i|
+          obj = c.retrieve(key, sha)
+          next unless obj
+          @caches[0...i].each {|prev| prev.store(key, sha, obj)}
+          return obj
+        end
+        nil
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/cache_stores/filesystem.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/cache_stores/filesystem.rb
new file mode 100644
index 0000000..eea7c53
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/cache_stores/filesystem.rb
@@ -0,0 +1,60 @@
+require 'fileutils'
+
+module Sass
+  module CacheStores
+    # A backend for the Sass cache using the filesystem.
+    class Filesystem < Base
+      # The directory where the cached files will be stored.
+      #
+      # @return [String]
+      attr_accessor :cache_location
+
+      # @param cache_location [String] see \{#cache\_location}
+      def initialize(cache_location)
+        @cache_location = cache_location
+      end
+
+      # @see Base#\_retrieve
+      def _retrieve(key, version, sha)
+        return unless File.readable?(path_to(key))
+        File.open(path_to(key), "rb") do |f|
+          if f.readline("\n").strip == version && f.readline("\n").strip == sha
+            return f.read
+          end
+        end
+        begin
+          File.unlink path_to(key)
+        rescue Errno::ENOENT
+          # Already deleted. Race condition?
+        end
+        nil
+      rescue EOFError, TypeError, ArgumentError => e
+        Sass::Util.sass_warn "Warning. Error encountered while reading cache #{path_to(key)}: #{e}"
+      end
+
+      # @see Base#\_store
+      def _store(key, version, sha, contents)
+        compiled_filename = path_to(key)
+        FileUtils.mkdir_p(File.dirname(compiled_filename))
+        Sass::Util.atomic_create_and_write_file(compiled_filename, 0600) do |f|
+          f.puts(version)
+          f.puts(sha)
+          f.write(contents)
+        end
+      rescue Errno::EACCES
+        # pass
+      end
+
+      private
+
+      # Returns the path to a file for the given key.
+      #
+      # @param key [String]
+      # @return [String] The path to the cache file.
+      def path_to(key)
+        key = key.gsub(/[<>:\\|?*%]/) {|c| "%%%03d" % Sass::Util.ord(c)}
+        File.join(cache_location, key)
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/cache_stores/memory.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/cache_stores/memory.rb
new file mode 100644
index 0000000..ac7eb3d
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/cache_stores/memory.rb
@@ -0,0 +1,47 @@
+module Sass
+  module CacheStores
+    # A backend for the Sass cache using in-process memory.
+    class Memory < Base
+      # Since the {Memory} store is stored in the Sass tree's options hash,
+      # when the options get serialized as part of serializing the tree,
+      # you get crazy exponential growth in the size of the cached objects
+      # unless you don't dump the cache.
+      #
+      # @private
+      def _dump(depth)
+        ""
+      end
+
+      # If we deserialize this class, just make a new empty one.
+      #
+      # @private
+      def self._load(repr)
+        Memory.new
+      end
+
+      # Create a new, empty cache store.
+      def initialize
+        @contents = {}
+      end
+
+      # @see Base#retrieve
+      def retrieve(key, sha)
+        if @contents.has_key?(key)
+          return unless @contents[key][:sha] == sha
+          obj = @contents[key][:obj]
+          obj.respond_to?(:deep_copy) ? obj.deep_copy : obj.dup
+        end
+      end
+
+      # @see Base#store
+      def store(key, sha, obj)
+        @contents[key] = {:sha => sha, :obj => obj}
+      end
+
+      # Destructively clear the cache.
+      def reset!
+        @contents = {}
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/cache_stores/null.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/cache_stores/null.rb
new file mode 100644
index 0000000..f14f4c7
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/cache_stores/null.rb
@@ -0,0 +1,25 @@
+module Sass
+  module CacheStores
+    # Doesn't store anything, but records what things it should have stored.
+    # This doesn't currently have any use except for testing and debugging.
+    #
+    # @private
+    class Null < Base
+      def initialize
+        @keys = {}
+      end
+
+      def _retrieve(key, version, sha)
+        nil
+      end
+
+      def _store(key, version, sha, contents)
+        @keys[key] = true
+      end
+
+      def was_set?(key)
+        @keys[key]
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/callbacks.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/callbacks.rb
new file mode 100644
index 0000000..8d9cd77
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/callbacks.rb
@@ -0,0 +1,67 @@
+module Sass
+  # A lightweight infrastructure for defining and running callbacks.
+  # Callbacks are defined using \{#define\_callback\} at the class level,
+  # and called using `run_#{name}` at the instance level.
+  #
+  # Clients can add callbacks by calling the generated `on_#{name}` method,
+  # and passing in a block that's run when the callback is activated.
+  #
+  # @example Define a callback
+  #   class Munger
+  #     extend Sass::Callbacks
+  #     define_callback :string_munged
+  #
+  #     def munge(str)
+  #       res = str.gsub(/[a-z]/, '\1\1')
+  #       run_string_munged str, res
+  #       res
+  #     end
+  #   end
+  #
+  # @example Use a callback
+  #   m = Munger.new
+  #   m.on_string_munged {|str, res| puts "#{str} was munged into #{res}!"}
+  #   m.munge "bar" #=> bar was munged into bbaarr!
+  module Callbacks
+    # Automatically includes {InstanceMethods}
+    # when something extends this module.
+    #
+    # @param base [Module]
+    def self.extended(base)
+      base.send(:include, InstanceMethods)
+    end
+
+    protected
+
+    module InstanceMethods
+      # Removes all callbacks registered against this object.
+      def clear_callbacks!
+        @_sass_callbacks = {}
+      end
+    end
+
+    # Define a callback with the given name.
+    # This will define an `on_#{name}` method
+    # that registers a block,
+    # and a `run_#{name}` method that runs that block
+    # (optionall with some arguments).
+    #
+    # @param name [Symbol] The name of the callback
+    # @return [void]
+    def define_callback(name)
+      class_eval <<RUBY, __FILE__, __LINE__ + 1
+def on_#{name}(&block)
+  @_sass_callbacks ||= {}
+  (@_sass_callbacks[#{name.inspect}] ||= []) << block
+end
+
+def run_#{name}(*args)
+  return unless @_sass_callbacks
+  return unless @_sass_callbacks[#{name.inspect}]
+  @_sass_callbacks[#{name.inspect}].each {|c| c[*args]}
+end
+private :run_#{name}
+RUBY
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/css.rb b/backends/css/gems/sass-3.4.9/lib/sass/css.rb
new file mode 100644
index 0000000..15aa0f4
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/css.rb
@@ -0,0 +1,407 @@
+require File.dirname(__FILE__) + '/../sass'
+require 'sass/tree/node'
+require 'sass/scss/css_parser'
+
+module Sass
+  # This class converts CSS documents into Sass or SCSS templates.
+  # It works by parsing the CSS document into a {Sass::Tree} structure,
+  # and then applying various transformations to the structure
+  # to produce more concise and idiomatic Sass/SCSS.
+  #
+  # Example usage:
+  #
+  #     Sass::CSS.new("p { color: blue }").render(:sass) #=> "p\n  color: blue"
+  #     Sass::CSS.new("p { color: blue }").render(:scss) #=> "p {\n  color: blue; }"
+  class CSS
+    # @param template [String] The CSS stylesheet.
+    #   This stylesheet can be encoded using any encoding
+    #   that can be converted to Unicode.
+    #   If the stylesheet contains an ` charset` declaration,
+    #   that overrides the Ruby encoding
+    #   (see {file:SASS_REFERENCE.md#encodings the encoding documentation})
+    # @option options :old [Boolean] (false)
+    #     Whether or not to output old property syntax
+    #     (`:color blue` as opposed to `color: blue`).
+    #     This is only meaningful when generating Sass code,
+    #     rather than SCSS.
+    # @option options :indent [String] ("  ")
+    #     The string to use for indenting each line. Defaults to two spaces.
+    def initialize(template, options = {})
+      if template.is_a? IO
+        template = template.read
+      end
+
+      @options = options.dup
+      # Backwards compatibility
+      @options[:old] = true if @options[:alternate] == false
+      @template = template
+    end
+
+    # Converts the CSS template into Sass or SCSS code.
+    #
+    # @param fmt [Symbol] `:sass` or `:scss`, designating the format to return.
+    # @return [String] The resulting Sass or SCSS code
+    # @raise [Sass::SyntaxError] if there's an error parsing the CSS template
+    def render(fmt = :sass)
+      check_encoding!
+      build_tree.send("to_#{fmt}", @options).strip + "\n"
+    rescue Sass::SyntaxError => err
+      err.modify_backtrace(:filename => @options[:filename] || '(css)')
+      raise err
+    end
+
+    # Returns the original encoding of the document,
+    # or `nil` under Ruby 1.8.
+    #
+    # @return [Encoding, nil]
+    # @raise [Encoding::UndefinedConversionError] if the source encoding
+    #   cannot be converted to UTF-8
+    # @raise [ArgumentError] if the document uses an unknown encoding with ` charset`
+    def source_encoding
+      check_encoding!
+      @original_encoding
+    end
+
+    private
+
+    def check_encoding!
+      return if @checked_encoding
+      @checked_encoding = true
+      @template, @original_encoding = Sass::Util.check_sass_encoding(@template)
+    end
+
+    # Parses the CSS template and applies various transformations
+    #
+    # @return [Tree::Node] The root node of the parsed tree
+    def build_tree
+      root = Sass::SCSS::CssParser.new(@template, @options[:filename], nil).parse
+      parse_selectors    root
+      expand_commas      root
+      nest_seqs          root
+      parent_ref_rules   root
+      flatten_rules      root
+      bubble_subject     root
+      fold_commas        root
+      dump_selectors     root
+      root
+    end
+
+    # Parse all the selectors in the document and assign them to
+    # {Sass::Tree::RuleNode#parsed_rules}.
+    #
+    # @param root [Tree::Node] The parent node
+    def parse_selectors(root)
+      root.children.each do |child|
+        next parse_selectors(child) if child.is_a?(Tree::DirectiveNode)
+        next unless child.is_a?(Tree::RuleNode)
+        parser = Sass::SCSS::CssParser.new(child.rule.first, child.filename, nil, child.line)
+        child.parsed_rules = parser.parse_selector
+      end
+    end
+
+    # Transform
+    #
+    #     foo, bar, baz
+    #       color: blue
+    #
+    # into
+    #
+    #     foo
+    #       color: blue
+    #     bar
+    #       color: blue
+    #     baz
+    #       color: blue
+    #
+    # @param root [Tree::Node] The parent node
+    def expand_commas(root)
+      root.children.map! do |child|
+        # child.parsed_rules.members.size > 1 iff the rule contains a comma
+        unless child.is_a?(Tree::RuleNode) && child.parsed_rules.members.size > 1
+          expand_commas(child) if child.is_a?(Tree::DirectiveNode)
+          next child
+        end
+        child.parsed_rules.members.map do |seq|
+          node = Tree::RuleNode.new([])
+          node.parsed_rules = make_cseq(seq)
+          node.children = child.children
+          node
+        end
+      end
+      root.children.flatten!
+    end
+
+    # Make rules use nesting so that
+    #
+    #     foo
+    #       color: green
+    #     foo bar
+    #       color: red
+    #     foo baz
+    #       color: blue
+    #
+    # becomes
+    #
+    #     foo
+    #       color: green
+    #       bar
+    #         color: red
+    #       baz
+    #         color: blue
+    #
+    # @param root [Tree::Node] The parent node
+    def nest_seqs(root)
+      current_rule = nil
+      root.children.map! do |child|
+        unless child.is_a?(Tree::RuleNode)
+          nest_seqs(child) if child.is_a?(Tree::DirectiveNode)
+          next child
+        end
+
+        seq = first_seq(child)
+        seq.members.reject! {|sseq| sseq == "\n"}
+        first, rest = seq.members.first, seq.members[1..-1]
+
+        if current_rule.nil? || first_sseq(current_rule) != first
+          current_rule = Tree::RuleNode.new([])
+          current_rule.parsed_rules = make_seq(first)
+        end
+
+        if rest.empty?
+          current_rule.children += child.children
+        else
+          child.parsed_rules = make_seq(*rest)
+          current_rule << child
+        end
+
+        current_rule
+      end
+      root.children.compact!
+      root.children.uniq!
+
+      root.children.each {|v| nest_seqs(v)}
+    end
+
+    # Make rules use parent refs so that
+    #
+    #     foo
+    #       color: green
+    #     foo.bar
+    #       color: blue
+    #
+    # becomes
+    #
+    #     foo
+    #       color: green
+    #       &.bar
+    #         color: blue
+    #
+    # @param root [Tree::Node] The parent node
+    def parent_ref_rules(root)
+      current_rule = nil
+      root.children.map! do |child|
+        unless child.is_a?(Tree::RuleNode)
+          parent_ref_rules(child) if child.is_a?(Tree::DirectiveNode)
+          next child
+        end
+
+        sseq = first_sseq(child)
+        next child unless sseq.is_a?(Sass::Selector::SimpleSequence)
+
+        firsts, rest = [sseq.members.first], sseq.members[1..-1]
+        firsts.push rest.shift if firsts.first.is_a?(Sass::Selector::Parent)
+
+        last_simple_subject = rest.empty? && sseq.subject?
+        if current_rule.nil? || first_sseq(current_rule).members != firsts ||
+            !!first_sseq(current_rule).subject? != !!last_simple_subject
+          current_rule = Tree::RuleNode.new([])
+          current_rule.parsed_rules = make_sseq(last_simple_subject, *firsts)
+        end
+
+        if rest.empty?
+          current_rule.children += child.children
+        else
+          rest.unshift Sass::Selector::Parent.new
+          child.parsed_rules = make_sseq(sseq.subject?, *rest)
+          current_rule << child
+        end
+
+        current_rule
+      end
+      root.children.compact!
+      root.children.uniq!
+
+      root.children.each {|v| parent_ref_rules(v)}
+    end
+
+    # Flatten rules so that
+    #
+    #     foo
+    #       bar
+    #         color: red
+    #
+    # becomes
+    #
+    #     foo bar
+    #       color: red
+    #
+    # and
+    #
+    #     foo
+    #       &.bar
+    #         color: blue
+    #
+    # becomes
+    #
+    #     foo.bar
+    #       color: blue
+    #
+    # @param root [Tree::Node] The parent node
+    def flatten_rules(root)
+      root.children.each do |child|
+        case child
+        when Tree::RuleNode
+          flatten_rule(child)
+        when Tree::DirectiveNode
+          flatten_rules(child)
+        end
+      end
+    end
+
+    # Flattens a single rule.
+    #
+    # @param rule [Tree::RuleNode] The candidate for flattening
+    # @see #flatten_rules
+    def flatten_rule(rule)
+      while rule.children.size == 1 && rule.children.first.is_a?(Tree::RuleNode)
+        child = rule.children.first
+
+        if first_simple_sel(child).is_a?(Sass::Selector::Parent)
+          rule.parsed_rules = child.parsed_rules.resolve_parent_refs(rule.parsed_rules)
+        else
+          rule.parsed_rules = make_seq(*(first_seq(rule).members + first_seq(child).members))
+        end
+
+        rule.children = child.children
+      end
+
+      flatten_rules(rule)
+    end
+
+    def bubble_subject(root)
+      root.children.each do |child|
+        bubble_subject(child) if child.is_a?(Tree::RuleNode) || child.is_a?(Tree::DirectiveNode)
+        next unless child.is_a?(Tree::RuleNode) && !child.children.empty?
+        next unless child.children.all? do |c|
+          next unless c.is_a?(Tree::RuleNode)
+          first_simple_sel(c).is_a?(Sass::Selector::Parent) && first_sseq(c).subject?
+        end
+        first_sseq(child).subject = true
+        child.children.each {|c| first_sseq(c).subject = false}
+      end
+    end
+
+    # Transform
+    #
+    #     foo
+    #       bar
+    #         color: blue
+    #       baz
+    #         color: blue
+    #
+    # into
+    #
+    #     foo
+    #       bar, baz
+    #         color: blue
+    #
+    # @param root [Tree::Node] The parent node
+    def fold_commas(root)
+      prev_rule = nil
+      root.children.map! do |child|
+        unless child.is_a?(Tree::RuleNode)
+          fold_commas(child) if child.is_a?(Tree::DirectiveNode)
+          next child
+        end
+
+        if prev_rule && prev_rule.children.map {|c| c.to_sass} == child.children.map {|c| c.to_sass}
+          prev_rule.parsed_rules.members << first_seq(child)
+          next nil
+        end
+
+        fold_commas(child)
+        prev_rule = child
+        child
+      end
+      root.children.compact!
+    end
+
+    # Dump all the parsed {Sass::Tree::RuleNode} selectors to strings.
+    #
+    # @param root [Tree::Node] The parent node
+    def dump_selectors(root)
+      root.children.each do |child|
+        next dump_selectors(child) if child.is_a?(Tree::DirectiveNode)
+        next unless child.is_a?(Tree::RuleNode)
+        child.rule = [child.parsed_rules.to_s]
+        dump_selectors(child)
+      end
+    end
+
+    # Create a {Sass::Selector::CommaSequence}.
+    #
+    # @param seqs [Array<Sass::Selector::Sequence>]
+    # @return [Sass::Selector::CommaSequence]
+    def make_cseq(*seqs)
+      Sass::Selector::CommaSequence.new(seqs)
+    end
+
+    # Create a {Sass::Selector::CommaSequence} containing only a single
+    # {Sass::Selector::Sequence}.
+    #
+    # @param sseqs [Array<Sass::Selector::Sequence, String>]
+    # @return [Sass::Selector::CommaSequence]
+    def make_seq(*sseqs)
+      make_cseq(Sass::Selector::Sequence.new(sseqs))
+    end
+
+    # Create a {Sass::Selector::CommaSequence} containing only a single
+    # {Sass::Selector::Sequence} which in turn contains only a single
+    # {Sass::Selector::SimpleSequence}.
+    #
+    # @param subject [Boolean] Whether this is a subject selector
+    # @param sseqs [Array<Sass::Selector::Sequence, String>]
+    # @return [Sass::Selector::CommaSequence]
+    def make_sseq(subject, *sseqs)
+      make_seq(Sass::Selector::SimpleSequence.new(sseqs, subject))
+    end
+
+    # Return the first {Sass::Selector::Sequence} in a {Sass::Tree::RuleNode}.
+    #
+    # @param rule [Sass::Tree::RuleNode]
+    # @return [Sass::Selector::Sequence]
+    def first_seq(rule)
+      rule.parsed_rules.members.first
+    end
+
+    # Return the first {Sass::Selector::SimpleSequence} in a
+    # {Sass::Tree::RuleNode}.
+    #
+    # @param rule [Sass::Tree::RuleNode]
+    # @return [Sass::Selector::SimpleSequence, String]
+    def first_sseq(rule)
+      first_seq(rule).members.first
+    end
+
+    # Return the first {Sass::Selector::Simple} in a {Sass::Tree::RuleNode},
+    # unless the rule begins with a combinator.
+    #
+    # @param rule [Sass::Tree::RuleNode]
+    # @return [Sass::Selector::Simple?]
+    def first_simple_sel(rule)
+      sseq = first_sseq(rule)
+      return unless sseq.is_a?(Sass::Selector::SimpleSequence)
+      sseq.members.first
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/engine.rb b/backends/css/gems/sass-3.4.9/lib/sass/engine.rb
new file mode 100644
index 0000000..3650e43
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/engine.rb
@@ -0,0 +1,1182 @@
+require 'set'
+require 'digest/sha1'
+require 'sass/cache_stores'
+require 'sass/source/position'
+require 'sass/source/range'
+require 'sass/source/map'
+require 'sass/tree/node'
+require 'sass/tree/root_node'
+require 'sass/tree/rule_node'
+require 'sass/tree/comment_node'
+require 'sass/tree/prop_node'
+require 'sass/tree/directive_node'
+require 'sass/tree/media_node'
+require 'sass/tree/supports_node'
+require 'sass/tree/css_import_node'
+require 'sass/tree/variable_node'
+require 'sass/tree/mixin_def_node'
+require 'sass/tree/mixin_node'
+require 'sass/tree/trace_node'
+require 'sass/tree/content_node'
+require 'sass/tree/function_node'
+require 'sass/tree/return_node'
+require 'sass/tree/extend_node'
+require 'sass/tree/if_node'
+require 'sass/tree/while_node'
+require 'sass/tree/for_node'
+require 'sass/tree/each_node'
+require 'sass/tree/debug_node'
+require 'sass/tree/warn_node'
+require 'sass/tree/import_node'
+require 'sass/tree/charset_node'
+require 'sass/tree/at_root_node'
+require 'sass/tree/keyframe_rule_node'
+require 'sass/tree/error_node'
+require 'sass/tree/visitors/base'
+require 'sass/tree/visitors/perform'
+require 'sass/tree/visitors/cssize'
+require 'sass/tree/visitors/extend'
+require 'sass/tree/visitors/convert'
+require 'sass/tree/visitors/to_css'
+require 'sass/tree/visitors/deep_copy'
+require 'sass/tree/visitors/set_options'
+require 'sass/tree/visitors/check_nesting'
+require 'sass/selector'
+require 'sass/environment'
+require 'sass/script'
+require 'sass/scss'
+require 'sass/stack'
+require 'sass/error'
+require 'sass/importers'
+require 'sass/shared'
+require 'sass/media'
+require 'sass/supports'
+
+module Sass
+  # A Sass mixin or function.
+  #
+  # `name`: `String`
+  # : The name of the mixin/function.
+  #
+  # `args`: `Array<(Script::Tree::Node, Script::Tree::Node)>`
+  # : The arguments for the mixin/function.
+  #   Each element is a tuple containing the variable node of the argument
+  #   and the parse tree for the default value of the argument.
+  #
+  # `splat`: `Script::Tree::Node?`
+  # : The variable node of the splat argument for this callable, or null.
+  #
+  # `environment`: {Sass::Environment}
+  # : The environment in which the mixin/function was defined.
+  #   This is captured so that the mixin/function can have access
+  #   to local variables defined in its scope.
+  #
+  # `tree`: `Array<Tree::Node>`
+  # : The parse tree for the mixin/function.
+  #
+  # `has_content`: `Boolean`
+  # : Whether the callable accepts a content block.
+  #
+  # `type`: `String`
+  # : The user-friendly name of the type of the callable.
+  Callable = Struct.new(:name, :args, :splat, :environment, :tree, :has_content, :type)
+
+  # This class handles the parsing and compilation of the Sass template.
+  # Example usage:
+  #
+  #     template = File.load('stylesheets/sassy.sass')
+  #     sass_engine = Sass::Engine.new(template)
+  #     output = sass_engine.render
+  #     puts output
+  class Engine
+    # A line of Sass code.
+    #
+    # `text`: `String`
+    # : The text in the line, without any whitespace at the beginning or end.
+    #
+    # `tabs`: `Fixnum`
+    # : The level of indentation of the line.
+    #
+    # `index`: `Fixnum`
+    # : The line number in the original document.
+    #
+    # `offset`: `Fixnum`
+    # : The number of bytes in on the line that the text begins.
+    #   This ends up being the number of bytes of leading whitespace.
+    #
+    # `filename`: `String`
+    # : The name of the file in which this line appeared.
+    #
+    # `children`: `Array<Line>`
+    # : The lines nested below this one.
+    #
+    # `comment_tab_str`: `String?`
+    # : The prefix indentation for this comment, if it is a comment.
+    class Line < Struct.new(:text, :tabs, :index, :offset, :filename, :children, :comment_tab_str)
+      def comment?
+        text[0] == COMMENT_CHAR && (text[1] == SASS_COMMENT_CHAR || text[1] == CSS_COMMENT_CHAR)
+      end
+    end
+
+    # The character that begins a CSS property.
+    PROPERTY_CHAR  = ?:
+
+    # The character that designates the beginning of a comment,
+    # either Sass or CSS.
+    COMMENT_CHAR = ?/
+
+    # The character that follows the general COMMENT_CHAR and designates a Sass comment,
+    # which is not output as a CSS comment.
+    SASS_COMMENT_CHAR = ?/
+
+    # The character that indicates that a comment allows interpolation
+    # and should be preserved even in `:compressed` mode.
+    SASS_LOUD_COMMENT_CHAR = ?!
+
+    # The character that follows the general COMMENT_CHAR and designates a CSS comment,
+    # which is embedded in the CSS document.
+    CSS_COMMENT_CHAR = ?*
+
+    # The character used to denote a compiler directive.
+    DIRECTIVE_CHAR = ?@
+
+    # Designates a non-parsed rule.
+    ESCAPE_CHAR    = ?\\
+
+    # Designates block as mixin definition rather than CSS rules to output
+    MIXIN_DEFINITION_CHAR = ?=
+
+    # Includes named mixin declared using MIXIN_DEFINITION_CHAR
+    MIXIN_INCLUDE_CHAR    = ?+
+
+    # The regex that matches and extracts data from
+    # properties of the form `:name prop`.
+    PROPERTY_OLD = /^:([^\s=:"]+)\s*(?:\s+|$)(.*)/
+
+    # The default options for Sass::Engine.
+    # @api public
+    DEFAULT_OPTIONS = {
+      :style => :nested,
+      :load_paths => ['.'],
+      :cache => true,
+      :cache_location => './.sass-cache',
+      :syntax => :sass,
+      :filesystem_importer => Sass::Importers::Filesystem
+    }.freeze
+
+    # Converts a Sass options hash into a standard form, filling in
+    # default values and resolving aliases.
+    #
+    # @param options [{Symbol => Object}] The options hash;
+    #   see {file:SASS_REFERENCE.md#sass_options the Sass options documentation}
+    # @return [{Symbol => Object}] The normalized options hash.
+    # @private
+    def self.normalize_options(options)
+      options = DEFAULT_OPTIONS.merge(options.reject {|k, v| v.nil?})
+
+      # If the `:filename` option is passed in without an importer,
+      # assume it's using the default filesystem importer.
+      options[:importer] ||= options[:filesystem_importer].new(".") if options[:filename]
+
+      # Tracks the original filename of the top-level Sass file
+      options[:original_filename] ||= options[:filename]
+
+      options[:cache_store] ||= Sass::CacheStores::Chain.new(
+        Sass::CacheStores::Memory.new, Sass::CacheStores::Filesystem.new(options[:cache_location]))
+      # Support both, because the docs said one and the other actually worked
+      # for quite a long time.
+      options[:line_comments] ||= options[:line_numbers]
+
+      options[:load_paths] = (options[:load_paths] + Sass.load_paths).map do |p|
+        next p unless p.is_a?(String) || (defined?(Pathname) && p.is_a?(Pathname))
+        options[:filesystem_importer].new(p.to_s)
+      end
+
+      # Backwards compatibility
+      options[:property_syntax] ||= options[:attribute_syntax]
+      case options[:property_syntax]
+      when :alternate; options[:property_syntax] = :new
+      when :normal; options[:property_syntax] = :old
+      end
+      options[:sourcemap] = :auto if options[:sourcemap] == true
+      options[:sourcemap] = :none if options[:sourcemap] == false
+
+      options
+    end
+
+    # Returns the {Sass::Engine} for the given file.
+    # This is preferable to Sass::Engine.new when reading from a file
+    # because it properly sets up the Engine's metadata,
+    # enables parse-tree caching,
+    # and infers the syntax from the filename.
+    #
+    # @param filename [String] The path to the Sass or SCSS file
+    # @param options [{Symbol => Object}] The options hash;
+    #   See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
+    # @return [Sass::Engine] The Engine for the given Sass or SCSS file.
+    # @raise [Sass::SyntaxError] if there's an error in the document.
+    def self.for_file(filename, options)
+      had_syntax = options[:syntax]
+
+      if had_syntax
+        # Use what was explicitly specificed
+      elsif filename =~ /\.scss$/
+        options.merge!(:syntax => :scss)
+      elsif filename =~ /\.sass$/
+        options.merge!(:syntax => :sass)
+      end
+
+      Sass::Engine.new(File.read(filename), options.merge(:filename => filename))
+    end
+
+    # The options for the Sass engine.
+    # See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
+    #
+    # @return [{Symbol => Object}]
+    attr_reader :options
+
+    # Creates a new Engine. Note that Engine should only be used directly
+    # when compiling in-memory Sass code.
+    # If you're compiling a single Sass file from the filesystem,
+    # use \{Sass::Engine.for\_file}.
+    # If you're compiling multiple files from the filesystem,
+    # use {Sass::Plugin}.
+    #
+    # @param template [String] The Sass template.
+    #   This template can be encoded using any encoding
+    #   that can be converted to Unicode.
+    #   If the template contains an ` charset` declaration,
+    #   that overrides the Ruby encoding
+    #   (see {file:SASS_REFERENCE.md#encodings the encoding documentation})
+    # @param options [{Symbol => Object}] An options hash.
+    #   See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
+    # @see {Sass::Engine.for_file}
+    # @see {Sass::Plugin}
+    def initialize(template, options = {})
+      @options = self.class.normalize_options(options)
+      @template = template
+    end
+
+    # Render the template to CSS.
+    #
+    # @return [String] The CSS
+    # @raise [Sass::SyntaxError] if there's an error in the document
+    # @raise [Encoding::UndefinedConversionError] if the source encoding
+    #   cannot be converted to UTF-8
+    # @raise [ArgumentError] if the document uses an unknown encoding with ` charset`
+    def render
+      return _to_tree.render unless @options[:quiet]
+      Sass::Util.silence_sass_warnings {_to_tree.render}
+    end
+
+    # Render the template to CSS and return the source map.
+    #
+    # @param sourcemap_uri [String] The sourcemap URI to use in the
+    #   ` sourceMappingURL` comment. If this is relative, it should be relative
+    #   to the location of the CSS file.
+    # @return [(String, Sass::Source::Map)] The rendered CSS and the associated
+    #   source map
+    # @raise [Sass::SyntaxError] if there's an error in the document, or if the
+    #   public URL for this document couldn't be determined.
+    # @raise [Encoding::UndefinedConversionError] if the source encoding
+    #   cannot be converted to UTF-8
+    # @raise [ArgumentError] if the document uses an unknown encoding with ` charset`
+    def render_with_sourcemap(sourcemap_uri)
+      return _render_with_sourcemap(sourcemap_uri) unless @options[:quiet]
+      Sass::Util.silence_sass_warnings {_render_with_sourcemap(sourcemap_uri)}
+    end
+
+    alias_method :to_css, :render
+
+    # Parses the document into its parse tree. Memoized.
+    #
+    # @return [Sass::Tree::Node] The root of the parse tree.
+    # @raise [Sass::SyntaxError] if there's an error in the document
+    def to_tree
+      @tree ||= if @options[:quiet]
+                  Sass::Util.silence_sass_warnings {_to_tree}
+                else
+                  _to_tree
+                end
+    end
+
+    # Returns the original encoding of the document,
+    # or `nil` under Ruby 1.8.
+    #
+    # @return [Encoding, nil]
+    # @raise [Encoding::UndefinedConversionError] if the source encoding
+    #   cannot be converted to UTF-8
+    # @raise [ArgumentError] if the document uses an unknown encoding with ` charset`
+    def source_encoding
+      check_encoding!
+      @source_encoding
+    end
+
+    # Gets a set of all the documents
+    # that are (transitive) dependencies of this document,
+    # not including the document itself.
+    #
+    # @return [[Sass::Engine]] The dependency documents.
+    def dependencies
+      _dependencies(Set.new, engines = Set.new)
+      Sass::Util.array_minus(engines, [self])
+    end
+
+    # Helper for \{#dependencies}.
+    #
+    # @private
+    def _dependencies(seen, engines)
+      key = [ options[:filename], @options[:importer]]
+      return if seen.include?(key)
+      seen << key
+      engines << self
+      to_tree.grep(Tree::ImportNode) do |n|
+        next if n.css_import?
+        n.imported_file._dependencies(seen, engines)
+      end
+    end
+
+    private
+
+    def _render_with_sourcemap(sourcemap_uri)
+      filename = @options[:filename]
+      importer = @options[:importer]
+      sourcemap_dir = @options[:sourcemap_filename] &&
+        File.dirname(File.expand_path(@options[:sourcemap_filename]))
+      if filename.nil?
+        raise Sass::SyntaxError.new(<<ERR)
+Error generating source map: couldn't determine public URL for the source stylesheet.
+  No filename is available so there's nothing for the source map to link to.
+ERR
+      elsif importer.nil?
+        raise Sass::SyntaxError.new(<<ERR)
+Error generating source map: couldn't determine public URL for "#{filename}".
+  Without a public URL, there's nothing for the source map to link to.
+  An importer was not set for this file.
+ERR
+      elsif Sass::Util.silence_warnings do
+              sourcemap_dir = nil if @options[:sourcemap] == :file
+              importer.public_url(filename, sourcemap_dir).nil?
+            end
+        raise Sass::SyntaxError.new(<<ERR)
+Error generating source map: couldn't determine public URL for "#{filename}".
+  Without a public URL, there's nothing for the source map to link to.
+  Custom importers should define the #public_url method.
+ERR
+      end
+
+      rendered, sourcemap = _to_tree.render_with_sourcemap
+      compressed = @options[:style] == :compressed
+      rendered << "\n" if rendered[-1] != ?\n
+      rendered << "\n" unless compressed
+      rendered << "/*# sourceMappingURL="
+      rendered << Sass::Util.escape_uri(sourcemap_uri)
+      rendered << " */\n"
+      return rendered, sourcemap
+    end
+
+    def _to_tree
+      check_encoding!
+
+      if (@options[:cache] || @options[:read_cache]) &&
+          @options[:filename] && @options[:importer]
+        key = sassc_key
+        sha = Digest::SHA1.hexdigest(@template)
+
+        if (root = @options[:cache_store].retrieve(key, sha))
+          root.options = @options
+          return root
+        end
+      end
+
+      if @options[:syntax] == :scss
+        root = Sass::SCSS::Parser.new(@template, @options[:filename], @options[:importer]).parse
+      else
+        root = Tree::RootNode.new(@template)
+        append_children(root, tree(tabulate(@template)).first, true)
+      end
+
+      root.options = @options
+      if @options[:cache] && key && sha
+        begin
+          old_options = root.options
+          root.options = {}
+          @options[:cache_store].store(key, sha, root)
+        ensure
+          root.options = old_options
+        end
+      end
+      root
+    rescue SyntaxError => e
+      e.modify_backtrace(:filename => @options[:filename], :line => @line)
+      e.sass_template = @template
+      raise e
+    end
+
+    def sassc_key
+      @options[:cache_store].key(* options[:importer].key(@options[:filename], @options))
+    end
+
+    def check_encoding!
+      return if @checked_encoding
+      @checked_encoding = true
+      @template, @source_encoding = Sass::Util.check_sass_encoding(@template)
+    end
+
+    def tabulate(string)
+      tab_str = nil
+      comment_tab_str = nil
+      first = true
+      lines = []
+      string.scan(/^[^\n]*?$/).each_with_index do |line, index|
+        index += (@options[:line] || 1)
+        if line.strip.empty?
+          lines.last.text << "\n" if lines.last && lines.last.comment?
+          next
+        end
+
+        line_tab_str = line[/^\s*/]
+        unless line_tab_str.empty?
+          if tab_str.nil?
+            comment_tab_str ||= line_tab_str
+            next if try_comment(line, lines.last, "", comment_tab_str, index)
+            comment_tab_str = nil
+          end
+
+          tab_str ||= line_tab_str
+
+          raise SyntaxError.new("Indenting at the beginning of the document is illegal.",
+            :line => index) if first
+
+          raise SyntaxError.new("Indentation can't use both tabs and spaces.",
+            :line => index) if tab_str.include?(?\s) && tab_str.include?(?\t)
+        end
+        first &&= !tab_str.nil?
+        if tab_str.nil?
+          lines << Line.new(line.strip, 0, index, 0, @options[:filename], [])
+          next
+        end
+
+        comment_tab_str ||= line_tab_str
+        if try_comment(line, lines.last, tab_str * lines.last.tabs, comment_tab_str, index)
+          next
+        else
+          comment_tab_str = nil
+        end
+
+        line_tabs = line_tab_str.scan(tab_str).size
+        if tab_str * line_tabs != line_tab_str
+          message = <<END.strip.gsub("\n", ' ')
+Inconsistent indentation: #{Sass::Shared.human_indentation line_tab_str, true} used for indentation,
+but the rest of the document was indented using #{Sass::Shared.human_indentation tab_str}.
+END
+          raise SyntaxError.new(message, :line => index)
+        end
+
+        lines << Line.new(line.strip, line_tabs, index, line_tab_str.size, @options[:filename], [])
+      end
+      lines
+    end
+
+    # @comment
+    #   rubocop:disable ParameterLists
+    def try_comment(line, last, tab_str, comment_tab_str, index)
+      # rubocop:enable ParameterLists
+      return unless last && last.comment?
+      # Nested comment stuff must be at least one whitespace char deeper
+      # than the normal indentation
+      return unless line =~ /^#{tab_str}\s/
+      unless line =~ /^(?:#{comment_tab_str})(.*)$/
+        raise SyntaxError.new(<<MSG.strip.gsub("\n", " "), :line => index)
+Inconsistent indentation:
+previous line was indented by #{Sass::Shared.human_indentation comment_tab_str},
+but this line was indented by #{Sass::Shared.human_indentation line[/^\s*/]}.
+MSG
+      end
+
+      last.comment_tab_str ||= comment_tab_str
+      last.text << "\n" << line
+      true
+    end
+
+    def tree(arr, i = 0)
+      return [], i if arr[i].nil?
+
+      base = arr[i].tabs
+      nodes = []
+      while (line = arr[i]) && line.tabs >= base
+        if line.tabs > base
+          raise SyntaxError.new(
+            "The line was indented #{line.tabs - base} levels deeper than the previous line.",
+            :line => line.index) if line.tabs > base + 1
+
+          nodes.last.children, i = tree(arr, i)
+        else
+          nodes << line
+          i += 1
+        end
+      end
+      return nodes, i
+    end
+
+    def build_tree(parent, line, root = false)
+      @line = line.index
+      @offset = line.offset
+      node_or_nodes = parse_line(parent, line, root)
+
+      Array(node_or_nodes).each do |node|
+        # Node is a symbol if it's non-outputting, like a variable assignment
+        next unless node.is_a? Tree::Node
+
+        node.line = line.index
+        node.filename = line.filename
+
+        append_children(node, line.children, false)
+      end
+
+      node_or_nodes
+    end
+
+    def append_children(parent, children, root)
+      continued_rule = nil
+      continued_comment = nil
+      children.each do |line|
+        child = build_tree(parent, line, root)
+
+        if child.is_a?(Tree::RuleNode)
+          if child.continued? && child.children.empty?
+            if continued_rule
+              continued_rule.add_rules child
+            else
+              continued_rule = child
+            end
+            next
+          elsif continued_rule
+            continued_rule.add_rules child
+            continued_rule.children = child.children
+            continued_rule, child = nil, continued_rule
+          end
+        elsif continued_rule
+          continued_rule = nil
+        end
+
+        if child.is_a?(Tree::CommentNode) && child.type == :silent
+          if continued_comment &&
+              child.line == continued_comment.line +
+              continued_comment.lines + 1
+            continued_comment.value.last.sub!(/ \*\/\Z/, '')
+            child.value.first.gsub!(/\A\/\*/, ' *')
+            continued_comment.value += ["\n"] + child.value
+            next
+          end
+
+          continued_comment = child
+        end
+
+        check_for_no_children(child)
+        validate_and_append_child(parent, child, line, root)
+      end
+
+      parent
+    end
+
+    def validate_and_append_child(parent, child, line, root)
+      case child
+      when Array
+        child.each {|c| validate_and_append_child(parent, c, line, root)}
+      when Tree::Node
+        parent << child
+      end
+    end
+
+    def check_for_no_children(node)
+      return unless node.is_a?(Tree::RuleNode) && node.children.empty?
+      Sass::Util.sass_warn(<<WARNING.strip)
+WARNING on line #{node.line}#{" of #{node.filename}" if node.filename}:
+This selector doesn't have any properties and will not be rendered.
+WARNING
+    end
+
+    def parse_line(parent, line, root)
+      case line.text[0]
+      when PROPERTY_CHAR
+        if line.text[1] == PROPERTY_CHAR ||
+            (@options[:property_syntax] == :new &&
+             line.text =~ PROPERTY_OLD && $2.empty?)
+          # Support CSS3-style pseudo-elements,
+          # which begin with ::,
+          # as well as pseudo-classes
+          # if we're using the new property syntax
+          Tree::RuleNode.new(parse_interp(line.text), full_line_range(line))
+        else
+          name_start_offset = line.offset + 1 # +1 for the leading ':'
+          name, value = line.text.scan(PROPERTY_OLD)[0]
+          raise SyntaxError.new("Invalid property: \"#{line.text}\".",
+            :line => @line) if name.nil? || value.nil?
+
+          value_start_offset = name_end_offset = name_start_offset + name.length
+          unless value.empty?
+            # +1 and -1 both compensate for the leading ':', which is part of line.text
+            value_start_offset = name_start_offset + line.text.index(value, name.length + 1) - 1
+          end
+
+          property = parse_property(name, parse_interp(name), value, :old, line, value_start_offset)
+          property.name_source_range = Sass::Source::Range.new(
+            Sass::Source::Position.new(@line, to_parser_offset(name_start_offset)),
+            Sass::Source::Position.new(@line, to_parser_offset(name_end_offset)),
+            @options[:filename], @options[:importer])
+          property
+        end
+      when ?$
+        parse_variable(line)
+      when COMMENT_CHAR
+        parse_comment(line)
+      when DIRECTIVE_CHAR
+        parse_directive(parent, line, root)
+      when ESCAPE_CHAR
+        Tree::RuleNode.new(parse_interp(line.text[1..-1]), full_line_range(line))
+      when MIXIN_DEFINITION_CHAR
+        parse_mixin_definition(line)
+      when MIXIN_INCLUDE_CHAR
+        if line.text[1].nil? || line.text[1] == ?\s
+          Tree::RuleNode.new(parse_interp(line.text), full_line_range(line))
+        else
+          parse_mixin_include(line, root)
+        end
+      else
+        parse_property_or_rule(line)
+      end
+    end
+
+    def parse_property_or_rule(line)
+      scanner = Sass::Util::MultibyteStringScanner.new(line.text)
+      hack_char = scanner.scan(/[:\*\.]|\#(?!\{)/)
+      offset = line.offset
+      offset += hack_char.length if hack_char
+      parser = Sass::SCSS::Parser.new(scanner,
+        @options[:filename], @options[:importer],
+        @line, to_parser_offset(offset))
+
+      unless (res = parser.parse_interp_ident)
+        parsed = parse_interp(line.text, line.offset)
+        return Tree::RuleNode.new(parsed, full_line_range(line))
+      end
+
+      ident_range = Sass::Source::Range.new(
+        Sass::Source::Position.new(@line, to_parser_offset(line.offset)),
+        Sass::Source::Position.new(@line, parser.offset),
+        @options[:filename], @options[:importer])
+      offset = parser.offset - 1
+      res.unshift(hack_char) if hack_char
+
+      # Handle comments after a property name but before the colon.
+      if (comment = scanner.scan(Sass::SCSS::RX::COMMENT))
+        res << comment
+        offset += comment.length
+      end
+
+      name = line.text[0...scanner.pos]
+      if (scanned = scanner.scan(/\s*:(?:\s+|$)/)) # test for a property
+        offset += scanned.length
+        property = parse_property(name, res, scanner.rest, :new, line, offset)
+        property.name_source_range = ident_range
+        property
+      else
+        res.pop if comment
+
+        if (trailing = (scanner.scan(/\s*#{Sass::SCSS::RX::COMMENT}/) ||
+                        scanner.scan(/\s*#{Sass::SCSS::RX::SINGLE_LINE_COMMENT}/)))
+          trailing.strip!
+        end
+        interp_parsed = parse_interp(scanner.rest)
+        selector_range = Sass::Source::Range.new(
+          ident_range.start_pos,
+          Sass::Source::Position.new(@line, to_parser_offset(line.offset) + line.text.length),
+          @options[:filename], @options[:importer])
+        rule = Tree::RuleNode.new(res + interp_parsed, selector_range)
+        rule << Tree::CommentNode.new([trailing], :silent) if trailing
+        rule
+      end
+    end
+
+    # @comment
+    #   rubocop:disable ParameterLists
+    def parse_property(name, parsed_name, value, prop, line, start_offset)
+      # rubocop:enable ParameterLists
+      if value.strip.empty?
+        expr = Sass::Script::Tree::Literal.new(Sass::Script::Value::String.new(""))
+        end_offset = start_offset
+      else
+        expr = parse_script(value, :offset => to_parser_offset(start_offset))
+        end_offset = expr.source_range.end_pos.offset - 1
+      end
+      node = Tree::PropNode.new(parse_interp(name), expr, prop)
+      node.value_source_range = Sass::Source::Range.new(
+        Sass::Source::Position.new(line.index, to_parser_offset(start_offset)),
+        Sass::Source::Position.new(line.index, to_parser_offset(end_offset)),
+        @options[:filename], @options[:importer])
+      if value.strip.empty? && line.children.empty?
+        raise SyntaxError.new(
+          "Invalid property: \"#{node.declaration}\" (no value)." +
+          node.pseudo_class_selector_message)
+      end
+
+      node
+    end
+
+    def parse_variable(line)
+      name, value, flags = line.text.scan(Script::MATCH)[0]
+      raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath variable declarations.",
+        :line => @line + 1) unless line.children.empty?
+      raise SyntaxError.new("Invalid variable: \"#{line.text}\".",
+        :line => @line) unless name && value
+      flags = flags ? flags.split(/\s+/) : []
+      if (invalid_flag = flags.find {|f| f != '!default' && f != '!global'})
+        raise SyntaxError.new("Invalid flag \"#{invalid_flag}\".", :line => @line)
+      end
+
+      # This workaround is needed for the case when the variable value is part of the identifier,
+      # otherwise we end up with the offset equal to the value index inside the name:
+      # $red_color: red;
+      var_lhs_length = 1 + name.length # 1 stands for '$'
+      index = line.text.index(value, line.offset + var_lhs_length) || 0
+      expr = parse_script(value, :offset => to_parser_offset(line.offset + index))
+
+      Tree::VariableNode.new(name, expr, flags.include?('!default'), flags.include?('!global'))
+    end
+
+    def parse_comment(line)
+      if line.text[1] == CSS_COMMENT_CHAR || line.text[1] == SASS_COMMENT_CHAR
+        silent = line.text[1] == SASS_COMMENT_CHAR
+        loud = !silent && line.text[2] == SASS_LOUD_COMMENT_CHAR
+        if silent
+          value = [line.text]
+        else
+          value = self.class.parse_interp(
+            line.text, line.index, to_parser_offset(line.offset), :filename => @filename)
+        end
+        value = Sass::Util.with_extracted_values(value) do |str|
+          str = str.gsub(/^#{line.comment_tab_str}/m, '')[2..-1] # get rid of // or /*
+          format_comment_text(str, silent)
+        end
+        type = if silent
+                 :silent
+               elsif loud
+                 :loud
+               else
+                 :normal
+               end
+        Tree::CommentNode.new(value, type)
+      else
+        Tree::RuleNode.new(parse_interp(line.text), full_line_range(line))
+      end
+    end
+
+    DIRECTIVES = Set[:mixin, :include, :function, :return, :debug, :warn, :for,
+      :each, :while, :if, :else, :extend, :import, :media, :charset, :content,
+      :at_root, :error]
+
+    # @comment
+    #   rubocop:disable MethodLength
+    def parse_directive(parent, line, root)
+      directive, whitespace, value = line.text[1..-1].split(/(\s+)/, 2)
+      raise SyntaxError.new("Invalid directive: '@'.") unless directive
+      offset = directive.size + whitespace.size + 1 if whitespace
+
+      directive_name = directive.gsub('-', '_').to_sym
+      if DIRECTIVES.include?(directive_name)
+        return send("parse_#{directive_name}_directive", parent, line, root, value, offset)
+      end
+
+      unprefixed_directive = directive.gsub(/^-[a-z0-9]+-/i, '')
+      if unprefixed_directive == 'supports'
+        parser = Sass::SCSS::Parser.new(value, @options[:filename], @line)
+        return Tree::SupportsNode.new(directive, parser.parse_supports_condition)
+      end
+
+      Tree::DirectiveNode.new(
+        value.nil? ? ["@#{directive}"] : ["@#{directive} "] + parse_interp(value, offset))
+    end
+
+    def parse_while_directive(parent, line, root, value, offset)
+      raise SyntaxError.new("Invalid while directive '@while': expected expression.") unless value
+      Tree::WhileNode.new(parse_script(value, :offset => offset))
+    end
+
+    def parse_if_directive(parent, line, root, value, offset)
+      raise SyntaxError.new("Invalid if directive '@if': expected expression.") unless value
+      Tree::IfNode.new(parse_script(value, :offset => offset))
+    end
+
+    def parse_debug_directive(parent, line, root, value, offset)
+      raise SyntaxError.new("Invalid debug directive '@debug': expected expression.") unless value
+      raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath debug directives.",
+        :line => @line + 1) unless line.children.empty?
+      offset = line.offset + line.text.index(value).to_i
+      Tree::DebugNode.new(parse_script(value, :offset => offset))
+    end
+
+    def parse_error_directive(parent, line, root, value, offset)
+      raise SyntaxError.new("Invalid error directive '@error': expected expression.") unless value
+      raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath error directives.",
+        :line => @line + 1) unless line.children.empty?
+      offset = line.offset + line.text.index(value).to_i
+      Tree::ErrorNode.new(parse_script(value, :offset => offset))
+    end
+
+    def parse_extend_directive(parent, line, root, value, offset)
+      raise SyntaxError.new("Invalid extend directive '@extend': expected expression.") unless value
+      raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath extend directives.",
+        :line => @line + 1) unless line.children.empty?
+      optional = !!value.gsub!(/\s+#{Sass::SCSS::RX::OPTIONAL}$/, '')
+      offset = line.offset + line.text.index(value).to_i
+      interp_parsed = parse_interp(value, offset)
+      selector_range = Sass::Source::Range.new(
+        Sass::Source::Position.new(@line, to_parser_offset(offset)),
+        Sass::Source::Position.new(@line, to_parser_offset(line.offset) + line.text.length),
+        @options[:filename], @options[:importer]
+      )
+      Tree::ExtendNode.new(interp_parsed, optional, selector_range)
+    end
+    # @comment
+    #   rubocop:enable MethodLength
+
+    def parse_warn_directive(parent, line, root, value, offset)
+      raise SyntaxError.new("Invalid warn directive '@warn': expected expression.") unless value
+      raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath warn directives.",
+        :line => @line + 1) unless line.children.empty?
+      offset = line.offset + line.text.index(value).to_i
+      Tree::WarnNode.new(parse_script(value, :offset => offset))
+    end
+
+    def parse_return_directive(parent, line, root, value, offset)
+      raise SyntaxError.new("Invalid @return: expected expression.") unless value
+      raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath return directives.",
+        :line => @line + 1) unless line.children.empty?
+      offset = line.offset + line.text.index(value).to_i
+      Tree::ReturnNode.new(parse_script(value, :offset => offset))
+    end
+
+    def parse_charset_directive(parent, line, root, value, offset)
+      name = value && value[/\A(["'])(.*)\1\Z/, 2] # "
+      raise SyntaxError.new("Invalid charset directive '@charset': expected string.") unless name
+      raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath charset directives.",
+        :line => @line + 1) unless line.children.empty?
+      Tree::CharsetNode.new(name)
+    end
+
+    def parse_media_directive(parent, line, root, value, offset)
+      parser = Sass::SCSS::Parser.new(value,
+        @options[:filename], @options[:importer],
+        @line, to_parser_offset(@offset))
+      offset = line.offset + line.text.index('media').to_i - 1
+      parsed_media_query_list = parser.parse_media_query_list.to_a
+      node = Tree::MediaNode.new(parsed_media_query_list)
+      node.source_range = Sass::Source::Range.new(
+        Sass::Source::Position.new(@line, to_parser_offset(offset)),
+        Sass::Source::Position.new(@line, to_parser_offset(line.offset) + line.text.length),
+        @options[:filename], @options[:importer])
+      node
+    end
+
+    def parse_at_root_directive(parent, line, root, value, offset)
+      return Sass::Tree::AtRootNode.new unless value
+
+      if value.start_with?('(')
+        parser = Sass::SCSS::Parser.new(value,
+          @options[:filename], @options[:importer],
+          @line, to_parser_offset(@offset))
+        offset = line.offset + line.text.index('at-root').to_i - 1
+        return Tree::AtRootNode.new(parser.parse_at_root_query)
+      end
+
+      at_root_node = Tree::AtRootNode.new
+      parsed = parse_interp(value, offset)
+      rule_node = Tree::RuleNode.new(parsed, full_line_range(line))
+
+      # The caller expects to automatically add children to the returned node
+      # and we want it to add children to the rule node instead, so we
+      # manually handle the wiring here and return nil so the caller doesn't
+      # duplicate our efforts.
+      append_children(rule_node, line.children, false)
+      at_root_node << rule_node
+      parent << at_root_node
+      nil
+    end
+
+    def parse_for_directive(parent, line, root, value, offset)
+      var, from_expr, to_name, to_expr =
+        value.scan(/^([^\s]+)\s+from\s+(.+)\s+(to|through)\s+(.+)$/).first
+
+      if var.nil? # scan failed, try to figure out why for error message
+        if value !~ /^[^\s]+/
+          expected = "variable name"
+        elsif value !~ /^[^\s]+\s+from\s+.+/
+          expected = "'from <expr>'"
+        else
+          expected = "'to <expr>' or 'through <expr>'"
+        end
+        raise SyntaxError.new("Invalid for directive '@for #{value}': expected #{expected}.")
+      end
+      raise SyntaxError.new("Invalid variable \"#{var}\".") unless var =~ Script::VALIDATE
+
+      var = var[1..-1]
+      parsed_from = parse_script(from_expr, :offset => line.offset + line.text.index(from_expr))
+      parsed_to = parse_script(to_expr, :offset => line.offset + line.text.index(to_expr))
+      Tree::ForNode.new(var, parsed_from, parsed_to, to_name == 'to')
+    end
+
+    def parse_each_directive(parent, line, root, value, offset)
+      vars, list_expr = value.scan(/^([^\s]+(?:\s*,\s*[^\s]+)*)\s+in\s+(.+)$/).first
+
+      if vars.nil? # scan failed, try to figure out why for error message
+        if value !~ /^[^\s]+/
+          expected = "variable name"
+        elsif value !~ /^[^\s]+(?:\s*,\s*[^\s]+)*[^\s]+\s+from\s+.+/
+          expected = "'in <expr>'"
+        end
+        raise SyntaxError.new("Invalid each directive '@each #{value}': expected #{expected}.")
+      end
+
+      vars = vars.split(',').map do |var|
+        var.strip!
+        raise SyntaxError.new("Invalid variable \"#{var}\".") unless var =~ Script::VALIDATE
+        var[1..-1]
+      end
+
+      parsed_list = parse_script(list_expr, :offset => line.offset + line.text.index(list_expr))
+      Tree::EachNode.new(vars, parsed_list)
+    end
+
+    def parse_else_directive(parent, line, root, value, offset)
+      previous = parent.children.last
+      raise SyntaxError.new("@else must come after @if.") unless previous.is_a?(Tree::IfNode)
+
+      if value
+        if value !~ /^if\s+(.+)/
+          raise SyntaxError.new("Invalid else directive '@else #{value}': expected 'if <expr>'.")
+        end
+        expr = parse_script($1, :offset => line.offset + line.text.index($1))
+      end
+
+      node = Tree::IfNode.new(expr)
+      append_children(node, line.children, false)
+      previous.add_else node
+      nil
+    end
+
+    def parse_import_directive(parent, line, root, value, offset)
+      raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath import directives.",
+        :line => @line + 1) unless line.children.empty?
+
+      scanner = Sass::Util::MultibyteStringScanner.new(value)
+      values = []
+
+      loop do
+        unless (node = parse_import_arg(scanner, offset + scanner.pos))
+          raise SyntaxError.new(
+            "Invalid @import: expected file to import, was #{scanner.rest.inspect}",
+            :line => @line)
+        end
+        values << node
+        break unless scanner.scan(/,\s*/)
+      end
+
+      if scanner.scan(/;/)
+        raise SyntaxError.new("Invalid @import: expected end of line, was \";\".",
+          :line => @line)
+      end
+
+      values
+    end
+
+    # @comment
+    #   rubocop:disable MethodLength
+    def parse_import_arg(scanner, offset)
+      return if scanner.eos?
+
+      if scanner.match?(/url\(/i)
+        script_parser = Sass::Script::Parser.new(scanner, @line, to_parser_offset(offset), @options)
+        str = script_parser.parse_string
+
+        if scanner.eos?
+          end_pos = str.source_range.end_pos
+          node = Tree::CssImportNode.new(str)
+        else
+          media_parser = Sass::SCSS::Parser.new(scanner,
+            @options[:filename], @options[:importer],
+            @line, str.source_range.end_pos.offset)
+          media = media_parser.parse_media_query_list
+          end_pos = Sass::Source::Position.new(@line, media_parser.offset + 1)
+          node = Tree::CssImportNode.new(str, media.to_a)
+        end
+
+        node.source_range = Sass::Source::Range.new(
+          str.source_range.start_pos, end_pos,
+          @options[:filename], @options[:importer])
+        return node
+      end
+
+      unless (quoted_val = scanner.scan(Sass::SCSS::RX::STRING))
+        scanned = scanner.scan(/[^,;]+/)
+        node = Tree::ImportNode.new(scanned)
+        start_parser_offset = to_parser_offset(offset)
+        node.source_range = Sass::Source::Range.new(
+          Sass::Source::Position.new(@line, start_parser_offset),
+          Sass::Source::Position.new(@line, start_parser_offset + scanned.length),
+          @options[:filename], @options[:importer])
+        return node
+      end
+
+      start_offset = offset
+      offset += scanner.matched.length
+      val = Sass::Script::Value::String.value(scanner[1] || scanner[2])
+      scanned = scanner.scan(/\s*/)
+      if !scanner.match?(/[,;]|$/)
+        offset += scanned.length if scanned
+        media_parser = Sass::SCSS::Parser.new(scanner,
+          @options[:filename], @options[:importer], @line, offset)
+        media = media_parser.parse_media_query_list
+        node = Tree::CssImportNode.new(quoted_val, media.to_a)
+        node.source_range = Sass::Source::Range.new(
+          Sass::Source::Position.new(@line, to_parser_offset(start_offset)),
+          Sass::Source::Position.new(@line, media_parser.offset),
+          @options[:filename], @options[:importer])
+      elsif val =~ %r{^(https?:)?//}
+        node = Tree::CssImportNode.new(quoted_val)
+        node.source_range = Sass::Source::Range.new(
+          Sass::Source::Position.new(@line, to_parser_offset(start_offset)),
+          Sass::Source::Position.new(@line, to_parser_offset(offset)),
+          @options[:filename], @options[:importer])
+      else
+        node = Tree::ImportNode.new(val)
+        node.source_range = Sass::Source::Range.new(
+          Sass::Source::Position.new(@line, to_parser_offset(start_offset)),
+          Sass::Source::Position.new(@line, to_parser_offset(offset)),
+          @options[:filename], @options[:importer])
+      end
+      node
+    end
+    # @comment
+    #   rubocop:enable MethodLength
+
+    def parse_mixin_directive(parent, line, root, value, offset)
+      parse_mixin_definition(line)
+    end
+
+    MIXIN_DEF_RE = /^(?:=|@mixin)\s*(#{Sass::SCSS::RX::IDENT})(.*)$/
+    def parse_mixin_definition(line)
+      name, arg_string = line.text.scan(MIXIN_DEF_RE).first
+      raise SyntaxError.new("Invalid mixin \"#{line.text[1..-1]}\".") if name.nil?
+
+      offset = line.offset + line.text.size - arg_string.size
+      args, splat = Script::Parser.new(arg_string.strip, @line, to_parser_offset(offset), @options).
+        parse_mixin_definition_arglist
+      Tree::MixinDefNode.new(name, args, splat)
+    end
+
+    CONTENT_RE = /^ content\s*(.+)?$/
+    def parse_content_directive(parent, line, root, value, offset)
+      trailing = line.text.scan(CONTENT_RE).first.first
+      unless trailing.nil?
+        raise SyntaxError.new(
+          "Invalid content directive. Trailing characters found: \"#{trailing}\".")
+      end
+      raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath @content directives.",
+        :line => line.index + 1) unless line.children.empty?
+      Tree::ContentNode.new
+    end
+
+    def parse_include_directive(parent, line, root, value, offset)
+      parse_mixin_include(line, root)
+    end
+
+    MIXIN_INCLUDE_RE = /^(?:\+|@include)\s*(#{Sass::SCSS::RX::IDENT})(.*)$/
+    def parse_mixin_include(line, root)
+      name, arg_string = line.text.scan(MIXIN_INCLUDE_RE).first
+      raise SyntaxError.new("Invalid mixin include \"#{line.text}\".") if name.nil?
+
+      offset = line.offset + line.text.size - arg_string.size
+      args, keywords, splat, kwarg_splat =
+        Script::Parser.new(arg_string.strip, @line, to_parser_offset(offset), @options).
+          parse_mixin_include_arglist
+      Tree::MixinNode.new(name, args, keywords, splat, kwarg_splat)
+    end
+
+    FUNCTION_RE = /^ function\s*(#{Sass::SCSS::RX::IDENT})(.*)$/
+    def parse_function_directive(parent, line, root, value, offset)
+      name, arg_string = line.text.scan(FUNCTION_RE).first
+      raise SyntaxError.new("Invalid function definition \"#{line.text}\".") if name.nil?
+
+      offset = line.offset + line.text.size - arg_string.size
+      args, splat = Script::Parser.new(arg_string.strip, @line, to_parser_offset(offset), @options).
+        parse_function_definition_arglist
+      Tree::FunctionNode.new(name, args, splat)
+    end
+
+    def parse_script(script, options = {})
+      line = options[:line] || @line
+      offset = options[:offset] || @offset + 1
+      Script.parse(script, line, offset, @options)
+    end
+
+    def format_comment_text(text, silent)
+      content = text.split("\n")
+
+      if content.first && content.first.strip.empty?
+        removed_first = true
+        content.shift
+      end
+
+      return "/* */" if content.empty?
+      content.last.gsub!(/ ?\*\/ *$/, '')
+      first = content.shift unless removed_first
+      content.map! {|l| l.gsub!(/^\*( ?)/, '\1') || (l.empty? ? "" : " ") + l}
+      content.unshift first unless removed_first
+      if silent
+        "/*" + content.join("\n *") + " */"
+      else
+        # The #gsub fixes the case of a trailing */
+        "/*" + content.join("\n *").gsub(/ \*\Z/, '') + " */"
+      end
+    end
+
+    def parse_interp(text, offset = 0)
+      self.class.parse_interp(text, @line, offset, :filename => @filename)
+    end
+
+    # Parser tracks 1-based line and offset, so our offset should be converted.
+    def to_parser_offset(offset)
+      offset + 1
+    end
+
+    def full_line_range(line)
+      Sass::Source::Range.new(
+        Sass::Source::Position.new(@line, to_parser_offset(line.offset)),
+        Sass::Source::Position.new(@line, to_parser_offset(line.offset) + line.text.length),
+        @options[:filename], @options[:importer])
+    end
+
+    # It's important that this have strings (at least)
+    # at the beginning, the end, and between each Script::Tree::Node.
+    #
+    # @private
+    def self.parse_interp(text, line, offset, options)
+      res = []
+      rest = Sass::Shared.handle_interpolation text do |scan|
+        escapes = scan[2].size
+        res << scan.matched[0...-2 - escapes]
+        if escapes.odd?
+          res << "\\" * (escapes - 1) << '#{'
+        else
+          res << "\\" * [0, escapes - 1].max
+          # Add 1 to emulate to_parser_offset.
+          res << Script::Parser.new(
+            scan, line, offset + scan.pos - scan.matched_size + 1, options).
+            parse_interpolated
+        end
+      end
+      res << rest
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/environment.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/environment.rb
new file mode 100644
index 0000000..f4c1231
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/environment.rb
@@ -0,0 +1,208 @@
+require 'set'
+
+module Sass
+  # The abstract base class for lexical environments for SassScript.
+  class BaseEnvironment
+    class << self
+      # Note: when updating this,
+      # update sass/yard/inherited_hash.rb as well.
+      def inherited_hash_accessor(name)
+        inherited_hash_reader(name)
+        inherited_hash_writer(name)
+      end
+
+      def inherited_hash_reader(name)
+        class_eval <<-RUBY, __FILE__, __LINE__ + 1
+          def #{name}(name)
+            _#{name}(name.tr('_', '-'))
+          end
+
+          def _#{name}(name)
+            (@#{name}s && @#{name}s[name]) || @parent && @parent._#{name}(name)
+          end
+          protected :_#{name}
+
+          def is_#{name}_global?(name)
+            return ! parent if @#{name}s && @#{name}s.has_key?(name)
+            @parent && @parent.is_#{name}_global?(name)
+          end
+        RUBY
+      end
+
+      def inherited_hash_writer(name)
+        class_eval <<-RUBY, __FILE__, __LINE__ + 1
+          def set_#{name}(name, value)
+            name = name.tr('_', '-')
+            @#{name}s[name] = value unless try_set_#{name}(name, value)
+          end
+
+          def try_set_#{name}(name, value)
+            @#{name}s ||= {}
+            if @#{name}s.include?(name)
+              @#{name}s[name] = value
+              true
+            elsif @parent && ! parent global?
+              @parent.try_set_#{name}(name, value)
+            else
+              false
+            end
+          end
+          protected :try_set_#{name}
+
+          def set_local_#{name}(name, value)
+            @#{name}s ||= {}
+            @#{name}s[name.tr('_', '-')] = value
+          end
+
+          def set_global_#{name}(name, value)
+            global_env.set_#{name}(name, value)
+          end
+        RUBY
+      end
+    end
+
+    # The options passed to the Sass Engine.
+    attr_reader :options
+
+    attr_writer :caller
+    attr_writer :content
+    attr_writer :selector
+
+    # variable
+    # Script::Value
+    inherited_hash_reader :var
+
+    # mixin
+    # Sass::Callable
+    inherited_hash_reader :mixin
+
+    # function
+    # Sass::Callable
+    inherited_hash_reader :function
+
+    # @param options [{Symbol => Object}] The options hash. See
+    #   {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
+    # @param parent [Environment] See \{#parent}
+    def initialize(parent = nil, options = nil)
+      @parent = parent
+      @options = options || (parent && parent.options) || {}
+      @stack = Sass::Stack.new if @parent.nil?
+    end
+
+    # Returns whether this is the global environment.
+    #
+    # @return [Boolean]
+    def global?
+      @parent.nil?
+    end
+
+    # The environment of the caller of this environment's mixin or function.
+    # @return {Environment?}
+    def caller
+      @caller || (@parent && @parent.caller)
+    end
+
+    # The content passed to this environment. This is naturally only set
+    # for mixin body environments with content passed in.
+    #
+    # @return {[Array<Sass::Tree::Node>, Environment]?} The content nodes and
+    #   the lexical environment of the content block.
+    def content
+      @content || (@parent && @parent.content)
+    end
+
+    # The selector for the current CSS rule, or nil if there is no
+    # current CSS rule.
+    #
+    # @return [Selector::CommaSequence?] The current selector, with any
+    #   nesting fully resolved.
+    def selector
+      @selector || (@caller && @caller.selector) || (@parent && @parent.selector)
+    end
+
+    # The top-level Environment object.
+    #
+    # @return [Environment]
+    def global_env
+      @global_env ||= global? ? self : @parent.global_env
+    end
+
+    # The import/mixin stack.
+    #
+    # @return [Sass::Stack]
+    def stack
+      @stack || global_env.stack
+    end
+  end
+
+  # The lexical environment for SassScript.
+  # This keeps track of variable, mixin, and function definitions.
+  #
+  # A new environment is created for each level of Sass nesting.
+  # This allows variables to be lexically scoped.
+  # The new environment refers to the environment in the upper scope,
+  # so it has access to variables defined in enclosing scopes,
+  # but new variables are defined locally.
+  #
+  # Environment also keeps track of the {Engine} options
+  # so that they can be made available to {Sass::Script::Functions}.
+  class Environment < BaseEnvironment
+    # The enclosing environment,
+    # or nil if this is the global environment.
+    #
+    # @return [Environment]
+    attr_reader :parent
+
+    # variable
+    # Script::Value
+    inherited_hash_writer :var
+
+    # mixin
+    # Sass::Callable
+    inherited_hash_writer :mixin
+
+    # function
+    # Sass::Callable
+    inherited_hash_writer :function
+  end
+
+  # A read-only wrapper for a lexical environment for SassScript.
+  class ReadOnlyEnvironment < BaseEnvironment
+    # The read-only environment of the caller of this environment's mixin or function.
+    #
+    # @see BaseEnvironment#caller
+    # @return {ReadOnlyEnvironment}
+    def caller
+      return @caller if @caller
+      env = super
+      @caller ||= env.is_a?(ReadOnlyEnvironment) ? env : ReadOnlyEnvironment.new(env, env.options)
+    end
+
+    # The read-only content passed to this environment.
+    #
+    # @see BaseEnvironment#content
+    # @return {ReadOnlyEnvironment}
+    def content
+      return @content if @content
+      env = super
+      @content ||= env.is_a?(ReadOnlyEnvironment) ? env : ReadOnlyEnvironment.new(env, env.options)
+    end
+  end
+
+  # An environment that can write to in-scope global variables, but doesn't
+  # create new variables in the global scope. Useful for top-level control
+  # directives.
+  class SemiGlobalEnvironment < Environment
+    def try_set_var(name, value)
+      @vars ||= {}
+      if @vars.include?(name)
+        @vars[name] = value
+        true
+      elsif @parent
+        @parent.try_set_var(name, value)
+      else
+        false
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/error.rb b/backends/css/gems/sass-3.4.9/lib/sass/error.rb
new file mode 100644
index 0000000..79b2f90
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/error.rb
@@ -0,0 +1,198 @@
+module Sass
+  # An exception class that keeps track of
+  # the line of the Sass template it was raised on
+  # and the Sass file that was being parsed (if applicable).
+  #
+  # All Sass errors are raised as {Sass::SyntaxError}s.
+  #
+  # When dealing with SyntaxErrors,
+  # it's important to provide filename and line number information.
+  # This will be used in various error reports to users, including backtraces;
+  # see \{#sass\_backtrace} for details.
+  #
+  # Some of this information is usually provided as part of the constructor.
+  # New backtrace entries can be added with \{#add\_backtrace},
+  # which is called when an exception is raised between files (e.g. with ` import`).
+  #
+  # Often, a chunk of code will all have similar backtrace information -
+  # the same filename or even line.
+  # It may also be useful to have a default line number set.
+  # In those situations, the default values can be used
+  # by omitting the information on the original exception,
+  # and then calling \{#modify\_backtrace} in a wrapper `rescue`.
+  # When doing this, be sure that all exceptions ultimately end up
+  # with the information filled in.
+  class SyntaxError < StandardError
+    # The backtrace of the error within Sass files.
+    # This is an array of hashes containing information for a single entry.
+    # The hashes have the following keys:
+    #
+    # `:filename`
+    # : The name of the file in which the exception was raised,
+    #   or `nil` if no filename is available.
+    #
+    # `:mixin`
+    # : The name of the mixin in which the exception was raised,
+    #   or `nil` if it wasn't raised in a mixin.
+    #
+    # `:line`
+    # : The line of the file on which the error occurred. Never nil.
+    #
+    # This information is also included in standard backtrace format
+    # in the output of \{#backtrace}.
+    #
+    # @return [Aray<{Symbol => Object>}]
+    attr_accessor :sass_backtrace
+
+    # The text of the template where this error was raised.
+    #
+    # @return [String]
+    attr_accessor :sass_template
+
+    # @param msg [String] The error message
+    # @param attrs [{Symbol => Object}] The information in the backtrace entry.
+    #   See \{#sass\_backtrace}
+    def initialize(msg, attrs = {})
+      @message = msg
+      @sass_backtrace = []
+      add_backtrace(attrs)
+    end
+
+    # The name of the file in which the exception was raised.
+    # This could be `nil` if no filename is available.
+    #
+    # @return [String, nil]
+    def sass_filename
+      sass_backtrace.first[:filename]
+    end
+
+    # The name of the mixin in which the error occurred.
+    # This could be `nil` if the error occurred outside a mixin.
+    #
+    # @return [Fixnum]
+    def sass_mixin
+      sass_backtrace.first[:mixin]
+    end
+
+    # The line of the Sass template on which the error occurred.
+    #
+    # @return [Fixnum]
+    def sass_line
+      sass_backtrace.first[:line]
+    end
+
+    # Adds an entry to the exception's Sass backtrace.
+    #
+    # @param attrs [{Symbol => Object}] The information in the backtrace entry.
+    #   See \{#sass\_backtrace}
+    def add_backtrace(attrs)
+      sass_backtrace << attrs.reject {|k, v| v.nil?}
+    end
+
+    # Modify the top Sass backtrace entries
+    # (that is, the most deeply nested ones)
+    # to have the given attributes.
+    #
+    # Specifically, this goes through the backtrace entries
+    # from most deeply nested to least,
+    # setting the given attributes for each entry.
+    # If an entry already has one of the given attributes set,
+    # the pre-existing attribute takes precedence
+    # and is not used for less deeply-nested entries
+    # (even if they don't have that attribute set).
+    #
+    # @param attrs [{Symbol => Object}] The information to add to the backtrace entry.
+    #   See \{#sass\_backtrace}
+    def modify_backtrace(attrs)
+      attrs = attrs.reject {|k, v| v.nil?}
+      # Move backwards through the backtrace
+      (0...sass_backtrace.size).to_a.reverse.each do |i|
+        entry = sass_backtrace[i]
+        sass_backtrace[i] = attrs.merge(entry)
+        attrs.reject! {|k, v| entry.include?(k)}
+        break if attrs.empty?
+      end
+    end
+
+    # @return [String] The error message
+    def to_s
+      @message
+    end
+
+    # Returns the standard exception backtrace,
+    # including the Sass backtrace.
+    #
+    # @return [Array<String>]
+    def backtrace
+      return nil if super.nil?
+      return super if sass_backtrace.all? {|h| h.empty?}
+      sass_backtrace.map do |h|
+        "#{h[:filename] || "(sass)"}:#{h[:line]}" +
+          (h[:mixin] ? ":in `#{h[:mixin]}'" : "")
+      end + super
+    end
+
+    # Returns a string representation of the Sass backtrace.
+    #
+    # @param default_filename [String] The filename to use for unknown files
+    # @see #sass_backtrace
+    # @return [String]
+    def sass_backtrace_str(default_filename = "an unknown file")
+      lines = message.split("\n")
+      msg = lines[0] + lines[1..-1].
+        map {|l| "\n" + (" " * "Error: ".size) + l}.join
+      "Error: #{msg}" +
+        Sass::Util.enum_with_index(sass_backtrace).map do |entry, i|
+          "\n        #{i == 0 ? "on" : "from"} line #{entry[:line]}" +
+            " of #{entry[:filename] || default_filename}" +
+            (entry[:mixin] ? ", in `#{entry[:mixin]}'" : "")
+        end.join
+    end
+
+    class << self
+      # Returns an error report for an exception in CSS format.
+      #
+      # @param e [Exception]
+      # @param line_offset [Fixnum] The number of the first line of the Sass template.
+      # @return [String] The error report
+      # @raise [Exception] `e`, if the
+      #   {file:SASS_REFERENCE.md#full_exception-option `:full_exception`} option
+      #   is set to false.
+      def exception_to_css(e, line_offset = 1)
+        header = header_string(e, line_offset)
+
+        <<END
+/*
+#{header.gsub("*/", "*\\/")}
+
+Backtrace:\n#{e.backtrace.join("\n").gsub("*/", "*\\/")}
+*/
+body:before {
+  white-space: pre;
+  font-family: monospace;
+  content: "#{header.gsub('"', '\"').gsub("\n", '\\A ')}"; }
+END
+      end
+
+      private
+
+      def header_string(e, line_offset)
+        unless e.is_a?(Sass::SyntaxError) && e.sass_line && e.sass_template
+          return "#{e.class}: #{e.message}"
+        end
+
+        line_num = e.sass_line + 1 - line_offset
+        min = [line_num - 6, 0].max
+        section = e.sass_template.rstrip.split("\n")[min ... line_num + 5]
+        return e.sass_backtrace_str if section.nil? || section.empty?
+
+        e.sass_backtrace_str + "\n\n" + Sass::Util.enum_with_index(section).
+          map {|line, i| "#{line_offset + min + i}: #{line}"}.join("\n")
+      end
+    end
+  end
+
+  # The class for Sass errors that are raised due to invalid unit conversions
+  # in SassScript.
+  class UnitConversionError < SyntaxError; end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/exec.rb b/backends/css/gems/sass-3.4.9/lib/sass/exec.rb
new file mode 100644
index 0000000..8add324
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/exec.rb
@@ -0,0 +1,9 @@
+module Sass
+  # This module handles the Sass executables (`sass` and `sass-convert`).
+  module Exec
+  end
+end
+
+require 'sass/exec/base'
+require 'sass/exec/sass_scss'
+require 'sass/exec/sass_convert'
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/exec/base.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/exec/base.rb
new file mode 100644
index 0000000..3b13e6a
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/exec/base.rb
@@ -0,0 +1,199 @@
+require 'optparse'
+
+module Sass::Exec
+  # The abstract base class for Sass executables.
+  class Base
+    # @param args [Array<String>] The command-line arguments
+    def initialize(args)
+      @args = args
+      @options = {}
+    end
+
+    # Parses the command-line arguments and runs the executable.
+    # Calls `Kernel#exit` at the end, so it never returns.
+    #
+    # @see #parse
+    def parse!
+      # rubocop:disable RescueException
+      begin
+        parse
+      rescue Exception => e
+        # Exit code 65 indicates invalid data per
+        # http://www.freebsd.org/cgi/man.cgi?query=sysexits. Setting it via
+        # at_exit is a bit of a hack, but it allows us to rethrow when --trace
+        # is active and get both the built-in exception formatting and the
+        # correct exit code.
+        at_exit {exit 65} if e.is_a?(Sass::SyntaxError)
+
+        raise e if @options[:trace] || e.is_a?(SystemExit)
+
+        if e.is_a?(Sass::SyntaxError)
+          $stderr.puts e.sass_backtrace_str("standard input")
+        else
+          $stderr.print "#{e.class}: " unless e.class == RuntimeError
+          $stderr.puts e.message.to_s
+        end
+        $stderr.puts "  Use --trace for backtrace."
+
+        exit 1
+      end
+      exit 0
+      # rubocop:enable RescueException
+    end
+
+    # Parses the command-line arguments and runs the executable.
+    # This does not handle exceptions or exit the program.
+    #
+    # @see #parse!
+    def parse
+      @opts = OptionParser.new(&method(:set_opts))
+      @opts.parse!(@args)
+
+      process_result
+
+      @options
+    end
+
+    # @return [String] A description of the executable
+    def to_s
+      @opts.to_s
+    end
+
+    protected
+
+    # Finds the line of the source template
+    # on which an exception was raised.
+    #
+    # @param exception [Exception] The exception
+    # @return [String] The line number
+    def get_line(exception)
+      # SyntaxErrors have weird line reporting
+      # when there's trailing whitespace
+      if exception.is_a?(::SyntaxError)
+        return (exception.message.scan(/:(\d+)/).first || ["??"]).first
+      end
+      (exception.backtrace[0].scan(/:(\d+)/).first || ["??"]).first
+    end
+
+    # Tells optparse how to parse the arguments
+    # available for all executables.
+    #
+    # This is meant to be overridden by subclasses
+    # so they can add their own options.
+    #
+    # @param opts [OptionParser]
+    def set_opts(opts)
+      Sass::Util.abstract(this)
+    end
+
+    # Set an option for specifying `Encoding.default_external`.
+    #
+    # @param opts [OptionParser]
+    def encoding_option(opts)
+      encoding_desc = if Sass::Util.ruby1_8?
+                        'Does not work in Ruby 1.8.'
+                      else
+                        'Specify the default encoding for input files.'
+                      end
+      opts.on('-E', '--default-encoding ENCODING', encoding_desc) do |encoding|
+        if Sass::Util.ruby1_8?
+          $stderr.puts "Specifying the encoding is not supported in ruby 1.8."
+          exit 1
+        else
+          Encoding.default_external = encoding
+        end
+      end
+    end
+
+    # Processes the options set by the command-line arguments. In particular,
+    # sets ` options[:input]` and ` options[:output]` to appropriate IO streams.
+    #
+    # This is meant to be overridden by subclasses
+    # so they can run their respective programs.
+    def process_result
+      input, output = @options[:input], @options[:output]
+      args = @args.dup
+      input ||=
+        begin
+          filename = args.shift
+          @options[:filename] = filename
+          open_file(filename) || $stdin
+        end
+      @options[:output_filename] = args.shift
+      output ||= @options[:output_filename] || $stdout
+      @options[:input], @options[:output] = input, output
+    end
+
+    COLORS = {:red => 31, :green => 32, :yellow => 33}
+
+    # Prints a status message about performing the given action,
+    # colored using the given color (via terminal escapes) if possible.
+    #
+    # @param name [#to_s] A short name for the action being performed.
+    #   Shouldn't be longer than 11 characters.
+    # @param color [Symbol] The name of the color to use for this action.
+    #   Can be `:red`, `:green`, or `:yellow`.
+    def puts_action(name, color, arg)
+      return if @options[:for_engine][:quiet]
+      printf color(color, "%11s %s\n"), name, arg
+      STDOUT.flush
+    end
+
+    # Same as `Kernel.puts`, but doesn't print anything if the `--quiet` option is set.
+    #
+    # @param args [Array] Passed on to `Kernel.puts`
+    def puts(*args)
+      return if @options[:for_engine][:quiet]
+      Kernel.puts(*args)
+    end
+
+    # Wraps the given string in terminal escapes
+    # causing it to have the given color.
+    # If terminal esapes aren't supported on this platform,
+    # just returns the string instead.
+    #
+    # @param color [Symbol] The name of the color to use.
+    #   Can be `:red`, `:green`, or `:yellow`.
+    # @param str [String] The string to wrap in the given color.
+    # @return [String] The wrapped string.
+    def color(color, str)
+      raise "[BUG] Unrecognized color #{color}" unless COLORS[color]
+
+      # Almost any real Unix terminal will support color,
+      # so we just filter for Windows terms (which don't set TERM)
+      # and not-real terminals, which aren't ttys.
+      return str if ENV["TERM"].nil? || ENV["TERM"].empty? || !STDOUT.tty?
+      "\e[#{COLORS[color]}m#{str}\e[0m"
+    end
+
+    def write_output(text, destination)
+      if destination.is_a?(String)
+        open_file(destination, 'w') {|file| file.write(text)}
+      else
+        destination.write(text)
+      end
+    end
+
+    private
+
+    def open_file(filename, flag = 'r')
+      return if filename.nil?
+      flag = 'wb' if @options[:unix_newlines] && flag == 'w'
+      file = File.open(filename, flag)
+      return file unless block_given?
+      yield file
+      file.close
+    end
+
+    def handle_load_error(err)
+      dep = err.message[/^no such file to load -- (.*)/, 1]
+      raise err if @options[:trace] || dep.nil? || dep.empty?
+      $stderr.puts <<MESSAGE
+Required dependency #{dep} not found!
+    Run "gem install #{dep}" to get it.
+  Use --trace for backtrace.
+MESSAGE
+      exit 1
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/exec/sass_convert.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/exec/sass_convert.rb
new file mode 100644
index 0000000..6ea43f2
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/exec/sass_convert.rb
@@ -0,0 +1,269 @@
+require 'optparse'
+require 'fileutils'
+
+module Sass::Exec
+  # The `sass-convert` executable.
+  class SassConvert < Base
+    # @param args [Array<String>] The command-line arguments
+    def initialize(args)
+      super
+      require 'sass'
+      @options[:for_tree] = {}
+      @options[:for_engine] = {:cache => false, :read_cache => true}
+    end
+
+    # Tells optparse how to parse the arguments.
+    #
+    # @param opts [OptionParser]
+    def set_opts(opts)
+      opts.banner = <<END
+Usage: sass-convert [options] [INPUT] [OUTPUT]
+
+Description:
+  Converts between CSS, indented syntax, and SCSS files. For example,
+  this can convert from the indented syntax to SCSS, or from CSS to
+  SCSS (adding appropriate nesting).
+END
+
+      common_options(opts)
+      style(opts)
+      input_and_output(opts)
+      miscellaneous(opts)
+    end
+
+    # Processes the options set by the command-line arguments,
+    # and runs the CSS compiler appropriately.
+    def process_result
+      require 'sass'
+
+      if @options[:recursive]
+        process_directory
+        return
+      end
+
+      super
+      input = @options[:input]
+      if File.directory?(input)
+        raise "Error: '#{input.path}' is a directory (did you mean to use --recursive?)"
+      end
+      output = @options[:output]
+      output = input if @options[:in_place]
+      process_file(input, output)
+    end
+
+    private
+
+    def common_options(opts)
+      opts.separator ''
+      opts.separator 'Common Options:'
+
+      opts.on('-F', '--from FORMAT',
+        'The format to convert from. Can be css, scss, sass.',
+        'By default, this is inferred from the input filename.',
+        'If there is none, defaults to css.') do |name|
+        @options[:from] = name.downcase.to_sym
+        raise "sass-convert no longer supports LessCSS." if @options[:from] == :less
+        unless [:css, :scss, :sass].include?(@options[:from])
+          raise "Unknown format for sass-convert --from: #{name}"
+        end
+      end
+
+      opts.on('-T', '--to FORMAT',
+        'The format to convert to. Can be scss or sass.',
+        'By default, this is inferred from the output filename.',
+        'If there is none, defaults to sass.') do |name|
+        @options[:to] = name.downcase.to_sym
+        unless [:scss, :sass].include?(@options[:to])
+          raise "Unknown format for sass-convert --to: #{name}"
+        end
+      end
+
+      opts.on('-i', '--in-place',
+        'Convert a file to its own syntax.',
+        'This can be used to update some deprecated syntax.') do
+        @options[:in_place] = true
+      end
+
+      opts.on('-R', '--recursive',
+          'Convert all the files in a directory. Requires --from and --to.') do
+        @options[:recursive] = true
+      end
+
+      opts.on("-?", "-h", "--help", "Show this help message.") do
+        puts opts
+        exit
+      end
+
+      opts.on("-v", "--version", "Print the Sass version.") do
+        puts("Sass #{Sass.version[:string]}")
+        exit
+      end
+    end
+
+    def style(opts)
+      opts.separator ''
+      opts.separator 'Style:'
+
+      opts.on('--dasherize', 'Convert underscores to dashes.') do
+        @options[:for_tree][:dasherize] = true
+      end
+
+      opts.on('--indent NUM',
+        'How many spaces to use for each level of indentation. Defaults to 2.',
+        '"t" means use hard tabs.') do |indent|
+
+        if indent == 't'
+          @options[:for_tree][:indent] = "\t"
+        else
+          @options[:for_tree][:indent] = " " * indent.to_i
+        end
+      end
+
+      opts.on('--old', 'Output the old-style ":prop val" property syntax.',
+                       'Only meaningful when generating Sass.') do
+        @options[:for_tree][:old] = true
+      end
+    end
+
+    def input_and_output(opts)
+      opts.separator ''
+      opts.separator 'Input and Output:'
+
+      opts.on('-s', '--stdin', :NONE,
+              'Read input from standard input instead of an input file.',
+              'This is the default if no input file is specified. Requires --from.') do
+        @options[:input] = $stdin
+      end
+
+      encoding_option(opts)
+
+      opts.on('--unix-newlines', 'Use Unix-style newlines in written files.',
+                                 ('Always true on Unix.' unless Sass::Util.windows?)) do
+        @options[:unix_newlines] = true if Sass::Util.windows?
+      end
+    end
+
+    def miscellaneous(opts)
+      opts.separator ''
+      opts.separator 'Miscellaneous:'
+
+        opts.on('--cache-location PATH',
+                'The path to save parsed Sass files. Defaults to .sass-cache.') do |loc|
+          @options[:for_engine][:cache_location] = loc
+        end
+
+      opts.on('-C', '--no-cache', "Don't cache to sassc files.") do
+        @options[:for_engine][:read_cache] = false
+      end
+
+      opts.on('--trace', :NONE, 'Show a full Ruby stack trace on error') do
+        @options[:trace] = true
+      end
+    end
+
+    def process_directory
+      unless @options[:input] = @args.shift
+        raise "Error: directory required when using --recursive."
+      end
+
+      output = @options[:output] = @args.shift
+      raise "Error: --from required when using --recursive." unless @options[:from]
+      raise "Error: --to required when using --recursive." unless @options[:to]
+      unless File.directory?(@options[:input])
+        raise "Error: '#{ options[:input]}' is not a directory"
+      end
+      if @options[:output] && File.exist?(@options[:output]) &&
+        !File.directory?(@options[:output])
+        raise "Error: '#{ options[:output]}' is not a directory"
+      end
+      @options[:output] ||= @options[:input]
+
+      if @options[:to] == @options[:from] && ! options[:in_place]
+        fmt = @options[:from]
+        raise "Error: converting from #{fmt} to #{fmt} without --in-place"
+      end
+
+      ext = @options[:from]
+      Sass::Util.glob("#{ options[:input]}/**/*.#{ext}") do |f|
+        output =
+          if @options[:in_place]
+            f
+          elsif @options[:output]
+            output_name = f.gsub(/\.(c|sa|sc|le)ss$/, " #{ options[:to]}")
+            output_name[0    options[:input].size] = @options[:output]
+            output_name
+          else
+            f.gsub(/\.(c|sa|sc|le)ss$/, " #{ options[:to]}")
+          end
+
+        unless File.directory?(File.dirname(output))
+          puts_action :directory, :green, File.dirname(output)
+          FileUtils.mkdir_p(File.dirname(output))
+        end
+        puts_action :convert, :green, f
+        if File.exist?(output)
+          puts_action :overwrite, :yellow, output
+        else
+          puts_action :create, :green, output
+        end
+
+        process_file(f, output)
+      end
+    end
+
+    def process_file(input, output)
+      input_path, output_path = path_for(input), path_for(output)
+      if input_path
+        @options[:from] ||=
+          case input_path
+          when /\.scss$/; :scss
+          when /\.sass$/; :sass
+          when /\.less$/; raise "sass-convert no longer supports LessCSS."
+          when /\.css$/; :css
+          end
+      elsif @options[:in_place]
+        raise "Error: the --in-place option requires a filename."
+      end
+
+      if output_path
+        @options[:to] ||=
+          case output_path
+          when /\.scss$/; :scss
+          when /\.sass$/; :sass
+          end
+      end
+
+      @options[:from] ||= :css
+      @options[:to] ||= :sass
+      @options[:for_engine][:syntax] = @options[:from]
+
+      out =
+        Sass::Util.silence_sass_warnings do
+          if @options[:from] == :css
+            require 'sass/css'
+            Sass::CSS.new(input.read, @options[:for_tree]).render(@options[:to])
+          else
+            if input_path
+              Sass::Engine.for_file(input_path, @options[:for_engine])
+            else
+              Sass::Engine.new(input.read, @options[:for_engine])
+            end.to_tree.send("to_#{ options[:to]}", @options[:for_tree])
+          end
+        end
+
+      output = input_path if @options[:in_place]
+      write_output(out, output)
+    rescue Sass::SyntaxError => e
+      raise e if @options[:trace]
+      file = " of #{e.sass_filename}" if e.sass_filename
+      raise "Error on line #{e.sass_line}#{file}: #{e.message}\n  Use --trace for backtrace"
+    rescue LoadError => err
+      handle_load_error(err)
+    end
+
+    def path_for(file)
+      return file.path if file.is_a?(File)
+      return file if file.is_a?(String)
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/exec/sass_scss.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/exec/sass_scss.rb
new file mode 100644
index 0000000..9012f8d
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/exec/sass_scss.rb
@@ -0,0 +1,444 @@
+module Sass::Exec
+  # The `sass` and `scss` executables.
+  class SassScss < Base
+    attr_reader :default_syntax
+
+    # @param args [Array<String>] The command-line arguments
+    def initialize(args, default_syntax)
+      super(args)
+      @options[:sourcemap] = :auto
+      @options[:for_engine] = {
+        :load_paths => default_sass_path
+      }
+      @default_syntax = default_syntax
+    end
+
+    protected
+
+    # Tells optparse how to parse the arguments.
+    #
+    # @param opts [OptionParser]
+    def set_opts(opts)
+      opts.banner = <<END
+Usage: #{default_syntax} [options] [INPUT] [OUTPUT]
+
+Description:
+  Converts SCSS or Sass files to CSS.
+END
+
+      common_options(opts)
+      watching_and_updating(opts)
+      input_and_output(opts)
+      miscellaneous(opts)
+    end
+
+    # Processes the options set by the command-line arguments,
+    # and runs the Sass compiler appropriately.
+    def process_result
+      require 'sass'
+
+      if ! options[:update] && ! options[:watch] &&
+          @args.first && colon_path?(@args.first)
+        if @args.size == 1
+          @args = split_colon_path(@args.first)
+        else
+          @options[:update] = true
+        end
+      end
+      load_compass if @options[:compass]
+      return interactive if @options[:interactive]
+      return watch_or_update if @options[:watch] || @options[:update]
+      super
+
+      if @options[:sourcemap] != :none && @options[:output_filename]
+        @options[:sourcemap_filename] = Sass::Util.sourcemap_name(@options[:output_filename])
+      end
+
+      @options[:for_engine][:filename] = @options[:filename]
+      @options[:for_engine][:css_filename] = @options[:output] if @options[:output].is_a?(String)
+      @options[:for_engine][:sourcemap_filename] = @options[:sourcemap_filename]
+      @options[:for_engine][:sourcemap] = @options[:sourcemap]
+
+      run
+    end
+
+    private
+
+    def common_options(opts)
+      opts.separator ''
+      opts.separator 'Common Options:'
+
+      opts.on('-I', '--load-path PATH', 'Specify a Sass import path.') do |path|
+        (@options[:for_engine][:load_paths] ||= []) << path
+      end
+
+      opts.on('-r', '--require LIB', 'Require a Ruby library before running Sass.') do |lib|
+        require lib
+      end
+
+      opts.on('--compass', 'Make Compass imports available and load project configuration.') do
+        @options[:compass] = true
+      end
+
+      opts.on('-t', '--style NAME', 'Output style. Can be nested (default), compact, ' \
+                                    'compressed, or expanded.') do |name|
+        @options[:for_engine][:style] = name.to_sym
+      end
+
+      opts.on("-?", "-h", "--help", "Show this help message.") do
+        puts opts
+        exit
+      end
+
+      opts.on("-v", "--version", "Print the Sass version.") do
+        puts("Sass #{Sass.version[:string]}")
+        exit
+      end
+    end
+
+    def watching_and_updating(opts)
+      opts.separator ''
+      opts.separator 'Watching and Updating:'
+
+      opts.on('--watch', 'Watch files or directories for changes.',
+                         'The location of the generated CSS can be set using a colon:',
+                         "  #{ default_syntax} --watch input #{ default_syntax}:output.css",
+                         "  #{ default_syntax} --watch input-dir:output-dir") do
+        @options[:watch] = true
+      end
+
+      # Polling is used by default on Windows.
+      unless Sass::Util.windows?
+        opts.on('--poll', 'Check for file changes manually, rather than relying on the OS.',
+                          'Only meaningful for --watch.') do
+          @options[:poll] = true
+        end
+      end
+
+      opts.on('--update', 'Compile files or directories to CSS.',
+                          'Locations are set like --watch.') do
+        @options[:update] = true
+      end
+
+      opts.on('-f', '--force', 'Recompile every Sass file, even if the CSS file is newer.',
+                               'Only meaningful for --update.') do
+        @options[:force] = true
+      end
+
+      opts.on('--stop-on-error', 'If a file fails to compile, exit immediately.',
+                                 'Only meaningful for --watch and --update.') do
+        @options[:stop_on_error] = true
+      end
+    end
+
+    def input_and_output(opts)
+      opts.separator ''
+      opts.separator 'Input and Output:'
+
+      if @default_syntax == :sass
+        opts.on('--scss',
+                'Use the CSS-superset SCSS syntax.') do
+          @options[:for_engine][:syntax] = :scss
+        end
+      else
+        opts.on('--sass',
+                'Use the indented Sass syntax.') do
+          @options[:for_engine][:syntax] = :sass
+        end
+      end
+
+      # This is optional for backwards-compatibility with Sass 3.3, which didn't
+      # enable sourcemaps by default and instead used "--sourcemap" to do so.
+      opts.on(:OPTIONAL, '--sourcemap=TYPE',
+          'How to link generated output to the source files.',
+          '  auto (default): relative paths where possible, file URIs elsewhere',
+          '  file: always absolute file URIs',
+          '  inline: include the source text in the sourcemap',
+          '  none: no sourcemaps') do |type|
+        if type && !%w[auto file inline none].include?(type)
+          $stderr.puts "Unknown sourcemap type #{type}.\n\n"
+          $stderr.puts opts
+          exit
+        elsif type.nil?
+          Sass::Util.sass_warn <<MESSAGE.rstrip
+DEPRECATION WARNING: Passing --sourcemap without a value is deprecated.
+Sourcemaps are now generated by default, so this flag has no effect.
+MESSAGE
+        end
+
+        @options[:sourcemap] = (type || :auto).to_sym
+      end
+
+      opts.on('-s', '--stdin', :NONE,
+              'Read input from standard input instead of an input file.',
+              'This is the default if no input file is specified.') do
+        @options[:input] = $stdin
+      end
+
+      encoding_option(opts)
+
+      opts.on('--unix-newlines', 'Use Unix-style newlines in written files.',
+                                 ('Always true on Unix.' unless Sass::Util.windows?)) do
+        @options[:unix_newlines] = true if Sass::Util.windows?
+      end
+
+      opts.on('-g', '--debug-info',
+              'Emit output that can be used by the FireSass Firebug plugin.') do
+        @options[:for_engine][:debug_info] = true
+      end
+
+      opts.on('-l', '--line-numbers', '--line-comments',
+              'Emit comments in the generated CSS indicating the corresponding source line.') do
+        @options[:for_engine][:line_numbers] = true
+      end
+    end
+
+    def miscellaneous(opts)
+      opts.separator ''
+      opts.separator 'Miscellaneous:'
+
+      opts.on('-i', '--interactive',
+              'Run an interactive SassScript shell.') do
+        @options[:interactive] = true
+      end
+
+      opts.on('-c', '--check', "Just check syntax, don't evaluate.") do
+        require 'stringio'
+        @options[:check_syntax] = true
+        @options[:output] = StringIO.new
+      end
+
+      opts.on('--precision NUMBER_OF_DIGITS', Integer,
+              "How many digits of precision to use when outputting decimal numbers.",
+              "Defaults to #{Sass::Script::Value::Number.precision}.") do |precision|
+        Sass::Script::Value::Number.precision = precision
+      end
+
+      opts.on('--cache-location PATH',
+              'The path to save parsed Sass files. Defaults to .sass-cache.') do |loc|
+        @options[:for_engine][:cache_location] = loc
+      end
+
+      opts.on('-C', '--no-cache', "Don't cache parsed Sass files.") do
+        @options[:for_engine][:cache] = false
+      end
+
+      opts.on('--trace', :NONE, 'Show a full Ruby stack trace on error.') do
+        @options[:trace] = true
+      end
+
+      opts.on('-q', '--quiet', 'Silence warnings and status messages during compilation.') do
+        @options[:for_engine][:quiet] = true
+      end
+    end
+
+    def load_compass
+      begin
+        require 'compass'
+      rescue LoadError
+        require 'rubygems'
+        begin
+          require 'compass'
+        rescue LoadError
+          puts "ERROR: Cannot load compass."
+          exit 1
+        end
+      end
+      Compass.add_project_configuration
+      Compass.configuration.project_path ||= Dir.pwd
+      @options[:for_engine][:load_paths] ||= []
+      @options[:for_engine][:load_paths] += Compass.configuration.sass_load_paths
+    end
+
+    def interactive
+      require 'sass/repl'
+      Sass::Repl.new(@options).run
+    end
+
+    # @comment
+    #   rubocop:disable MethodLength
+    def watch_or_update
+      require 'sass/plugin'
+      Sass::Plugin.options.merge! @options[:for_engine]
+      Sass::Plugin.options[:unix_newlines] = @options[:unix_newlines]
+      Sass::Plugin.options[:poll] = @options[:poll]
+      Sass::Plugin.options[:sourcemap] = @options[:sourcemap]
+
+      if @options[:force]
+        raise "The --force flag may only be used with --update." unless @options[:update]
+        Sass::Plugin.options[:always_update] = true
+      end
+
+      raise <<MSG if @args.empty?
+What files should I watch? Did you mean something like:
+    #{ default_syntax} --watch input #{ default_syntax}:output.css
+    #{ default_syntax} --watch input-dir:output-dir
+MSG
+
+      if !colon_path?(@args[0]) && probably_dest_dir?(@args[1])
+        flag = @options[:update] ? "--update" : "--watch"
+        err =
+          if !File.exist?(@args[1])
+            "doesn't exist"
+          elsif @args[1] =~ /\.css$/
+            "is a CSS file"
+          end
+        raise <<MSG if err
+File #{ args[1]} #{err}.
+    Did you mean: #{ default_syntax} #{flag} #{ args[0]}:#{ args[1]}
+MSG
+      end
+
+      # Watch the working directory for changes without adding it to the load
+      # path. This preserves the pre-3.4 behavior when the working directory was
+      # on the load path. We should remove this when we can look for directories
+      # to watch by traversing the import graph.
+      class << Sass::Plugin.compiler
+        # We have to use a class var to make this visible to #watched_file? and
+        # #watched_paths.
+        # rubocop:disable ClassVars
+        @@working_directory = Sass::Util.realpath('.').to_s
+        # rubocop:ensable ClassVars
+
+        def watched_file?(file)
+          super(file) ||
+            (file =~ /\.s[ac]ss$/ && file.start_with?(@@working_directory + File::SEPARATOR))
+        end
+
+        def watched_paths
+          @watched_paths ||= super + [@@working_directory]
+        end
+      end
+
+      dirs, files = @args.map {|name| split_colon_path(name)}.
+        partition {|i, _| File.directory? i}
+      files.map! do |from, to|
+        to ||= from.gsub(/\.[^.]*?$/, '.css')
+        sourcemap = Sass::Util.sourcemap_name(to) if @options[:sourcemap]
+        [from, to, sourcemap]
+      end
+      dirs.map! {|from, to| [from, to || from]}
+      Sass::Plugin.options[:template_location] = dirs
+
+      Sass::Plugin.on_updated_stylesheet do |_, css, sourcemap|
+        [css, sourcemap].each do |file|
+          next unless file
+          puts_action :write, :green, file
+        end
+      end
+
+      had_error = false
+      Sass::Plugin.on_creating_directory {|dirname| puts_action :directory, :green, dirname}
+      Sass::Plugin.on_deleting_css {|filename| puts_action :delete, :yellow, filename}
+      Sass::Plugin.on_deleting_sourcemap {|filename| puts_action :delete, :yellow, filename}
+      Sass::Plugin.on_compilation_error do |error, _, _|
+        if error.is_a?(SystemCallError) && ! options[:stop_on_error]
+          had_error = true
+          puts_action :error, :red, error.message
+          STDOUT.flush
+          next
+        end
+
+        raise error unless error.is_a?(Sass::SyntaxError) && ! options[:stop_on_error]
+        had_error = true
+        puts_action :error, :red,
+          "#{error.sass_filename} (Line #{error.sass_line}: #{error.message})"
+        STDOUT.flush
+      end
+
+      if @options[:update]
+        Sass::Plugin.update_stylesheets(files)
+        exit 1 if had_error
+        return
+      end
+
+      puts ">>> Sass is watching for changes. Press Ctrl-C to stop."
+
+      Sass::Plugin.on_template_modified do |template|
+        puts ">>> Change detected to: #{template}"
+        STDOUT.flush
+      end
+      Sass::Plugin.on_template_created do |template|
+        puts ">>> New template detected: #{template}"
+        STDOUT.flush
+      end
+      Sass::Plugin.on_template_deleted do |template|
+        puts ">>> Deleted template detected: #{template}"
+        STDOUT.flush
+      end
+
+      Sass::Plugin.watch(files)
+    end
+    # @comment
+    #   rubocop:enable MethodLength
+
+    def run
+      input = @options[:input]
+      output = @options[:output]
+
+      @options[:for_engine][:syntax] ||= :scss if input.is_a?(File) && input.path =~ /\.scss$/
+      @options[:for_engine][:syntax] ||= @default_syntax
+      engine =
+        if input.is_a?(File) && ! options[:check_syntax]
+          Sass::Engine.for_file(input.path, @options[:for_engine])
+        else
+          # We don't need to do any special handling of @options[:check_syntax] here,
+          # because the Sass syntax checking happens alongside evaluation
+          # and evaluation doesn't actually evaluate any code anyway.
+          Sass::Engine.new(input.read, @options[:for_engine])
+        end
+
+      input.close if input.is_a?(File)
+
+      if @options[:sourcemap] != :none && @options[:sourcemap_filename]
+        relative_sourcemap_path = Sass::Util.relative_path_from(
+          @options[:sourcemap_filename], Sass::Util.pathname(@options[:output_filename]).dirname)
+        rendered, mapping = engine.render_with_sourcemap(relative_sourcemap_path.to_s)
+        write_output(rendered, output)
+        write_output(mapping.to_json(
+            :type => @options[:sourcemap],
+            :css_path => @options[:output_filename],
+            :sourcemap_path => @options[:sourcemap_filename]) + "\n",
+          @options[:sourcemap_filename])
+      else
+        write_output(engine.render, output)
+      end
+    rescue Sass::SyntaxError => e
+      write_output(Sass::SyntaxError.exception_to_css(e), output) if output.is_a?(String)
+      raise e
+    ensure
+      output.close if output.is_a? File
+    end
+
+    def colon_path?(path)
+      !split_colon_path(path)[1].nil?
+    end
+
+    def split_colon_path(path)
+      one, two = path.split(':', 2)
+      if one && two && Sass::Util.windows? &&
+          one =~ /\A[A-Za-z]\Z/ && two =~ /\A[\/\\]/
+        # If we're on Windows and we were passed a drive letter path,
+        # don't split on that colon.
+        one2, two = two.split(':', 2)
+        one = one + ':' + one2
+      end
+      return one, two
+    end
+
+    # Whether path is likely to be meant as the destination
+    # in a source:dest pair.
+    def probably_dest_dir?(path)
+      return false unless path
+      return false if colon_path?(path)
+      Sass::Util.glob(File.join(path, "*.s[ca]ss")).empty?
+    end
+
+    def default_sass_path
+      return unless ENV['SASS_PATH']
+      # The select here prevents errors when the environment's
+      # load paths specified do not exist.
+      ENV['SASS_PATH'].split(File::PATH_SEPARATOR).select {|d| File.directory?(d)}
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/features.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/features.rb
new file mode 100644
index 0000000..f93031e
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/features.rb
@@ -0,0 +1,47 @@
+require 'set'
+module Sass
+  # Provides `Sass.has_feature?` which allows for simple feature detection
+  # by providing a feature name.
+  module Features
+    # This is the set of features that can be detected.
+    #
+    # When this is updated, the documentation of `feature-exists()` should be
+    # updated as well.
+    KNOWN_FEATURES = Set[*%w{
+      global-variable-shadowing
+      extend-selector-pseudoclass
+      units-level-3
+      at-error
+    }]
+
+    # Check if a feature exists by name. This is used to implement
+    # the Sass function `feature-exists($feature)`
+    #
+    # @param feature_name [String] The case sensitive name of the feature to
+    #   check if it exists in this version of Sass.
+    # @return [Boolean] whether the feature of that name exists.
+    def has_feature?(feature_name)
+      KNOWN_FEATURES.include?(feature_name)
+    end
+
+    # Add a feature to Sass. Plugins can use this to easily expose their
+    # availability to end users. Plugins must prefix their feature
+    # names with a dash to distinguish them from official features.
+    #
+    # @example
+    #   Sass.add_feature("-import-globbing")
+    #   Sass.add_feature("-math-cos")
+    #
+    #
+    # @param feature_name [String] The case sensitive name of the feature to
+    #   to add to Sass. Must begin with a dash.
+    def add_feature(feature_name)
+      unless feature_name[0] == ?-
+        raise ArgumentError.new("Plugin feature names must begin with a dash")
+      end
+      KNOWN_FEATURES << feature_name
+    end
+  end
+
+  extend Features
+end
diff --git a/backends/css/gems/sass-3.2.12/lib/sass/importers.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/importers.rb
similarity index 100%
rename from backends/css/gems/sass-3.2.12/lib/sass/importers.rb
rename to backends/css/gems/sass-3.4.9/lib/sass/importers.rb
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/importers/base.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/importers/base.rb
new file mode 100644
index 0000000..62fb814
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/importers/base.rb
@@ -0,0 +1,182 @@
+module Sass
+  module Importers
+    # The abstract base class for Sass importers.
+    # All importers should inherit from this.
+    #
+    # At the most basic level, an importer is given a string
+    # and must return a {Sass::Engine} containing some Sass code.
+    # This string can be interpreted however the importer wants;
+    # however, subclasses are encouraged to use the URI format
+    # for pathnames.
+    #
+    # Importers that have some notion of "relative imports"
+    # should take a single load path in their constructor,
+    # and interpret paths as relative to that.
+    # They should also implement the \{#find\_relative} method.
+    #
+    # Importers should be serializable via `Marshal.dump`.
+    #
+    # @abstract
+    class Base
+      # Find a Sass file relative to another file.
+      # Importers without a notion of "relative paths"
+      # should just return nil here.
+      #
+      # If the importer does have a notion of "relative paths",
+      # it should ignore its load path during this method.
+      #
+      # See \{#find} for important information on how this method should behave.
+      #
+      # The `:filename` option passed to the returned {Sass::Engine}
+      # should be of a format that could be passed to \{#find}.
+      #
+      # @param uri [String] The URI to import. This is not necessarily relative,
+      #   but this method should only return true if it is.
+      # @param base [String] The base filename. If `uri` is relative,
+      #   it should be interpreted as relative to `base`.
+      #   `base` is guaranteed to be in a format importable by this importer.
+      # @param options [{Symbol => Object}] Options for the Sass file
+      #   containing the ` import` that's currently being resolved.
+      # @return [Sass::Engine, nil] An Engine containing the imported file,
+      #   or nil if it couldn't be found or was in the wrong format.
+      def find_relative(uri, base, options)
+        Sass::Util.abstract(self)
+      end
+
+      # Find a Sass file, if it exists.
+      #
+      # This is the primary entry point of the Importer.
+      # It corresponds directly to an ` import` statement in Sass.
+      # It should do three basic things:
+      #
+      # * Determine if the URI is in this importer's format.
+      #   If not, return nil.
+      # * Determine if the file indicated by the URI actually exists and is readable.
+      #   If not, return nil.
+      # * Read the file and place the contents in a {Sass::Engine}.
+      #   Return that engine.
+      #
+      # If this importer's format allows for file extensions,
+      # it should treat them the same way as the default {Filesystem} importer.
+      # If the URI explicitly has a `.sass` or `.scss` filename,
+      # the importer should look for that exact file
+      # and import it as the syntax indicated.
+      # If it doesn't exist, the importer should return nil.
+      #
+      # If the URI doesn't have either of these extensions,
+      # the importer should look for files with the extensions.
+      # If no such files exist, it should return nil.
+      #
+      # The {Sass::Engine} to be returned should be passed `options`,
+      # with a few modifications. `:syntax` should be set appropriately,
+      # `:filename` should be set to `uri`,
+      # and `:importer` should be set to this importer.
+      #
+      # @param uri [String] The URI to import.
+      # @param options [{Symbol => Object}] Options for the Sass file
+      #   containing the ` import` that's currently being resolved.
+      #   This is safe for subclasses to modify destructively.
+      #   Callers should only pass in a value they don't mind being destructively modified.
+      # @return [Sass::Engine, nil] An Engine containing the imported file,
+      #   or nil if it couldn't be found or was in the wrong format.
+      def find(uri, options)
+        Sass::Util.abstract(self)
+      end
+
+      # Returns the time the given Sass file was last modified.
+      #
+      # If the given file has been deleted or the time can't be accessed
+      # for some other reason, this should return nil.
+      #
+      # @param uri [String] The URI of the file to check.
+      #   Comes from a `:filename` option set on an engine returned by this importer.
+      # @param options [{Symbol => Objet}] Options for the Sass file
+      #   containing the ` import` currently being checked.
+      # @return [Time, nil]
+      def mtime(uri, options)
+        Sass::Util.abstract(self)
+      end
+
+      # Get the cache key pair for the given Sass URI.
+      # The URI need not be checked for validity.
+      #
+      # The only strict requirement is that the returned pair of strings
+      # uniquely identify the file at the given URI.
+      # However, the first component generally corresponds roughly to the directory,
+      # and the second to the basename, of the URI.
+      #
+      # Note that keys must be unique *across importers*.
+      # Thus it's probably a good idea to include the importer name
+      # at the beginning of the first component.
+      #
+      # @param uri [String] A URI known to be valid for this importer.
+      # @param options [{Symbol => Object}] Options for the Sass file
+      #   containing the ` import` currently being checked.
+      # @return [(String, String)] The key pair which uniquely identifies
+      #   the file at the given URI.
+      def key(uri, options)
+        Sass::Util.abstract(self)
+      end
+
+      # Get the publicly-visible URL for an imported file. This URL is used by
+      # source maps to link to the source stylesheet. This may return `nil` to
+      # indicate that no public URL is available; however, this will cause
+      # sourcemap generation to fail if any CSS is generated from files imported
+      # from this importer.
+      #
+      # If an absolute "file:" URI can be produced for an imported file, that
+      # should be preferred to returning `nil`. However, a URL relative to
+      # `sourcemap_directory` should be preferred over an absolute "file:" URI.
+      #
+      # @param uri [String] A URI known to be valid for this importer.
+      # @param sourcemap_directory [String, NilClass] The absolute path to a
+      #   directory on disk where the sourcemap will be saved. If uri refers to
+      #   a file on disk that's accessible relative to sourcemap_directory, this
+      #   may return a relative URL. This may be `nil` if the sourcemap's
+      #   eventual location is unknown.
+      # @return [String?] The publicly-visible URL for this file, or `nil`
+      #   indicating that no publicly-visible URL exists. This should be
+      #   appropriately URL-escaped.
+      def public_url(uri, sourcemap_directory)
+        return if @public_url_warning_issued
+        @public_url_warning_issued = true
+        Sass::Util.sass_warn <<WARNING
+WARNING: #{self.class.name} should define the #public_url method.
+WARNING
+        nil
+      end
+
+      # A string representation of the importer.
+      # Should be overridden by subclasses.
+      #
+      # This is used to help debugging,
+      # and should usually just show the load path encapsulated by this importer.
+      #
+      # @return [String]
+      def to_s
+        Sass::Util.abstract(self)
+      end
+
+      # If the importer is based on files on the local filesystem
+      # this method should return folders which should be watched
+      # for changes.
+      #
+      # @return [Array<String>] List of absolute paths of directories to watch
+      def directories_to_watch
+        []
+      end
+
+      # If this importer is based on files on the local filesystem This method
+      # should return true if the file, when changed, should trigger a
+      # recompile.
+      #
+      # It is acceptable for non-sass files to be watched and trigger a recompile.
+      #
+      # @param filename [String] The absolute filename for a file that has changed.
+      # @return [Boolean] When the file changed should cause a recompile.
+      def watched_file?(filename)
+        false
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/importers/filesystem.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/importers/filesystem.rb
new file mode 100644
index 0000000..aeff696
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/importers/filesystem.rb
@@ -0,0 +1,217 @@
+require 'set'
+
+module Sass
+  module Importers
+    # The default importer, used for any strings found in the load path.
+    # Simply loads Sass files from the filesystem using the default logic.
+    class Filesystem < Base
+      attr_accessor :root
+
+      # Creates a new filesystem importer that imports files relative to a given path.
+      #
+      # @param root [String] The root path.
+      #   This importer will import files relative to this path.
+      def initialize(root)
+        @root = File.expand_path(root)
+        @real_root = Sass::Util.realpath(@root).to_s
+        @same_name_warnings = Set.new
+      end
+
+      # @see Base#find_relative
+      def find_relative(name, base, options)
+        _find(File.dirname(base), name, options)
+      end
+
+      # @see Base#find
+      def find(name, options)
+        _find(@root, name, options)
+      end
+
+      # @see Base#mtime
+      def mtime(name, options)
+        file, _ = Sass::Util.destructure(find_real_file(@root, name, options))
+        File.mtime(file) if file
+      rescue Errno::ENOENT
+        nil
+      end
+
+      # @see Base#key
+      def key(name, options)
+        [self.class.name + ":" + File.dirname(File.expand_path(name)),
+         File.basename(name)]
+      end
+
+      # @see Base#to_s
+      def to_s
+        @root
+      end
+
+      def hash
+        @root.hash
+      end
+
+      def eql?(other)
+        !other.nil? && other.respond_to?(:root) && root.eql?(other.root)
+      end
+
+      # @see Base#directories_to_watch
+      def directories_to_watch
+        [root]
+      end
+
+      # @see Base#watched_file?
+      def watched_file?(filename)
+        # Check against the root with symlinks resolved, since Listen
+        # returns fully-resolved paths.
+        filename =~ /\.s[ac]ss$/ && filename.start_with?(@real_root + File::SEPARATOR)
+      end
+
+      def public_url(name, sourcemap_directory)
+        file_pathname = Sass::Util.cleanpath(Sass::Util.absolute_path(name, @root))
+        return Sass::Util.file_uri_from_path(file_pathname) if sourcemap_directory.nil?
+
+        sourcemap_pathname = Sass::Util.cleanpath(sourcemap_directory)
+        begin
+          Sass::Util.file_uri_from_path(
+            Sass::Util.relative_path_from(file_pathname, sourcemap_pathname))
+        rescue ArgumentError # when a relative path cannot be constructed
+          Sass::Util.file_uri_from_path(file_pathname)
+        end
+      end
+
+      protected
+
+      # If a full uri is passed, this removes the root from it
+      # otherwise returns the name unchanged
+      def remove_root(name)
+        if name.index(@root + "/") == 0
+          name[(@root.length + 1)..-1]
+        else
+          name
+        end
+      end
+
+      # A hash from file extensions to the syntaxes for those extensions.
+      # The syntaxes must be `:sass` or `:scss`.
+      #
+      # This can be overridden by subclasses that want normal filesystem importing
+      # with unusual extensions.
+      #
+      # @return [{String => Symbol}]
+      def extensions
+        {'sass' => :sass, 'scss' => :scss}
+      end
+
+      # Given an ` import`ed path, returns an array of possible
+      # on-disk filenames and their corresponding syntaxes for that path.
+      #
+      # @param name [String] The filename.
+      # @return [Array(String, Symbol)] An array of pairs.
+      #   The first element of each pair is a filename to look for;
+      #   the second element is the syntax that file would be in (`:sass` or `:scss`).
+      def possible_files(name)
+        name = escape_glob_characters(name)
+        dirname, basename, extname = split(name)
+        sorted_exts = extensions.sort
+        syntax = extensions[extname]
+
+        if syntax
+          ret = [["#{dirname}/{_,}#{basename}.#{extensions.invert[syntax]}", syntax]]
+        else
+          ret = sorted_exts.map {|ext, syn| ["#{dirname}/{_,}#{basename}.#{ext}", syn]}
+        end
+
+        # JRuby chokes when trying to import files from JARs when the path starts with './'.
+        ret.map {|f, s| [f.sub(/^\.\//, ''), s]}
+      end
+
+      def escape_glob_characters(name)
+        name.gsub(/[\*\[\]\{\}\?]/) do |char|
+          "\\#{char}"
+        end
+      end
+
+      REDUNDANT_DIRECTORY = /#{Regexp.escape(File::SEPARATOR)}\.#{Regexp.escape(File::SEPARATOR)}/
+      # Given a base directory and an ` import`ed name,
+      # finds an existant file that matches the name.
+      #
+      # @param dir [String] The directory relative to which to search.
+      # @param name [String] The filename to search for.
+      # @return [(String, Symbol)] A filename-syntax pair.
+      def find_real_file(dir, name, options)
+        # On windows 'dir' or 'name' can be in native File::ALT_SEPARATOR form.
+        dir = dir.gsub(File::ALT_SEPARATOR, File::SEPARATOR) unless File::ALT_SEPARATOR.nil?
+        name = name.gsub(File::ALT_SEPARATOR, File::SEPARATOR) unless File::ALT_SEPARATOR.nil?
+
+        found = possible_files(remove_root(name)).map do |f, s|
+          path = (dir == "." || Sass::Util.pathname(f).absolute?) ? f :
+            "#{escape_glob_characters(dir)}/#{f}"
+          Dir[path].map do |full_path|
+            full_path.gsub!(REDUNDANT_DIRECTORY, File::SEPARATOR)
+            [Sass::Util.cleanpath(full_path).to_s, s]
+          end
+        end
+        found = Sass::Util.flatten(found, 1)
+        return if found.empty?
+
+        if found.size > 1 && ! same_name_warnings include?(found.first.first)
+          found.each {|(f, _)| @same_name_warnings << f}
+          relative_to = Sass::Util.pathname(dir)
+          if options[:_from_import_node]
+            # If _line exists, we're here due to an actual import in an
+            # import_node and we want to print a warning for a user writing an
+            # ambiguous import.
+            candidates = found.map do |(f, _)|
+              "  " + Sass::Util.pathname(f).relative_path_from(relative_to).to_s
+            end.join("\n")
+            raise Sass::SyntaxError.new(<<MESSAGE)
+It's not clear which file to import for '@import "#{name}"'.
+Candidates:
+#{candidates}
+Please delete or rename all but one of these files.
+MESSAGE
+          else
+            # Otherwise, we're here via StalenessChecker, and we want to print a
+            # warning for a user running `sass --watch` with two ambiguous files.
+            candidates = found.map {|(f, _)| "    " + File.basename(f)}.join("\n")
+            Sass::Util.sass_warn <<WARNING
+WARNING: In #{File.dirname(name)}:
+  There are multiple files that match the name "#{File.basename(name)}":
+#{candidates}
+WARNING
+          end
+        end
+        found.first
+      end
+
+      # Splits a filename into three parts, a directory part, a basename, and an extension
+      # Only the known extensions returned from the extensions method will be recognized as such.
+      def split(name)
+        extension = nil
+        dirname, basename = File.dirname(name), File.basename(name)
+        if basename =~ /^(.*)\.(#{extensions.keys.map {|e| Regexp.escape(e)}.join('|')})$/
+          basename = $1
+          extension = $2
+        end
+        [dirname, basename, extension]
+      end
+
+      private
+
+      def _find(dir, name, options)
+        full_filename, syntax = Sass::Util.destructure(find_real_file(dir, name, options))
+        return unless full_filename && File.readable?(full_filename)
+
+        # TODO: this preserves historical behavior, but it's possible
+        # :filename should be either normalized to the native format
+        # or consistently URI-format.
+        full_filename = full_filename.tr("\\", "/") if Sass::Util.windows?
+
+        options[:syntax] = syntax
+        options[:filename] = full_filename
+        options[:importer] = self
+        Sass::Engine.new(File.read(full_filename), options)
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/logger.rb b/backends/css/gems/sass-3.4.9/lib/sass/logger.rb
new file mode 100644
index 0000000..f3f2045
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/logger.rb
@@ -0,0 +1,12 @@
+module Sass::Logger; end
+
+require "sass/logger/log_level"
+require "sass/logger/base"
+
+module Sass
+  class << self
+    attr_accessor :logger
+  end
+
+  self.logger = Sass::Logger::Base.new
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/logger/base.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/logger/base.rb
new file mode 100644
index 0000000..a9d3631
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/logger/base.rb
@@ -0,0 +1,30 @@
+require 'sass/logger/log_level'
+
+class Sass::Logger::Base
+  include Sass::Logger::LogLevel
+
+  attr_accessor :log_level
+  attr_accessor :disabled
+
+  log_level :trace
+  log_level :debug
+  log_level :info
+  log_level :warn
+  log_level :error
+
+  def initialize(log_level = :debug)
+    self.log_level = log_level
+  end
+
+  def logging_level?(level)
+    !disabled && self.class.log_level?(level, log_level)
+  end
+
+  def log(level, message)
+    _log(level, message) if logging_level?(level)
+  end
+
+  def _log(level, message)
+    Kernel.warn(message)
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/logger/log_level.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/logger/log_level.rb
new file mode 100644
index 0000000..39e7cec
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/logger/log_level.rb
@@ -0,0 +1,45 @@
+module Sass
+  module Logger
+    module LogLevel
+      def self.included(base)
+        base.extend(ClassMethods)
+      end
+
+      module ClassMethods
+        def inherited(subclass)
+          subclass.log_levels = subclass.superclass.log_levels.dup
+        end
+
+        attr_writer :log_levels
+
+        def log_levels
+          @log_levels ||= {}
+        end
+
+        def log_level?(level, min_level)
+          log_levels[level] >= log_levels[min_level]
+        end
+
+        def log_level(name, options = {})
+          if options[:prepend]
+            level = log_levels.values.min
+            level = level.nil? ? 0 : level - 1
+          else
+            level = log_levels.values.max
+            level = level.nil? ? 0 : level + 1
+          end
+          log_levels.update(name => level)
+          define_logger(name)
+        end
+
+        def define_logger(name, options = {})
+          class_eval <<-RUBY, __FILE__, __LINE__ + 1
+            def #{name}(message)
+              #{options.fetch(:to, :log)}(#{name.inspect}, message)
+            end
+          RUBY
+        end
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/media.rb b/backends/css/gems/sass-3.4.9/lib/sass/media.rb
new file mode 100644
index 0000000..dc4542d
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/media.rb
@@ -0,0 +1,210 @@
+# A namespace for the ` media` query parse tree.
+module Sass::Media
+  # A comma-separated list of queries.
+  #
+  #     media_query [ ',' S* media_query ]*
+  class QueryList
+    # The queries contained in this list.
+    #
+    # @return [Array<Query>]
+    attr_accessor :queries
+
+    # @param queries [Array<Query>] See \{#queries}
+    def initialize(queries)
+      @queries = queries
+    end
+
+    # Merges this query list with another. The returned query list
+    # queries for the intersection between the two inputs.
+    #
+    # Both query lists should be resolved.
+    #
+    # @param other [QueryList]
+    # @return [QueryList?] The merged list, or nil if there is no intersection.
+    def merge(other)
+      new_queries = queries.map {|q1| other.queries.map {|q2| q1.merge(q2)}}.flatten.compact
+      return if new_queries.empty?
+      QueryList.new(new_queries)
+    end
+
+    # Returns the CSS for the media query list.
+    #
+    # @return [String]
+    def to_css
+      queries.map {|q| q.to_css}.join(', ')
+    end
+
+    # Returns the Sass/SCSS code for the media query list.
+    #
+    # @param options [{Symbol => Object}] An options hash (see {Sass::CSS#initialize}).
+    # @return [String]
+    def to_src(options)
+      queries.map {|q| q.to_src(options)}.join(', ')
+    end
+
+    # Returns a representation of the query as an array of strings and
+    # potentially {Sass::Script::Tree::Node}s (if there's interpolation in it).
+    # When the interpolation is resolved and the strings are joined together,
+    # this will be the string representation of this query.
+    #
+    # @return [Array<String, Sass::Script::Tree::Node>]
+    def to_a
+      Sass::Util.intersperse(queries.map {|q| q.to_a}, ', ').flatten
+    end
+
+    # Returns a deep copy of this query list and all its children.
+    #
+    # @return [QueryList]
+    def deep_copy
+      QueryList.new(queries.map {|q| q.deep_copy})
+    end
+  end
+
+  # A single media query.
+  #
+  #     [ [ONLY | NOT]? S* media_type S* | expression ] [ AND S* expression ]*
+  class Query
+    # The modifier for the query.
+    #
+    # When parsed as Sass code, this contains strings and SassScript nodes. When
+    # parsed as CSS, it contains a single string (accessible via
+    # \{#resolved_modifier}).
+    #
+    # @return [Array<String, Sass::Script::Tree::Node>]
+    attr_accessor :modifier
+
+    # The type of the query (e.g. `"screen"` or `"print"`).
+    #
+    # When parsed as Sass code, this contains strings and SassScript nodes. When
+    # parsed as CSS, it contains a single string (accessible via
+    # \{#resolved_type}).
+    #
+    # @return [Array<String, Sass::Script::Tree::Node>]
+    attr_accessor :type
+
+    # The trailing expressions in the query.
+    #
+    # When parsed as Sass code, each expression contains strings and SassScript
+    # nodes. When parsed as CSS, each one contains a single string.
+    #
+    # @return [Array<Array<String, Sass::Script::Tree::Node>>]
+    attr_accessor :expressions
+
+    # @param modifier [Array<String, Sass::Script::Tree::Node>] See \{#modifier}
+    # @param type [Array<String, Sass::Script::Tree::Node>] See \{#type}
+    # @param expressions [Array<Array<String, Sass::Script::Tree::Node>>] See \{#expressions}
+    def initialize(modifier, type, expressions)
+      @modifier = modifier
+      @type = type
+      @expressions = expressions
+    end
+
+    # See \{#modifier}.
+    # @return [String]
+    def resolved_modifier
+      # modifier should contain only a single string
+      modifier.first || ''
+    end
+
+    # See \{#type}.
+    # @return [String]
+    def resolved_type
+      # type should contain only a single string
+      type.first || ''
+    end
+
+    # Merges this query with another. The returned query queries for
+    # the intersection between the two inputs.
+    #
+    # Both queries should be resolved.
+    #
+    # @param other [Query]
+    # @return [Query?] The merged query, or nil if there is no intersection.
+    def merge(other)
+      m1, t1 = resolved_modifier.downcase, resolved_type.downcase
+      m2, t2 = other.resolved_modifier.downcase, other.resolved_type.downcase
+      t1 = t2 if t1.empty?
+      t2 = t1 if t2.empty?
+      if (m1 == 'not') ^ (m2 == 'not')
+        return if t1 == t2
+        type = m1 == 'not' ? t2 : t1
+        mod = m1 == 'not' ? m2 : m1
+      elsif m1 == 'not' && m2 == 'not'
+        # CSS has no way of representing "neither screen nor print"
+        return unless t1 == t2
+        type = t1
+        mod = 'not'
+      elsif t1 != t2
+        return
+      else # t1 == t2, neither m1 nor m2 are "not"
+        type = t1
+        mod = m1.empty? ? m2 : m1
+      end
+      Query.new([mod], [type], other.expressions + expressions)
+    end
+
+    # Returns the CSS for the media query.
+    #
+    # @return [String]
+    def to_css
+      css = ''
+      css << resolved_modifier
+      css << ' ' unless resolved_modifier.empty?
+      css << resolved_type
+      css << ' and ' unless resolved_type.empty? || expressions.empty?
+      css << expressions.map do |e|
+        # It's possible for there to be script nodes in Expressions even when
+        # we're converting to CSS in the case where we parsed the document as
+        # CSS originally (as in css_test.rb).
+        e.map {|c| c.is_a?(Sass::Script::Tree::Node) ? c.to_sass : c.to_s}.join
+      end.join(' and ')
+      css
+    end
+
+    # Returns the Sass/SCSS code for the media query.
+    #
+    # @param options [{Symbol => Object}] An options hash (see {Sass::CSS#initialize}).
+    # @return [String]
+    def to_src(options)
+      src = ''
+      src << Sass::Media._interp_to_src(modifier, options)
+      src << ' ' unless modifier.empty?
+      src << Sass::Media._interp_to_src(type, options)
+      src << ' and ' unless type.empty? || expressions.empty?
+      src << expressions.map do |e|
+        Sass::Media._interp_to_src(e, options)
+      end.join(' and ')
+      src
+    end
+
+    # @see \{MediaQuery#to\_a}
+    def to_a
+      res = []
+      res += modifier
+      res << ' ' unless modifier.empty?
+      res += type
+      res << ' and ' unless type.empty? || expressions.empty?
+      res += Sass::Util.intersperse(expressions, ' and ').flatten
+      res
+    end
+
+    # Returns a deep copy of this query and all its children.
+    #
+    # @return [Query]
+    def deep_copy
+      Query.new(
+        modifier.map {|c| c.is_a?(Sass::Script::Tree::Node) ? c.deep_copy : c},
+        type.map {|c| c.is_a?(Sass::Script::Tree::Node) ? c.deep_copy : c},
+        expressions.map {|e| e.map {|c| c.is_a?(Sass::Script::Tree::Node) ? c.deep_copy : c}})
+    end
+  end
+
+  # Converts an interpolation array to source.
+  #
+  # @param interp [Array<String, Sass::Script::Tree::Node>] The interpolation array to convert.
+  # @param options [{Symbol => Object}] An options hash (see {Sass::CSS#initialize}).
+  # @return [String]
+  def self._interp_to_src(interp, options)
+    interp.map {|r| r.is_a?(String) ? r : r.to_sass(options)}.join
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/plugin.rb b/backends/css/gems/sass-3.4.9/lib/sass/plugin.rb
new file mode 100644
index 0000000..08bd9b1
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/plugin.rb
@@ -0,0 +1,133 @@
+require 'fileutils'
+
+require 'sass'
+require 'sass/plugin/compiler'
+
+module Sass
+  # This module provides a single interface to the compilation of Sass/SCSS files
+  # for an application. It provides global options and checks whether CSS files
+  # need to be updated.
+  #
+  # This module is used as the primary interface with Sass
+  # when it's used as a plugin for various frameworks.
+  # All Rack-enabled frameworks are supported out of the box.
+  # The plugin is
+  # {file:SASS_REFERENCE.md#rails_merb_plugin automatically activated for Rails and Merb}.
+  # Other frameworks must enable it explicitly; see {Sass::Plugin::Rack}.
+  #
+  # This module has a large set of callbacks available
+  # to allow users to run code (such as logging) when certain things happen.
+  # All callback methods are of the form `on_#{name}`,
+  # and they all take a block that's called when the given action occurs.
+  #
+  # Note that this class proxies almost all methods to its {Sass::Plugin::Compiler} instance.
+  # See \{#compiler}.
+  #
+  # @example Using a callback
+  #   Sass::Plugin.on_updating_stylesheet do |template, css|
+  #     puts "Compiling #{template} to #{css}"
+  #   end
+  #   Sass::Plugin.update_stylesheets
+  #     #=> Compiling app/sass/screen.scss to public/stylesheets/screen.css
+  #     #=> Compiling app/sass/print.scss to public/stylesheets/print.css
+  #     #=> Compiling app/sass/ie.scss to public/stylesheets/ie.css
+  # @see Sass::Plugin::Compiler
+  module Plugin
+    extend self
+
+    @checked_for_updates = false
+
+    # Whether or not Sass has **ever** checked if the stylesheets need to be updated
+    # (in this Ruby instance).
+    #
+    # @return [Boolean]
+    attr_accessor :checked_for_updates
+
+    # Same as \{#update\_stylesheets}, but respects \{#checked\_for\_updates}
+    # and the {file:SASS_REFERENCE.md#always_update-option `:always_update`}
+    # and {file:SASS_REFERENCE.md#always_check-option `:always_check`} options.
+    #
+    # @see #update_stylesheets
+    def check_for_updates
+      return unless !Sass::Plugin.checked_for_updates ||
+          Sass::Plugin.options[:always_update] || Sass::Plugin.options[:always_check]
+      update_stylesheets
+    end
+
+    # Returns the singleton compiler instance.
+    # This compiler has been pre-configured according
+    # to the plugin configuration.
+    #
+    # @return [Sass::Plugin::Compiler]
+    def compiler
+      @compiler ||= Compiler.new
+    end
+
+    # Updates out-of-date stylesheets.
+    #
+    # Checks each Sass/SCSS file in
+    # {file:SASS_REFERENCE.md#template_location-option `:template_location`}
+    # to see if it's been modified more recently than the corresponding CSS file
+    # in {file:SASS_REFERENCE.md#css_location-option `:css_location`}.
+    # If it has, it updates the CSS file.
+    #
+    # @param individual_files [Array<(String, String)>]
+    #   A list of files to check for updates
+    #   **in addition to those specified by the
+    #   {file:SASS_REFERENCE.md#template_location-option `:template_location` option}.**
+    #   The first string in each pair is the location of the Sass/SCSS file,
+    #   the second is the location of the CSS file that it should be compiled to.
+    def update_stylesheets(individual_files = [])
+      return if options[:never_update]
+      compiler.update_stylesheets(individual_files)
+    end
+
+    # Updates all stylesheets, even those that aren't out-of-date.
+    # Ignores the cache.
+    #
+    # @param individual_files [Array<(String, String)>]
+    #   A list of files to check for updates
+    #   **in addition to those specified by the
+    #   {file:SASS_REFERENCE.md#template_location-option `:template_location` option}.**
+    #   The first string in each pair is the location of the Sass/SCSS file,
+    #   the second is the location of the CSS file that it should be compiled to.
+    # @see #update_stylesheets
+    def force_update_stylesheets(individual_files = [])
+      Compiler.new(options.dup.merge(
+          :never_update => false,
+          :always_update => true,
+          :cache => false)).update_stylesheets(individual_files)
+    end
+
+    # All other method invocations are proxied to the \{#compiler}.
+    #
+    # @see #compiler
+    # @see Sass::Plugin::Compiler
+    def method_missing(method, *args, &block)
+      if compiler.respond_to?(method)
+        compiler.send(method, *args, &block)
+      else
+        super
+      end
+    end
+
+    # For parity with method_missing
+    def respond_to?(method)
+      super || compiler.respond_to?(method)
+    end
+
+    # There's a small speedup by not using method missing for frequently delegated methods.
+    def options
+      compiler.options
+    end
+  end
+end
+
+if defined?(ActionController)
+  # On Rails 3+ the rails plugin is loaded at the right time in railtie.rb
+  require 'sass/plugin/rails' unless Sass::Util.ap_geq_3?
+elsif defined?(Merb::Plugins)
+  require 'sass/plugin/merb'
+else
+  require 'sass/plugin/generic'
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/plugin/compiler.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/plugin/compiler.rb
new file mode 100644
index 0000000..d4c339b
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/plugin/compiler.rb
@@ -0,0 +1,571 @@
+require 'fileutils'
+
+require 'sass'
+# XXX CE: is this still necessary now that we have the compiler class?
+require 'sass/callbacks'
+require 'sass/plugin/configuration'
+require 'sass/plugin/staleness_checker'
+
+module Sass::Plugin
+  # The Compiler class handles compilation of multiple files and/or directories,
+  # including checking which CSS files are out-of-date and need to be updated
+  # and calling Sass to perform the compilation on those files.
+  #
+  # {Sass::Plugin} uses this class to update stylesheets for a single application.
+  # Unlike {Sass::Plugin}, though, the Compiler class has no global state,
+  # and so multiple instances may be created and used independently.
+  #
+  # If you need to compile a Sass string into CSS,
+  # please see the {Sass::Engine} class.
+  #
+  # Unlike {Sass::Plugin}, this class doesn't keep track of
+  # whether or how many times a stylesheet should be updated.
+  # Therefore, the following `Sass::Plugin` options are ignored by the Compiler:
+  #
+  # * `:never_update`
+  # * `:always_check`
+  class Compiler
+    include Configuration
+    extend Sass::Callbacks
+
+    # Creates a new compiler.
+    #
+    # @param opts [{Symbol => Object}]
+    #   See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
+    def initialize(opts = {})
+      @watched_files = Set.new
+      options.merge!(opts)
+    end
+
+    # Register a callback to be run before stylesheets are mass-updated.
+    # This is run whenever \{#update\_stylesheets} is called,
+    # unless the \{file:SASS_REFERENCE.md#never_update-option `:never_update` option}
+    # is enabled.
+    #
+    # @yield [files]
+    # @yieldparam files [<(String, String, String)>]
+    #   Individual files to be updated. Files in directories specified are included in this list.
+    #   The first element of each pair is the source file,
+    #   the second is the target CSS file,
+    #   the third is the target sourcemap file.
+    define_callback :updating_stylesheets
+
+    # Register a callback to be run after stylesheets are mass-updated.
+    # This is run whenever \{#update\_stylesheets} is called,
+    # unless the \{file:SASS_REFERENCE.md#never_update-option `:never_update` option}
+    # is enabled.
+    #
+    # @yield [updated_files]
+    # @yieldparam updated_files [<(String, String)>]
+    #   Individual files that were updated.
+    #   The first element of each pair is the source file, the second is the target CSS file.
+    define_callback :updated_stylesheets
+
+    # Register a callback to be run after a single stylesheet is updated.
+    # The callback is only run if the stylesheet is really updated;
+    # if the CSS file is fresh, this won't be run.
+    #
+    # Even if the \{file:SASS_REFERENCE.md#full_exception-option `:full_exception` option}
+    # is enabled, this callback won't be run
+    # when an exception CSS file is being written.
+    # To run an action for those files, use \{#on\_compilation\_error}.
+    #
+    # @yield [template, css, sourcemap]
+    # @yieldparam template [String]
+    #   The location of the Sass/SCSS file being updated.
+    # @yieldparam css [String]
+    #   The location of the CSS file being generated.
+    # @yieldparam sourcemap [String]
+    #   The location of the sourcemap being generated, if any.
+    define_callback :updated_stylesheet
+
+    # Register a callback to be run when compilation starts.
+    #
+    # In combination with on_updated_stylesheet, this could be used
+    # to collect compilation statistics like timing or to take a
+    # diff of the changes to the output file.
+    #
+    # @yield [template, css, sourcemap]
+    # @yieldparam template [String]
+    #   The location of the Sass/SCSS file being updated.
+    # @yieldparam css [String]
+    #   The location of the CSS file being generated.
+    # @yieldparam sourcemap [String]
+    #   The location of the sourcemap being generated, if any.
+    define_callback :compilation_starting
+
+    # Register a callback to be run when Sass decides not to update a stylesheet.
+    # In particular, the callback is run when Sass finds that
+    # the template file and none of its dependencies
+    # have been modified since the last compilation.
+    #
+    # Note that this is **not** run when the
+    # \{file:SASS_REFERENCE.md#never-update_option `:never_update` option} is set,
+    # nor when Sass decides not to compile a partial.
+    #
+    # @yield [template, css]
+    # @yieldparam template [String]
+    #   The location of the Sass/SCSS file not being updated.
+    # @yieldparam css [String]
+    #   The location of the CSS file not being generated.
+    define_callback :not_updating_stylesheet
+
+    # Register a callback to be run when there's an error
+    # compiling a Sass file.
+    # This could include not only errors in the Sass document,
+    # but also errors accessing the file at all.
+    #
+    # @yield [error, template, css]
+    # @yieldparam error [Exception] The exception that was raised.
+    # @yieldparam template [String]
+    #   The location of the Sass/SCSS file being updated.
+    # @yieldparam css [String]
+    #   The location of the CSS file being generated.
+    define_callback :compilation_error
+
+    # Register a callback to be run when Sass creates a directory
+    # into which to put CSS files.
+    #
+    # Note that even if multiple levels of directories need to be created,
+    # the callback may only be run once.
+    # For example, if "foo/" exists and "foo/bar/baz/" needs to be created,
+    # this may only be run for "foo/bar/baz/".
+    # This is not a guarantee, however;
+    # it may also be run for "foo/bar/".
+    #
+    # @yield [dirname]
+    # @yieldparam dirname [String]
+    #   The location of the directory that was created.
+    define_callback :creating_directory
+
+    # Register a callback to be run when Sass detects
+    # that a template has been modified.
+    # This is only run when using \{#watch}.
+    #
+    # @yield [template]
+    # @yieldparam template [String]
+    #   The location of the template that was modified.
+    define_callback :template_modified
+
+    # Register a callback to be run when Sass detects
+    # that a new template has been created.
+    # This is only run when using \{#watch}.
+    #
+    # @yield [template]
+    # @yieldparam template [String]
+    #   The location of the template that was created.
+    define_callback :template_created
+
+    # Register a callback to be run when Sass detects
+    # that a template has been deleted.
+    # This is only run when using \{#watch}.
+    #
+    # @yield [template]
+    # @yieldparam template [String]
+    #   The location of the template that was deleted.
+    define_callback :template_deleted
+
+    # Register a callback to be run when Sass deletes a CSS file.
+    # This happens when the corresponding Sass/SCSS file has been deleted
+    # and when the compiler cleans the output files.
+    #
+    # @yield [filename]
+    # @yieldparam filename [String]
+    #   The location of the CSS file that was deleted.
+    define_callback :deleting_css
+
+    # Register a callback to be run when Sass deletes a sourcemap file.
+    # This happens when the corresponding Sass/SCSS file has been deleted
+    # and when the compiler cleans the output files.
+    #
+    # @yield [filename]
+    # @yieldparam filename [String]
+    #   The location of the sourcemap file that was deleted.
+    define_callback :deleting_sourcemap
+
+    # Updates out-of-date stylesheets.
+    #
+    # Checks each Sass/SCSS file in
+    # {file:SASS_REFERENCE.md#template_location-option `:template_location`}
+    # to see if it's been modified more recently than the corresponding CSS file
+    # in {file:SASS_REFERENCE.md#css_location-option `:css_location`}.
+    # If it has, it updates the CSS file.
+    #
+    # @param individual_files [Array<(String, String[, String])>]
+    #   A list of files to check for updates
+    #   **in addition to those specified by the
+    #   {file:SASS_REFERENCE.md#template_location-option `:template_location` option}.**
+    #   The first string in each pair is the location of the Sass/SCSS file,
+    #   the second is the location of the CSS file that it should be compiled to.
+    #   The third string, if provided, is the location of the Sourcemap file.
+    def update_stylesheets(individual_files = [])
+      Sass::Plugin.checked_for_updates = true
+      staleness_checker = StalenessChecker.new(engine_options)
+
+      files = file_list(individual_files)
+      run_updating_stylesheets(files)
+
+      updated_stylesheets = []
+      files.each do |file, css, sourcemap|
+        # TODO: Does staleness_checker need to check the sourcemap file as well?
+        if options[:always_update] || staleness_checker.stylesheet_needs_update?(css, file)
+          # XXX For consistency, this should return the sourcemap too, but it would
+          # XXX be an API change.
+          updated_stylesheets << [file, css]
+          update_stylesheet(file, css, sourcemap)
+        else
+          run_not_updating_stylesheet(file, css, sourcemap)
+        end
+      end
+      run_updated_stylesheets(updated_stylesheets)
+    end
+
+    # Construct a list of files that might need to be compiled
+    # from the provided individual_files and the template_locations.
+    #
+    # Note: this method does not cache the results as they can change
+    # across invocations when sass files are added or removed.
+    #
+    # @param individual_files [Array<(String, String[, String])>]
+    #   A list of files to check for updates
+    #   **in addition to those specified by the
+    #   {file:SASS_REFERENCE.md#template_location-option `:template_location` option}.**
+    #   The first string in each pair is the location of the Sass/SCSS file,
+    #   the second is the location of the CSS file that it should be compiled to.
+    #   The third string, if provided, is the location of the Sourcemap file.
+    # @return [Array<(String, String, String)>]
+    #   A list of [sass_file, css_file, sourcemap_file] tuples similar
+    #   to what was passed in, but expanded to include the current state
+    #   of the directories being updated.
+    def file_list(individual_files = [])
+      files = individual_files.map do |tuple|
+        if engine_options[:sourcemap] == :none
+          tuple[0..1]
+        elsif tuple.size < 3
+          [tuple[0], tuple[1], Sass::Util.sourcemap_name(tuple[1])]
+        else
+          tuple.dup
+        end
+      end
+
+      template_location_array.each do |template_location, css_location|
+        Sass::Util.glob(File.join(template_location, "**", "[^_]*.s[ca]ss")).sort.each do |file|
+          # Get the relative path to the file
+          name = Sass::Util.relative_path_from(file, template_location).to_s
+          css = css_filename(name, css_location)
+          sourcemap = Sass::Util.sourcemap_name(css) unless engine_options[:sourcemap] == :none
+          files << [file, css, sourcemap]
+        end
+      end
+      files
+    end
+
+    # Watches the template directory (or directories)
+    # and updates the CSS files whenever the related Sass/SCSS files change.
+    # `watch` never returns.
+    #
+    # Whenever a change is detected to a Sass/SCSS file in
+    # {file:SASS_REFERENCE.md#template_location-option `:template_location`},
+    # the corresponding CSS file in {file:SASS_REFERENCE.md#css_location-option `:css_location`}
+    # will be recompiled.
+    # The CSS files of any Sass/SCSS files that import the changed file will also be recompiled.
+    #
+    # Before the watching starts in earnest, `watch` calls \{#update\_stylesheets}.
+    #
+    # Note that `watch` uses the [Listen](http://github.com/guard/listen) library
+    # to monitor the filesystem for changes.
+    # Listen isn't loaded until `watch` is run.
+    # The version of Listen distributed with Sass is loaded by default,
+    # but if another version has already been loaded that will be used instead.
+    #
+    # @param individual_files [Array<(String, String[, String])>]
+    #   A list of files to check for updates
+    #   **in addition to those specified by the
+    #   {file:SASS_REFERENCE.md#template_location-option `:template_location` option}.**
+    #   The first string in each pair is the location of the Sass/SCSS file,
+    #   the second is the location of the CSS file that it should be compiled to.
+    #   The third string, if provided, is the location of the Sourcemap file.
+    # @param options [Hash] The options that control how watching works.
+    # @option options [Boolean] :skip_initial_update
+    #   Don't do an initial update when starting the watcher when true
+    def watch(individual_files = [], options = {})
+      options, individual_files = individual_files, [] if individual_files.is_a?(Hash)
+      update_stylesheets(individual_files) unless options[:skip_initial_update]
+
+      directories = watched_paths
+      individual_files.each do |(source, _, _)|
+        source = File.expand_path(source)
+        @watched_files << Sass::Util.realpath(source).to_s
+        directories << File.dirname(source)
+      end
+      directories = remove_redundant_directories(directories)
+
+      # A Listen version prior to 2.0 will write a test file to a directory to
+      # see if a watcher supports watching that directory. That breaks horribly
+      # on read-only directories, so we filter those out.
+      unless Sass::Util.listen_geq_2?
+        directories = directories.select {|d| File.directory?(d) && File.writable?(d)}
+      end
+
+      # TODO: Keep better track of what depends on what
+      # so we don't have to run a global update every time anything changes.
+      # XXX The :additional_watch_paths option exists for Compass to use until
+      # a deprecated feature is removed. It may be removed without warning.
+      listener_args = directories +
+                      Array(options[:additional_watch_paths]) +
+                      [{:relative_paths => false}]
+
+      # The native windows listener is much slower than the polling option, according to
+      # https://github.com/nex3/sass/commit/a3031856b22bc834a5417dedecb038b7be9b9e3e
+      poll = @options[:poll] || Sass::Util.windows?
+      if poll && Sass::Util.listen_geq_2?
+        # In Listen 2.0.0 and on, :force_polling is an option. In earlier
+        # versions, it's a method on the listener (called below).
+        listener_args.last[:force_polling] = true
+      end
+
+      listener = create_listener(*listener_args) do |modified, added, removed|
+        on_file_changed(individual_files, modified, added, removed)
+        yield(modified, added, removed) if block_given?
+      end
+
+      if poll && !Sass::Util.listen_geq_2?
+        # In Listen 2.0.0 and on, :force_polling is an option (set above). In
+        # earlier versions, it's a method on the listener.
+        listener.force_polling(true)
+      end
+
+      listen_to(listener)
+    end
+
+    # Non-destructively modifies \{#options} so that default values are properly set,
+    # and returns the result.
+    #
+    # @param additional_options [{Symbol => Object}] An options hash with which to merge \{#options}
+    # @return [{Symbol => Object}] The modified options hash
+    def engine_options(additional_options = {})
+      opts = options.merge(additional_options)
+      opts[:load_paths] = load_paths(opts)
+      options[:sourcemap] = :auto if options[:sourcemap] == true
+      options[:sourcemap] = :none if options[:sourcemap] == false
+      opts
+    end
+
+    # Compass expects this to exist
+    def stylesheet_needs_update?(css_file, template_file)
+      StalenessChecker.stylesheet_needs_update?(css_file, template_file)
+    end
+
+    # Remove all output files that would be created by calling update_stylesheets, if they exist.
+    #
+    # This method runs the deleting_css and deleting_sourcemap callbacks for
+    # the files that are deleted.
+    #
+    # @param individual_files [Array<(String, String[, String])>]
+    #   A list of files to check for updates
+    #   **in addition to those specified by the
+    #   {file:SASS_REFERENCE.md#template_location-option `:template_location` option}.**
+    #   The first string in each pair is the location of the Sass/SCSS file,
+    #   the second is the location of the CSS file that it should be compiled to.
+    #   The third string, if provided, is the location of the Sourcemap file.
+    def clean(individual_files = [])
+      file_list(individual_files).each do |(_, css_file, sourcemap_file)|
+        if File.exist?(css_file)
+          run_deleting_css css_file
+          File.delete(css_file)
+        end
+        if sourcemap_file && File.exist?(sourcemap_file)
+          run_deleting_sourcemap sourcemap_file
+          File.delete(sourcemap_file)
+        end
+      end
+      nil
+    end
+
+    private
+
+    def create_listener(*args, &block)
+      Sass::Util.load_listen!
+      if Sass::Util.listen_geq_2?
+        # Work around guard/listen#243.
+        options = args.pop if args.last.is_a?(Hash)
+        args.map do |dir|
+          Listen.to(dir, options, &block)
+        end
+      else
+        Listen::Listener.new(*args, &block)
+      end
+    end
+
+    def listen_to(listener)
+      if Sass::Util.listen_geq_2?
+        listener.map {|l| l.start}
+        sleep
+      else
+        listener.start!
+      end
+    rescue Interrupt
+      # Squelch Interrupt for clean exit from Listen::Listener
+    end
+
+    def remove_redundant_directories(directories)
+      dedupped = []
+      directories.each do |new_directory|
+        # no need to add a directory that is already watched.
+        next if dedupped.any? do |existing_directory|
+          child_of_directory?(existing_directory, new_directory)
+        end
+        # get rid of any sub directories of this new directory
+        dedupped.reject! do |existing_directory|
+          child_of_directory?(new_directory, existing_directory)
+        end
+        dedupped << new_directory
+      end
+      dedupped
+    end
+
+    def on_file_changed(individual_files, modified, added, removed)
+      recompile_required = false
+
+      modified.uniq.each do |f|
+        next unless watched_file?(f)
+        recompile_required = true
+        run_template_modified(relative_to_pwd(f))
+      end
+
+      added.uniq.each do |f|
+        next unless watched_file?(f)
+        recompile_required = true
+        run_template_created(relative_to_pwd(f))
+      end
+
+      removed.uniq.each do |f|
+        next unless watched_file?(f)
+        run_template_deleted(relative_to_pwd(f))
+        if (files = individual_files.find {|(source, _, _)| File.expand_path(source) == f})
+          recompile_required = true
+          # This was a file we were watching explicitly and compiling to a particular location.
+          # Delete the corresponding file.
+          try_delete_css files[1]
+        else
+          next unless watched_file?(f)
+          recompile_required = true
+          # Look for the sass directory that contained the sass file
+          # And try to remove the css file that corresponds to it
+          template_location_array.each do |(sass_dir, css_dir)|
+            sass_dir = File.expand_path(sass_dir)
+            if child_of_directory?(sass_dir, f)
+              remainder = f[(sass_dir.size + 1)..-1]
+              try_delete_css(css_filename(remainder, css_dir))
+              break
+            end
+          end
+        end
+      end
+
+      if recompile_required
+        # In case a file we're watching is removed and then recreated we
+        # prune out the non-existant files here.
+        watched_files_remaining = individual_files.select {|(source, _, _)| File.exist?(source)}
+        update_stylesheets(watched_files_remaining)
+      end
+    end
+
+    def update_stylesheet(filename, css, sourcemap)
+      dir = File.dirname(css)
+      unless File.exist?(dir)
+        run_creating_directory dir
+        FileUtils.mkdir_p dir
+      end
+
+      begin
+        File.read(filename) unless File.readable?(filename) # triggers an error for handling
+        engine_opts = engine_options(:css_filename => css,
+                                     :filename => filename,
+                                     :sourcemap_filename => sourcemap)
+        mapping = nil
+        run_compilation_starting(filename, css, sourcemap)
+        engine = Sass::Engine.for_file(filename, engine_opts)
+        if sourcemap
+          rendered, mapping = engine.render_with_sourcemap(File.basename(sourcemap))
+        else
+          rendered = engine.render
+        end
+      rescue StandardError => e
+        compilation_error_occured = true
+        run_compilation_error e, filename, css, sourcemap
+        raise e unless options[:full_exception]
+        rendered = Sass::SyntaxError.exception_to_css(e, options[:line] || 1)
+      end
+
+      write_file(css, rendered)
+      if mapping
+        write_file(sourcemap, mapping.to_json(
+            :css_path => css, :sourcemap_path => sourcemap, :type => options[:sourcemap]))
+      end
+      run_updated_stylesheet(filename, css, sourcemap) unless compilation_error_occured
+    end
+
+    def write_file(fileName, content)
+      flag = 'w'
+      flag = 'wb' if Sass::Util.windows? && options[:unix_newlines]
+      File.open(fileName, flag) do |file|
+        file.set_encoding(content.encoding) unless Sass::Util.ruby1_8?
+        file.print(content)
+      end
+    end
+
+    def try_delete_css(css)
+      if File.exist?(css)
+        run_deleting_css css
+        File.delete css
+      end
+      map = Sass::Util.sourcemap_name(css)
+      if File.exist?(map)
+        run_deleting_sourcemap map
+        File.delete map
+      end
+    end
+
+    def watched_file?(file)
+      @watched_files.include?(file) || normalized_load_paths.any? {|lp| lp.watched_file?(file)}
+    end
+
+    def watched_paths
+      @watched_paths ||= normalized_load_paths.map {|lp| lp.directories_to_watch}.compact.flatten
+    end
+
+    def normalized_load_paths
+      @normalized_load_paths ||=
+        Sass::Engine.normalize_options(:load_paths => load_paths)[:load_paths]
+    end
+
+    def load_paths(opts = options)
+      (opts[:load_paths] || []) + template_locations
+    end
+
+    def template_locations
+      template_location_array.to_a.map {|l| l.first}
+    end
+
+    def css_locations
+      template_location_array.to_a.map {|l| l.last}
+    end
+
+    def css_filename(name, path)
+      "#{path}#{File::SEPARATOR unless path.end_with?(File::SEPARATOR)}#{name}".
+        gsub(/\.s[ac]ss$/, '.css')
+    end
+
+    def relative_to_pwd(f)
+      Sass::Util.relative_path_from(f, Dir.pwd).to_s
+    rescue ArgumentError # when a relative path cannot be computed
+      f
+    end
+
+    def child_of_directory?(parent, child)
+      parent_dir = parent.end_with?(File::SEPARATOR) ? parent : (parent + File::SEPARATOR)
+      child.start_with?(parent_dir) || parent == child
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/plugin/configuration.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/plugin/configuration.rb
new file mode 100644
index 0000000..b78c3ad
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/plugin/configuration.rb
@@ -0,0 +1,118 @@
+module Sass
+  module Plugin
+    # We keep configuration in its own self-contained file
+    # so that we can load it independently in Rails 3,
+    # where the full plugin stuff is lazy-loaded.
+    module Configuration
+      # Returns the default options for a {Sass::Plugin::Compiler}.
+      #
+      # @return [{Symbol => Object}]
+      def default_options
+        @default_options ||= {
+          :css_location       => './public/stylesheets',
+          :always_update      => false,
+          :always_check       => true,
+          :full_exception     => true,
+          :cache_location     => ".sass-cache"
+        }.freeze
+      end
+
+      # Resets the options and
+      # {Sass::Callbacks::InstanceMethods#clear_callbacks! clears all callbacks}.
+      def reset!
+        @options = nil
+        clear_callbacks!
+      end
+
+      # An options hash.
+      # See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
+      #
+      # @return [{Symbol => Object}]
+      def options
+        @options ||= default_options.dup
+      end
+
+      # Adds a new template-location/css-location mapping.
+      # This means that Sass/SCSS files in `template_location`
+      # will be compiled to CSS files in `css_location`.
+      #
+      # This is preferred over manually manipulating the
+      # {file:SASS_REFERENCE.md#template_location-option `:template_location` option}
+      # since the option can be in multiple formats.
+      #
+      # Note that this method will change `options[:template_location]`
+      # to be in the Array format.
+      # This means that even if `options[:template_location]`
+      # had previously been a Hash or a String,
+      # it will now be an Array.
+      #
+      # @param template_location [String] The location where Sass/SCSS files will be.
+      # @param css_location [String] The location where compiled CSS files will go.
+      def add_template_location(template_location, css_location = options[:css_location])
+        normalize_template_location!
+        template_location_array << [template_location, css_location]
+      end
+
+      # Removes a template-location/css-location mapping.
+      # This means that Sass/SCSS files in `template_location`
+      # will no longer be compiled to CSS files in `css_location`.
+      #
+      # This is preferred over manually manipulating the
+      # {file:SASS_REFERENCE.md#template_location-option `:template_location` option}
+      # since the option can be in multiple formats.
+      #
+      # Note that this method will change `options[:template_location]`
+      # to be in the Array format.
+      # This means that even if `options[:template_location]`
+      # had previously been a Hash or a String,
+      # it will now be an Array.
+      #
+      # @param template_location [String]
+      #   The location where Sass/SCSS files were,
+      #   which is now going to be ignored.
+      # @param css_location [String]
+      #   The location where compiled CSS files went, but will no longer go.
+      # @return [Boolean]
+      #   Non-`nil` if the given mapping already existed and was removed,
+      #   or `nil` if nothing was changed.
+      def remove_template_location(template_location, css_location = options[:css_location])
+        normalize_template_location!
+        template_location_array.delete([template_location, css_location])
+      end
+
+      # Returns the template locations configured for Sass
+      # as an array of `[template_location, css_location]` pairs.
+      # See the {file:SASS_REFERENCE.md#template_location-option `:template_location` option}
+      # for details.
+      #
+      # @return [Array<(String, String)>]
+      #   An array of `[template_location, css_location]` pairs.
+      def template_location_array
+        old_template_location = options[:template_location]
+        normalize_template_location!
+        options[:template_location]
+      ensure
+        options[:template_location] = old_template_location
+      end
+
+      private
+
+      def normalize_template_location!
+        return if options[:template_location].is_a?(Array)
+        options[:template_location] =
+          case options[:template_location]
+          when nil
+            if options[:css_location]
+              [[File.join(options[:css_location], 'sass'), options[:css_location]]]
+            else
+              []
+            end
+          when String
+            [[options[:template_location], options[:css_location]]]
+          else
+            options[:template_location].to_a
+          end
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.2.12/lib/sass/plugin/generic.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/plugin/generic.rb
similarity index 100%
rename from backends/css/gems/sass-3.2.12/lib/sass/plugin/generic.rb
rename to backends/css/gems/sass-3.4.9/lib/sass/plugin/generic.rb
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/plugin/merb.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/plugin/merb.rb
new file mode 100644
index 0000000..074fd4e
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/plugin/merb.rb
@@ -0,0 +1,48 @@
+unless defined?(Sass::MERB_LOADED)
+  Sass::MERB_LOADED = true
+
+  module Sass::Plugin::Configuration
+    # Different default options in a m envirionment.
+    def default_options
+      @default_options ||= begin
+        version = Merb::VERSION.split('.').map {|n| n.to_i}
+        if version[0] <= 0 && version[1] < 5
+          root = MERB_ROOT
+          env  = MERB_ENV
+        else
+          root = Merb.root.to_s
+          env  = Merb.environment
+        end
+
+        {
+          :always_update      => false,
+          :template_location => root + '/public/stylesheets/sass',
+          :css_location      => root + '/public/stylesheets',
+          :cache_location    => root + '/tmp/sass-cache',
+          :always_check      => env != "production",
+          :quiet             => env != "production",
+          :full_exception    => env != "production"
+        }.freeze
+      end
+    end
+  end
+
+  config = Merb::Plugins.config[:sass] || Merb::Plugins.config["sass"] || {}
+
+  if defined? config.symbolize_keys!
+    config.symbolize_keys!
+  end
+
+  Sass::Plugin.options.merge!(config)
+
+  require 'sass/plugin/rack'
+  class Sass::Plugin::MerbBootLoader < Merb::BootLoader
+    after Merb::BootLoader::RackUpApplication
+
+    def self.run
+      # Apparently there's no better way than this to add Sass
+      # to Merb's Rack stack.
+      Merb::Config[:app] = Sass::Plugin::Rack.new(Merb::Config[:app])
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.2.12/lib/sass/plugin/rack.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/plugin/rack.rb
similarity index 100%
rename from backends/css/gems/sass-3.2.12/lib/sass/plugin/rack.rb
rename to backends/css/gems/sass-3.4.9/lib/sass/plugin/rack.rb
diff --git a/backends/css/gems/sass-3.2.12/lib/sass/plugin/rails.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/plugin/rails.rb
similarity index 100%
rename from backends/css/gems/sass-3.2.12/lib/sass/plugin/rails.rb
rename to backends/css/gems/sass-3.4.9/lib/sass/plugin/rails.rb
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/plugin/staleness_checker.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/plugin/staleness_checker.rb
new file mode 100644
index 0000000..23a9bf2
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/plugin/staleness_checker.rb
@@ -0,0 +1,199 @@
+require 'thread'
+
+module Sass
+  module Plugin
+    # The class handles `.s[ca]ss` file staleness checks via their mtime timestamps.
+    #
+    # To speed things up two level of caches are employed:
+    #
+    # * A class-level dependency cache which stores @import paths for each file.
+    #   This is a long-lived cache that is reused by every StalenessChecker instance.
+    # * Three short-lived instance-level caches, one for file mtimes,
+    #   one for whether a file is stale during this particular run.
+    #   and one for the parse tree for a file.
+    #   These are only used by a single StalenessChecker instance.
+    #
+    # Usage:
+    #
+    # * For a one-off staleness check of a single `.s[ca]ss` file,
+    #   the class-level {stylesheet_needs_update?} method
+    #   should be used.
+    # * For a series of staleness checks (e.g. checking all files for staleness)
+    #   a StalenessChecker instance should be created,
+    #   and the instance-level \{#stylesheet\_needs\_update?} method should be used.
+    #   the caches should make the whole process significantly faster.
+    #   *WARNING*: It is important not to retain the instance for too long,
+    #   as its instance-level caches are never explicitly expired.
+    class StalenessChecker
+      @dependencies_cache = {}
+      @dependency_cache_mutex = Mutex.new
+
+      class << self
+        # TODO: attach this to a compiler instance.
+        # @private
+        attr_accessor :dependencies_cache
+        attr_reader :dependency_cache_mutex
+      end
+
+      # Creates a new StalenessChecker
+      # for checking the staleness of several stylesheets at once.
+      #
+      # @param options [{Symbol => Object}]
+      #   See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
+      def initialize(options)
+        # URIs that are being actively checked for staleness. Protects against
+        # import loops.
+        @actively_checking = Set.new
+
+        # Entries in the following instance-level caches are never explicitly expired.
+        # Instead they are supposed to automatically go out of scope when a series of staleness
+        # checks (this instance of StalenessChecker was created for) is finished.
+        @mtimes, @dependencies_stale, @parse_trees = {}, {}, {}
+        @options = Sass::Engine.normalize_options(options)
+      end
+
+      # Returns whether or not a given CSS file is out of date
+      # and needs to be regenerated.
+      #
+      # @param css_file [String] The location of the CSS file to check.
+      # @param template_file [String] The location of the Sass or SCSS template
+      #   that is compiled to `css_file`.
+      # @return [Boolean] Whether the stylesheet needs to be updated.
+      def stylesheet_needs_update?(css_file, template_file, importer = nil)
+        template_file = File.expand_path(template_file)
+        begin
+          css_mtime = File.mtime(css_file)
+        rescue Errno::ENOENT
+          return true
+        end
+        stylesheet_modified_since?(template_file, css_mtime, importer)
+      end
+
+      # Returns whether a Sass or SCSS stylesheet has been modified since a given time.
+      #
+      # @param template_file [String] The location of the Sass or SCSS template.
+      # @param mtime [Fixnum] The modification time to check against.
+      # @param importer [Sass::Importers::Base] The importer used to locate the stylesheet.
+      #   Defaults to the filesystem importer.
+      # @return [Boolean] Whether the stylesheet has been modified.
+      def stylesheet_modified_since?(template_file, mtime, importer = nil)
+        importer ||= @options[:filesystem_importer].new(".")
+        dependency_updated?(mtime).call(template_file, importer)
+      end
+
+      # Returns whether or not a given CSS file is out of date
+      # and needs to be regenerated.
+      #
+      # The distinction between this method and the instance-level \{#stylesheet\_needs\_update?}
+      # is that the instance method preserves mtime and stale-dependency caches,
+      # so it's better to use when checking multiple stylesheets at once.
+      #
+      # @param css_file [String] The location of the CSS file to check.
+      # @param template_file [String] The location of the Sass or SCSS template
+      #   that is compiled to `css_file`.
+      # @return [Boolean] Whether the stylesheet needs to be updated.
+      def self.stylesheet_needs_update?(css_file, template_file, importer = nil)
+        new(Plugin.engine_options).stylesheet_needs_update?(css_file, template_file, importer)
+      end
+
+      # Returns whether a Sass or SCSS stylesheet has been modified since a given time.
+      #
+      # The distinction between this method and the instance-level \{#stylesheet\_modified\_since?}
+      # is that the instance method preserves mtime and stale-dependency caches,
+      # so it's better to use when checking multiple stylesheets at once.
+      #
+      # @param template_file [String] The location of the Sass or SCSS template.
+      # @param mtime [Fixnum] The modification time to check against.
+      # @param importer [Sass::Importers::Base] The importer used to locate the stylesheet.
+      #   Defaults to the filesystem importer.
+      # @return [Boolean] Whether the stylesheet has been modified.
+      def self.stylesheet_modified_since?(template_file, mtime, importer = nil)
+        new(Plugin.engine_options).stylesheet_modified_since?(template_file, mtime, importer)
+      end
+
+      private
+
+      def dependencies_stale?(uri, importer, css_mtime)
+        timestamps = @dependencies_stale[[uri, importer]] ||= {}
+        timestamps.each_pair do |checked_css_mtime, is_stale|
+          if checked_css_mtime <= css_mtime && !is_stale
+            return false
+          elsif checked_css_mtime > css_mtime && is_stale
+            return true
+          end
+        end
+        timestamps[css_mtime] = dependencies(uri, importer).any?(&dependency_updated?(css_mtime))
+      rescue Sass::SyntaxError
+        # If there's an error finding dependencies, default to recompiling.
+        true
+      end
+
+      def mtime(uri, importer)
+        @mtimes[[uri, importer]] ||=
+          begin
+            mtime = importer.mtime(uri, @options)
+            if mtime.nil?
+              with_dependency_cache {|cache| cache.delete([uri, importer])}
+              nil
+            else
+              mtime
+            end
+          end
+      end
+
+      def dependencies(uri, importer)
+        stored_mtime, dependencies =
+          with_dependency_cache {|cache| Sass::Util.destructure(cache[[uri, importer]])}
+
+        if !stored_mtime || stored_mtime < mtime(uri, importer)
+          dependencies = compute_dependencies(uri, importer)
+          with_dependency_cache do |cache|
+            cache[[uri, importer]] = [mtime(uri, importer), dependencies]
+          end
+        end
+
+        dependencies
+      end
+
+      def dependency_updated?(css_mtime)
+        proc do |uri, importer|
+          next true if @actively_checking.include?(uri)
+          begin
+            @actively_checking << uri
+            sass_mtime = mtime(uri, importer)
+            !sass_mtime ||
+              sass_mtime > css_mtime ||
+              dependencies_stale?(uri, importer, css_mtime)
+          ensure
+            @actively_checking.delete uri
+          end
+        end
+      end
+
+      def compute_dependencies(uri, importer)
+        tree(uri, importer).grep(Tree::ImportNode) do |n|
+          next if n.css_import?
+          file = n.imported_file
+          key = [file.options[:filename], file.options[:importer]]
+          @parse_trees[key] = file.to_tree
+          key
+        end.compact
+      end
+
+      def tree(uri, importer)
+        @parse_trees[[uri, importer]] ||= importer.find(uri, @options).to_tree
+      end
+
+      # Get access to the global dependency cache in a threadsafe manner.
+      # Inside the block, no other thread can access the dependency cache.
+      #
+      # @yieldparam cache [Hash] The hash that is the global dependency cache
+      # @return The value returned by the block to which this method yields
+      def with_dependency_cache
+        StalenessChecker.dependency_cache_mutex.synchronize do
+          yield StalenessChecker.dependencies_cache
+        end
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/railtie.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/railtie.rb
new file mode 100644
index 0000000..cf900b5
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/railtie.rb
@@ -0,0 +1,10 @@
+# Rails 3.0.0.beta.2+, < 3.1
+if defined?(ActiveSupport) && Sass::Util.has?(:public_method, ActiveSupport, :on_load) &&
+    !Sass::Util.ap_geq?('3.1.0.beta')
+  require 'sass/plugin/configuration'
+  ActiveSupport.on_load(:before_configuration) do
+    require 'sass'
+    require 'sass/plugin'
+    require 'sass/plugin/rails'
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/repl.rb b/backends/css/gems/sass-3.4.9/lib/sass/repl.rb
new file mode 100644
index 0000000..e9b9e6c
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/repl.rb
@@ -0,0 +1,57 @@
+require 'readline'
+
+module Sass
+  # Runs a SassScript read-eval-print loop.
+  # It presents a prompt on the terminal,
+  # reads in SassScript expressions,
+  # evaluates them,
+  # and prints the result.
+  class Repl
+    # @param options [{Symbol => Object}] An options hash.
+    def initialize(options = {})
+      @options = options
+    end
+
+    # Starts the read-eval-print loop.
+    def run
+      environment = Environment.new
+      @line = 0
+      loop do
+        @line += 1
+        unless (text = Readline.readline('>> '))
+          puts
+          return
+        end
+
+        Readline::HISTORY << text
+        parse_input(environment, text)
+      end
+    end
+
+    private
+
+    def parse_input(environment, text)
+      case text
+      when Script::MATCH
+        name = $1
+        guarded = !!$3
+        val = Script::Parser.parse($2, @line, text.size - ($3 || '').size - $2.size)
+
+        unless guarded && environment.var(name)
+          environment.set_var(name, val.perform(environment))
+        end
+
+        p environment.var(name)
+      else
+        p Script::Parser.parse(text, @line, 0).perform(environment)
+      end
+    rescue Sass::SyntaxError => e
+      puts "SyntaxError: #{e.message}"
+      if @options[:trace]
+        e.backtrace.each do |line|
+          puts "\tfrom #{line}"
+        end
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.2.12/lib/sass/root.rb b/backends/css/gems/sass-3.4.9/lib/sass/root.rb
similarity index 100%
rename from backends/css/gems/sass-3.2.12/lib/sass/root.rb
rename to backends/css/gems/sass-3.4.9/lib/sass/root.rb
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script.rb b/backends/css/gems/sass-3.4.9/lib/sass/script.rb
new file mode 100644
index 0000000..5ca639d
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script.rb
@@ -0,0 +1,66 @@
+require 'sass/scss/rx'
+
+module Sass
+  # SassScript is code that's embedded in Sass documents
+  # to allow for property values to be computed from variables.
+  #
+  # This module contains code that handles the parsing and evaluation of SassScript.
+  module Script
+    # The regular expression used to parse variables.
+    MATCH = /^\$(#{Sass::SCSS::RX::IDENT})\s*:\s*(.+?)
+      (!#{Sass::SCSS::RX::IDENT}(?:\s+!#{Sass::SCSS::RX::IDENT})*)?$/x
+
+    # The regular expression used to validate variables without matching.
+    VALIDATE = /^\$#{Sass::SCSS::RX::IDENT}$/
+
+    # Parses a string of SassScript
+    #
+    # @param value [String] The SassScript
+    # @param line [Fixnum] The number of the line on which the SassScript appeared.
+    #   Used for error reporting
+    # @param offset [Fixnum] The number of characters in on `line` that the SassScript started.
+    #   Used for error reporting
+    # @param options [{Symbol => Object}] An options hash;
+    #   see {file:SASS_REFERENCE.md#sass_options the Sass options documentation}
+    # @return [Script::Tree::Node] The root node of the parse tree
+    def self.parse(value, line, offset, options = {})
+      Parser.parse(value, line, offset, options)
+    rescue Sass::SyntaxError => e
+      e.message << ": #{value.inspect}." if e.message == "SassScript error"
+      e.modify_backtrace(:line => line, :filename => options[:filename])
+      raise e
+    end
+
+    require 'sass/script/functions'
+    require 'sass/script/parser'
+    require 'sass/script/tree'
+    require 'sass/script/value'
+
+    # @private
+    CONST_RENAMES = {
+      :Literal => Sass::Script::Value::Base,
+      :ArgList => Sass::Script::Value::ArgList,
+      :Bool => Sass::Script::Value::Bool,
+      :Color => Sass::Script::Value::Color,
+      :List => Sass::Script::Value::List,
+      :Null => Sass::Script::Value::Null,
+      :Number => Sass::Script::Value::Number,
+      :String => Sass::Script::Value::String,
+      :Node => Sass::Script::Tree::Node,
+      :Funcall => Sass::Script::Tree::Funcall,
+      :Interpolation => Sass::Script::Tree::Interpolation,
+      :Operation => Sass::Script::Tree::Operation,
+      :StringInterpolation => Sass::Script::Tree::StringInterpolation,
+      :UnaryOperation => Sass::Script::Tree::UnaryOperation,
+      :Variable => Sass::Script::Tree::Variable,
+    }
+
+    # @private
+    def self.const_missing(name)
+      klass = CONST_RENAMES[name]
+      super unless klass
+      CONST_RENAMES.each {|n, k| const_set(n, k)}
+      klass
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/css_lexer.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/css_lexer.rb
new file mode 100644
index 0000000..6362a9d
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/css_lexer.rb
@@ -0,0 +1,33 @@
+module Sass
+  module Script
+    # This is a subclass of {Lexer} for use in parsing plain CSS properties.
+    #
+    # @see Sass::SCSS::CssParser
+    class CssLexer < Lexer
+      private
+
+      def token
+        important || super
+      end
+
+      def string(re, *args)
+        if re == :uri
+          uri = scan(URI)
+          return unless uri
+          return [:string, Script::Value::String.new(uri)]
+        end
+
+        return unless scan(STRING)
+        string_value = Sass::Script::Value::String.value(@scanner[1] || @scanner[2])
+        value = Script::Value::String.new(string_value, :string)
+        [:string, value]
+      end
+
+      def important
+        s = scan(IMPORTANT)
+        return unless s
+        [:raw, s]
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/css_parser.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/css_parser.rb
new file mode 100644
index 0000000..4399493
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/css_parser.rb
@@ -0,0 +1,34 @@
+require 'sass/script'
+require 'sass/script/css_lexer'
+
+module Sass
+  module Script
+    # This is a subclass of {Parser} for use in parsing plain CSS properties.
+    #
+    # @see Sass::SCSS::CssParser
+    class CssParser < Parser
+      private
+
+      # @private
+      def lexer_class; CssLexer; end
+
+      # We need a production that only does /,
+      # since * and % aren't allowed in plain CSS
+      production :div, :unary_plus, :div
+
+      def string
+        tok = try_tok(:string)
+        return number unless tok
+        unless @lexer.peek && @lexer.peek.type == :begin_interpolation
+          return literal_node(tok.value, tok.source_range)
+        end
+      end
+
+      # Short-circuit all the SassScript-only productions
+      alias_method :interpolation, :space
+      alias_method :or_expr, :div
+      alias_method :unary_div, :ident
+      alias_method :paren, :string
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/functions.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/functions.rb
new file mode 100644
index 0000000..11249d6
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/functions.rb
@@ -0,0 +1,2646 @@
+require 'sass/script/value/helpers'
+
+module Sass::Script
+  # @comment
+  #   YARD can't handle some multiline tags, and we need really long tags for function declarations.
+  #   rubocop:disable LineLength
+  # Methods in this module are accessible from the SassScript context.
+  # For example, you can write
+  #
+  #     $color: hsl(120deg, 100%, 50%)
+  #
+  # and it will call {Functions#hsl}.
+  #
+  # The following functions are provided:
+  #
+  # *Note: These functions are described in more detail below.*
+  #
+  # ## RGB Functions
+  #
+  # \{#rgb rgb($red, $green, $blue)}
+  # : Creates a {Sass::Script::Value::Color Color} from red, green, and blue
+  #   values.
+  #
+  # \{#rgba rgba($red, $green, $blue, $alpha)}
+  # : Creates a {Sass::Script::Value::Color Color} from red, green, blue, and
+  #   alpha values.
+  #
+  # \{#red red($color)}
+  # : Gets the red component of a color.
+  #
+  # \{#green green($color)}
+  # : Gets the green component of a color.
+  #
+  # \{#blue blue($color)}
+  # : Gets the blue component of a color.
+  #
+  # \{#mix mix($color1, $color2, \[$weight\])}
+  # : Mixes two colors together.
+  #
+  # ## HSL Functions
+  #
+  # \{#hsl hsl($hue, $saturation, $lightness)}
+  # : Creates a {Sass::Script::Value::Color Color} from hue, saturation, and
+  #   lightness values.
+  #
+  # \{#hsla hsla($hue, $saturation, $lightness, $alpha)}
+  # : Creates a {Sass::Script::Value::Color Color} from hue, saturation,
+  #   lightness, and alpha values.
+  #
+  # \{#hue hue($color)}
+  # : Gets the hue component of a color.
+  #
+  # \{#saturation saturation($color)}
+  # : Gets the saturation component of a color.
+  #
+  # \{#lightness lightness($color)}
+  # : Gets the lightness component of a color.
+  #
+  # \{#adjust_hue adjust-hue($color, $degrees)}
+  # : Changes the hue of a color.
+  #
+  # \{#lighten lighten($color, $amount)}
+  # : Makes a color lighter.
+  #
+  # \{#darken darken($color, $amount)}
+  # : Makes a color darker.
+  #
+  # \{#saturate saturate($color, $amount)}
+  # : Makes a color more saturated.
+  #
+  # \{#desaturate desaturate($color, $amount)}
+  # : Makes a color less saturated.
+  #
+  # \{#grayscale grayscale($color)}
+  # : Converts a color to grayscale.
+  #
+  # \{#complement complement($color)}
+  # : Returns the complement of a color.
+  #
+  # \{#invert invert($color)}
+  # : Returns the inverse of a color.
+  #
+  # ## Opacity Functions
+  #
+  # \{#alpha alpha($color)} / \{#opacity opacity($color)}
+  # : Gets the alpha component (opacity) of a color.
+  #
+  # \{#rgba rgba($color, $alpha)}
+  # : Changes the alpha component for a color.
+  #
+  # \{#opacify opacify($color, $amount)} / \{#fade_in fade-in($color, $amount)}
+  # : Makes a color more opaque.
+  #
+  # \{#transparentize transparentize($color, $amount)} / \{#fade_out fade-out($color, $amount)}
+  # : Makes a color more transparent.
+  #
+  # ## Other Color Functions
+  #
+  # \{#adjust_color adjust-color($color, \[$red\], \[$green\], \[$blue\], \[$hue\], \[$saturation\], 
\[$lightness\], \[$alpha\])}
+  # : Increases or decreases one or more components of a color.
+  #
+  # \{#scale_color scale-color($color, \[$red\], \[$green\], \[$blue\], \[$saturation\], \[$lightness\], 
\[$alpha\])}
+  # : Fluidly scales one or more properties of a color.
+  #
+  # \{#change_color change-color($color, \[$red\], \[$green\], \[$blue\], \[$hue\], \[$saturation\], 
\[$lightness\], \[$alpha\])}
+  # : Changes one or more properties of a color.
+  #
+  # \{#ie_hex_str ie-hex-str($color)}
+  # : Converts a color into the format understood by IE filters.
+  #
+  # ## String Functions
+  #
+  # \{#unquote unquote($string)}
+  # : Removes quotes from a string.
+  #
+  # \{#quote quote($string)}
+  # : Adds quotes to a string.
+  #
+  # \{#str_length str-length($string)}
+  # : Returns the number of characters in a string.
+  #
+  # \{#str_insert str-insert($string, $insert, $index)}
+  # : Inserts `$insert` into `$string` at `$index`.
+  #
+  # \{#str_index str-index($string, $substring)}
+  # : Returns the index of the first occurance of `$substring` in `$string`.
+  #
+  # \{#str_slice str-slice($string, $start-at, [$end-at])}
+  # : Extracts a substring from `$string`.
+  #
+  # \{#to_upper_case to-upper-case($string)}
+  # : Converts a string to upper case.
+  #
+  # \{#to_lower_case to-lower-case($string)}
+  # : Converts a string to lower case.
+  #
+  # ## Number Functions
+  #
+  # \{#percentage percentage($number)}
+  # : Converts a unitless number to a percentage.
+  #
+  # \{#round round($number)}
+  # : Rounds a number to the nearest whole number.
+  #
+  # \{#ceil ceil($number)}
+  # : Rounds a number up to the next whole number.
+  #
+  # \{#floor floor($number)}
+  # : Rounds a number down to the previous whole number.
+  #
+  # \{#abs abs($number)}
+  # : Returns the absolute value of a number.
+  #
+  # \{#min min($numbers...)\}
+  # : Finds the minimum of several numbers.
+  #
+  # \{#max max($numbers...)\}
+  # : Finds the maximum of several numbers.
+  #
+  # \{#random random([$limit])\}
+  # : Returns a random number.
+  #
+  # ## List Functions {#list-functions}
+  #
+  # All list functions work for maps as well, treating them as lists of pairs.
+  #
+  # \{#length length($list)}
+  # : Returns the length of a list.
+  #
+  # \{#nth nth($list, $n)}
+  # : Returns a specific item in a list.
+  #
+  # \{#set-nth set-nth($list, $n, $value)}
+  # : Replaces the nth item in a list.
+  #
+  # \{#join join($list1, $list2, \[$separator\])}
+  # : Joins together two lists into one.
+  #
+  # \{#append append($list1, $val, \[$separator\])}
+  # : Appends a single value onto the end of a list.
+  #
+  # \{#zip zip($lists...)}
+  # : Combines several lists into a single multidimensional list.
+  #
+  # \{#index index($list, $value)}
+  # : Returns the position of a value within a list.
+  #
+  # \{#list_separator list-separator(#list)}
+  # : Returns the separator of a list.
+  #
+  # ## Map Functions {#map-functions}
+  #
+  # \{#map_get map-get($map, $key)}
+  # : Returns the value in a map associated with a given key.
+  #
+  # \{#map_merge map-merge($map1, $map2)}
+  # : Merges two maps together into a new map.
+  #
+  # \{#map_remove map-remove($map, $keys...)}
+  # : Returns a new map with keys removed.
+  #
+  # \{#map_keys map-keys($map)}
+  # : Returns a list of all keys in a map.
+  #
+  # \{#map_values map-values($map)}
+  # : Returns a list of all values in a map.
+  #
+  # \{#map_has_key map-has-key($map, $key)}
+  # : Returns whether a map has a value associated with a given key.
+  #
+  # \{#keywords keywords($args)}
+  # : Returns the keywords passed to a function that takes variable arguments.
+  #
+  # ## Selector Functions
+  #
+  # Selector functions are very liberal in the formats they support
+  # for selector arguments. They can take a plain string, a list of
+  # lists as returned by `&` or anything in between:
+  #
+  # * A plain sring, such as `".foo .bar, .baz .bang"`.
+  # * A space-separated list of strings such as `(".foo" ".bar")`.
+  # * A comma-separated list of strings such as `(".foo .bar", ".baz .bang")`.
+  # * A comma-separated list of space-separated lists of strings such
+  #   as `((".foo" ".bar"), (".baz" ".bang"))`.
+  #
+  # In general, selector functions allow placeholder selectors
+  # (`%foo`) but disallow parent-reference selectors (`&`).
+  #
+  # \{#selector_nest selector-nest($selectors...)}
+  # : Nests selector beneath one another like they would be nested in the
+  #   stylesheet.
+  #
+  # \{#selector_append selector-append($selectors...)}
+  # : Appends selectors to one another without spaces in between.
+  #
+  # \{#selector_extend selector-extend($selector, $extendee, $extender)}
+  # : Extends `$extendee` with `$extender` within `$selector`.
+  #
+  # \{#selector_replace selector-replace($selector, $original, $replacement)}
+  # : Replaces `$original` with `$replacement` within `$selector`.
+  #
+  # \{#selector_unify selector-unify($selector1, $selector2)}
+  # : Unifies two selectors to produce a selector that matches
+  #   elements matched by both.
+  #
+  # \{#is_superselector is-superselector($super, $sub)}
+  # : Returns whether `$super` matches all the elements `$sub` does, and
+  #   possibly more.
+  #
+  # \{#simple_selectors simple-selectors($selector)}
+  # : Returns the simple selectors that comprise a compound selector.
+  #
+  # \{#selector_parse selector-parse($selector)}
+  # : Parses a selector into the format returned by `&`.
+  #
+  # ## Introspection Functions
+  #
+  # \{#feature_exists feature-exists($feature)}
+  # : Returns whether a feature exists in the current Sass runtime.
+  #
+  # \{#variable_exists variable-exists($name)}
+  # : Returns whether a variable with the given name exists in the current scope.
+  #
+  # \{#global_variable_exists global-variable-exists($name)}
+  # : Returns whether a variable with the given name exists in the global scope.
+  #
+  # \{#function_exists function-exists($name)}
+  # : Returns whether a function with the given name exists.
+  #
+  # \{#mixin_exists mixin-exists($name)}
+  # : Returns whether a mixin with the given name exists.
+  #
+  # \{#inspect inspect($value)}
+  # : Returns the string representation of a value as it would be represented in Sass.
+  #
+  # \{#type_of type-of($value)}
+  # : Returns the type of a value.
+  #
+  # \{#unit unit($number)}
+  # : Returns the unit(s) associated with a number.
+  #
+  # \{#unitless unitless($number)}
+  # : Returns whether a number has units.
+  #
+  # \{#comparable comparable($number1, $number2)}
+  # : Returns whether two numbers can be added, subtracted, or compared.
+  #
+  # \{#call call($name, $args...)}
+  # : Dynamically calls a Sass function.
+  #
+  # ## Miscellaneous Functions
+  #
+  # \{#if if($condition, $if-true, $if-false)}
+  # : Returns one of two values, depending on whether or not `$condition` is
+  #   true.
+  #
+  # \{#unique_id unique-id()}
+  # : Returns a unique CSS identifier.
+  #
+  # ## Adding Custom Functions
+  #
+  # New Sass functions can be added by adding Ruby methods to this module.
+  # For example:
+  #
+  #     module Sass::Script::Functions
+  #       def reverse(string)
+  #         assert_type string, :String
+  #         Sass::Script::Value::String.new(string.value.reverse)
+  #       end
+  #       declare :reverse, [:string]
+  #     end
+  #
+  # Calling {declare} tells Sass the argument names for your function.
+  # If omitted, the function will still work, but will not be able to accept keyword arguments.
+  # {declare} can also allow your function to take arbitrary keyword arguments.
+  #
+  # There are a few things to keep in mind when modifying this module.
+  # First of all, the arguments passed are {Value} objects.
+  # Value objects are also expected to be returned.
+  # This means that Ruby values must be unwrapped and wrapped.
+  #
+  # Most Value objects support the {Value::Base#value value} accessor for getting
+  # their Ruby values. Color objects, though, must be accessed using
+  # {Sass::Script::Value::Color#rgb rgb}, {Sass::Script::Value::Color#red red},
+  # {Sass::Script::Value::Color#blue green}, or {Sass::Script::Value::Color#blue
+  # blue}.
+  #
+  # Second, making Ruby functions accessible from Sass introduces the temptation
+  # to do things like database access within stylesheets.
+  # This is generally a bad idea;
+  # since Sass files are by default only compiled once,
+  # dynamic code is not a great fit.
+  #
+  # If you really, really need to compile Sass on each request,
+  # first make sure you have adequate caching set up.
+  # Then you can use {Sass::Engine} to render the code,
+  # using the {file:SASS_REFERENCE.md#custom-option `options` parameter}
+  # to pass in data that {EvaluationContext#options can be accessed}
+  # from your Sass functions.
+  #
+  # Within one of the functions in this module,
+  # methods of {EvaluationContext} can be used.
+  #
+  # ### Caveats
+  #
+  # When creating new {Value} objects within functions, be aware that it's not
+  # safe to call {Value::Base#to_s #to_s} (or other methods that use the string
+  # representation) on those objects without first setting {Tree::Node#options=
+  # the #options attribute}.
+  #
+  # @comment
+  #   rubocop:enable LineLength
+  module Functions
+    @signatures = {}
+
+    # A class representing a Sass function signature.
+    #
+    # @attr args [Array<String>] The names of the arguments to the function.
+    # @attr delayed_args [Array<String>] The names of the arguments whose evaluation should be
+    #   delayed.
+    # @attr var_args [Boolean] Whether the function takes a variable number of arguments.
+    # @attr var_kwargs [Boolean] Whether the function takes an arbitrary set of keyword arguments.
+    Signature = Struct.new(:args, :delayed_args, :var_args, :var_kwargs, :deprecated)
+
+    # Declare a Sass signature for a Ruby-defined function.
+    # This includes the names of the arguments,
+    # whether the function takes a variable number of arguments,
+    # and whether the function takes an arbitrary set of keyword arguments.
+    #
+    # It's not necessary to declare a signature for a function.
+    # However, without a signature it won't support keyword arguments.
+    #
+    # A single function can have multiple signatures declared
+    # as long as each one takes a different number of arguments.
+    # It's also possible to declare multiple signatures
+    # that all take the same number of arguments,
+    # but none of them but the first will be used
+    # unless the user uses keyword arguments.
+    #
+    # @example
+    #   declare :rgba, [:hex, :alpha]
+    #   declare :rgba, [:red, :green, :blue, :alpha]
+    #   declare :accepts_anything, [], :var_args => true, :var_kwargs => true
+    #   declare :some_func, [:foo, :bar, :baz], :var_kwargs => true
+    #
+    # @param method_name [Symbol] The name of the method
+    #   whose signature is being declared.
+    # @param args [Array<Symbol>] The names of the arguments for the function signature.
+    # @option options :var_args [Boolean] (false)
+    #   Whether the function accepts a variable number of (unnamed) arguments
+    #   in addition to the named arguments.
+    # @option options :var_kwargs [Boolean] (false)
+    #   Whether the function accepts other keyword arguments
+    #   in addition to those in `:args`.
+    #   If this is true, the Ruby function will be passed a hash from strings
+    #   to {Value}s as the last argument.
+    #   In addition, if this is true and `:var_args` is not,
+    #   Sass will ensure that the last argument passed is a hash.
+    def self.declare(method_name, args, options = {})
+      delayed_args = []
+      args = args.map do |a|
+        a = a.to_s
+        if a[0] == ?&
+          a = a[1..-1]
+          delayed_args << a
+        end
+        a
+      end
+      # We don't expose this functionality except to certain builtin methods.
+      if delayed_args.any? && method_name != :if
+        raise ArgumentError.new("Delayed arguments are not allowed for method #{method_name}")
+      end
+      @signatures[method_name] ||= []
+      @signatures[method_name] << Signature.new(
+        args,
+        delayed_args,
+        options[:var_args],
+        options[:var_kwargs],
+        options[:deprecated] && options[:deprecated].map {|a| a.to_s})
+    end
+
+    # Determine the correct signature for the number of arguments
+    # passed in for a given function.
+    # If no signatures match, the first signature is returned for error messaging.
+    #
+    # @param method_name [Symbol] The name of the Ruby function to be called.
+    # @param arg_arity [Fixnum] The number of unnamed arguments the function was passed.
+    # @param kwarg_arity [Fixnum] The number of keyword arguments the function was passed.
+    #
+    # @return [{Symbol => Object}, nil]
+    #   The signature options for the matching signature,
+    #   or nil if no signatures are declared for this function. See {declare}.
+    def self.signature(method_name, arg_arity, kwarg_arity)
+      return unless @signatures[method_name]
+      @signatures[method_name].each do |signature|
+        sig_arity = signature.args.size
+        return signature if sig_arity == arg_arity + kwarg_arity
+        next unless sig_arity < arg_arity + kwarg_arity
+
+        # We have enough args.
+        # Now we need to figure out which args are varargs
+        # and if the signature allows them.
+        t_arg_arity, t_kwarg_arity = arg_arity, kwarg_arity
+        if sig_arity > t_arg_arity
+          # we transfer some kwargs arity to args arity
+          # if it does not have enough args -- assuming the names will work out.
+          t_kwarg_arity -= (sig_arity - t_arg_arity)
+          t_arg_arity = sig_arity
+        end
+
+        if   (t_arg_arity == sig_arity ||   t_arg_arity > sig_arity && signature.var_args) &&
+           (t_kwarg_arity == 0         || t_kwarg_arity > 0         && signature.var_kwargs)
+          return signature
+        end
+      end
+      @signatures[method_name].first
+    end
+
+    # Sets the random seed used by Sass's internal random number generator.
+    #
+    # This can be used to ensure consistent random number sequences which
+    # allows for consistent results when testing, etc.
+    #
+    # @param seed [Integer]
+    # @return [Integer] The same seed.
+    def self.random_seed=(seed)
+      @random_number_generator = Sass::Util::CrossPlatformRandom.new(seed)
+    end
+
+    # Get Sass's internal random number generator.
+    #
+    # @return [Random]
+    def self.random_number_generator
+      @random_number_generator ||= Sass::Util::CrossPlatformRandom.new
+    end
+
+    # The context in which methods in {Script::Functions} are evaluated.
+    # That means that all instance methods of {EvaluationContext}
+    # are available to use in functions.
+    class EvaluationContext
+      include Functions
+      include Value::Helpers
+
+      # The human-readable names for [Sass::Script::Value::Base]. The default is
+      # just the downcased name of the type.
+      TYPE_NAMES = {:ArgList => 'variable argument list'}
+
+      # The environment for this function. This environment's
+      # {Environment#parent} is the global environment, and its
+      # {Environment#caller} is a read-only view of the local environment of the
+      # caller of this function.
+      #
+      # @return [Environment]
+      attr_reader :environment
+
+      # The options hash for the {Sass::Engine} that is processing the function call
+      #
+      # @return [{Symbol => Object}]
+      attr_reader :options
+
+      # @param environment [Environment] See \{#environment}
+      def initialize(environment)
+        @environment = environment
+        @options = environment.options
+      end
+
+      # Asserts that the type of a given SassScript value
+      # is the expected type (designated by a symbol).
+      #
+      # Valid types are `:Bool`, `:Color`, `:Number`, and `:String`.
+      # Note that `:String` will match both double-quoted strings
+      # and unquoted identifiers.
+      #
+      # @example
+      #   assert_type value, :String
+      #   assert_type value, :Number
+      # @param value [Sass::Script::Value::Base] A SassScript value
+      # @param type [Symbol] The name of the type the value is expected to be
+      # @param name [String, Symbol, nil] The name of the argument.
+      # @raise [ArgumentError] if value is not of the correct type.
+      def assert_type(value, type, name = nil)
+        klass = Sass::Script::Value.const_get(type)
+        return if value.is_a?(klass)
+        return if value.is_a?(Sass::Script::Value::List) && type == :Map && value.value.empty?
+        err = "#{value.inspect} is not a #{TYPE_NAMES[type] || type.to_s.downcase}"
+        err = "$#{name.to_s.gsub('_', '-')}: " + err if name
+        raise ArgumentError.new(err)
+      end
+
+      # Asserts that the unit of the number is as expected.
+      #
+      # @example
+      #   assert_unit number, "px"
+      #   assert_unit number, nil
+      # @param number [Sass::Script::Value::Number] The number to be validated.
+      # @param unit [::String]
+      #   The unit that the number must have.
+      #   If nil, the number must be unitless.
+      # @param name [::String] The name of the parameter being validated.
+      # @raise [ArgumentError] if number is not of the correct unit or is not a number.
+      def assert_unit(number, unit, name = nil)
+        assert_type number, :Number, name
+        return if number.is_unit?(unit)
+        expectation = unit ? "have a unit of #{unit}" : "be unitless"
+        if name
+          raise ArgumentError.new("Expected $#{name} to #{expectation} but got #{number}")
+        else
+          raise ArgumentError.new("Expected #{number} to #{expectation}")
+        end
+      end
+
+      # Asserts that the value is an integer.
+      #
+      # @example
+      #   assert_integer 2px
+      #   assert_integer 2.5px
+      #     => SyntaxError: "Expected 2.5px to be an integer"
+      #   assert_integer 2.5px, "width"
+      #     => SyntaxError: "Expected width to be an integer but got 2.5px"
+      # @param number [Sass::Script::Value::Base] The value to be validated.
+      # @param name [::String] The name of the parameter being validated.
+      # @raise [ArgumentError] if number is not an integer or is not a number.
+      def assert_integer(number, name = nil)
+        assert_type number, :Number, name
+        return if number.int?
+        if name
+          raise ArgumentError.new("Expected $#{name} to be an integer but got #{number}")
+        else
+          raise ArgumentError.new("Expected #{number} to be an integer")
+        end
+      end
+
+      # Performs a node that has been delayed for execution.
+      #
+      # @private
+      # @param node [Sass::Script::Tree::Node,
+      #   Sass::Script::Value::Base] When this is a tree node, it's
+      #   performed in the caller's environment. When it's a value
+      #   (which can happen when the value had to be performed already
+      #   -- like for a splat), it's returned as-is.
+      # @param env [Sass::Environment] The environment within which to perform the node.
+      #   Defaults to the (read-only) environment of the caller.
+      def perform(node, env = environment.caller)
+        if node.is_a?(Sass::Script::Value::Base)
+          node
+        else
+          node.perform(env)
+        end
+      end
+    end
+
+    class << self
+      # Returns whether user function with a given name exists.
+      #
+      # @param function_name [String]
+      # @return [Boolean]
+      alias_method :callable?, :public_method_defined?
+
+      private
+
+      def include(*args)
+        r = super
+        # We have to re-include ourselves into EvaluationContext to work around
+        # an icky Ruby restriction.
+        EvaluationContext.send :include, self
+        r
+      end
+    end
+
+    # Creates a {Sass::Script::Value::Color Color} object from red, green, and
+    # blue values.
+    #
+    # @see #rgba
+    # @overload rgb($red, $green, $blue)
+    #   @param $red [Sass::Script::Value::Number] The amount of red in the color.
+    #     Must be between 0 and 255 inclusive, or between `0%` and `100%`
+    #     inclusive
+    #   @param $green [Sass::Script::Value::Number] The amount of green in the
+    #     color. Must be between 0 and 255 inclusive, or between `0%` and `100%`
+    #     inclusive
+    #   @param $blue [Sass::Script::Value::Number] The amount of blue in the
+    #     color. Must be between 0 and 255 inclusive, or between `0%` and `100%`
+    #     inclusive
+    # @return [Sass::Script::Value::Color]
+    # @raise [ArgumentError] if any parameter is the wrong type or out of bounds
+    def rgb(red, green, blue)
+      assert_type red, :Number, :red
+      assert_type green, :Number, :green
+      assert_type blue, :Number, :blue
+
+      color_attrs = [[red, :red], [green, :green], [blue, :blue]].map do |(c, name)|
+        if c.is_unit?("%")
+          c.value * 255 / 100.0
+        elsif c.unitless?
+          c.value
+        else
+          raise ArgumentError.new("Expected #{c} to be unitless or have a unit of % but got #{c}")
+        end
+      end
+
+      # Don't store the string representation for function-created colors, both
+      # because it's not very useful and because some functions aren't supported
+      # on older browsers.
+      Sass::Script::Value::Color.new(color_attrs)
+    end
+    declare :rgb, [:red, :green, :blue]
+
+    # Creates a {Sass::Script::Value::Color Color} from red, green, blue, and
+    # alpha values.
+    # @see #rgb
+    #
+    # @overload rgba($red, $green, $blue, $alpha)
+    #   @param $red [Sass::Script::Value::Number] The amount of red in the
+    #     color. Must be between 0 and 255 inclusive or 0% and 100% inclusive
+    #   @param $green [Sass::Script::Value::Number] The amount of green in the
+    #     color. Must be between 0 and 255 inclusive or 0% and 100% inclusive
+    #   @param $blue [Sass::Script::Value::Number] The amount of blue in the
+    #     color. Must be between 0 and 255 inclusive or 0% and 100% inclusive
+    #   @param $alpha [Sass::Script::Value::Number] The opacity of the color.
+    #     Must be between 0 and 1 inclusive
+    #   @return [Sass::Script::Value::Color]
+    #   @raise [ArgumentError] if any parameter is the wrong type or out of
+    #     bounds
+    #
+    # @overload rgba($color, $alpha)
+    #   Sets the opacity of an existing color.
+    #
+    #   @example
+    #     rgba(#102030, 0.5) => rgba(16, 32, 48, 0.5)
+    #     rgba(blue, 0.2)    => rgba(0, 0, 255, 0.2)
+    #
+    #   @param $color [Sass::Script::Value::Color] The color whose opacity will
+    #     be changed.
+    #   @param $alpha [Sass::Script::Value::Number] The new opacity of the
+    #     color. Must be between 0 and 1 inclusive
+    #   @return [Sass::Script::Value::Color]
+    #   @raise [ArgumentError] if `$alpha` is out of bounds or either parameter
+    #     is the wrong type
+    def rgba(*args)
+      case args.size
+      when 2
+        color, alpha = args
+
+        assert_type color, :Color, :color
+        assert_type alpha, :Number, :alpha
+        check_alpha_unit alpha, 'rgba'
+
+        color.with(:alpha => alpha.value)
+      when 4
+        red, green, blue, alpha = args
+        rgba(rgb(red, green, blue), alpha)
+      else
+        raise ArgumentError.new("wrong number of arguments (#{args.size} for 4)")
+      end
+    end
+    declare :rgba, [:red, :green, :blue, :alpha]
+    declare :rgba, [:color, :alpha]
+
+    # Creates a {Sass::Script::Value::Color Color} from hue, saturation, and
+    # lightness values. Uses the algorithm from the [CSS3 spec][].
+    #
+    # [CSS3 spec]: http://www.w3.org/TR/css3-color/#hsl-color
+    #
+    # @see #hsla
+    # @overload hsl($hue, $saturation, $lightness)
+    #   @param $hue [Sass::Script::Value::Number] The hue of the color. Should be
+    #     between 0 and 360 degrees, inclusive
+    #   @param $saturation [Sass::Script::Value::Number] The saturation of the
+    #     color. Must be between `0%` and `100%`, inclusive
+    #   @param $lightness [Sass::Script::Value::Number] The lightness of the
+    #     color. Must be between `0%` and `100%`, inclusive
+    # @return [Sass::Script::Value::Color]
+    # @raise [ArgumentError] if `$saturation` or `$lightness` are out of bounds
+    #   or any parameter is the wrong type
+    def hsl(hue, saturation, lightness)
+      hsla(hue, saturation, lightness, number(1))
+    end
+    declare :hsl, [:hue, :saturation, :lightness]
+
+    # Creates a {Sass::Script::Value::Color Color} from hue,
+    # saturation, lightness, and alpha values. Uses the algorithm from
+    # the [CSS3 spec][].
+    #
+    # [CSS3 spec]: http://www.w3.org/TR/css3-color/#hsl-color
+    #
+    # @see #hsl
+    # @overload hsla($hue, $saturation, $lightness, $alpha)
+    #   @param $hue [Sass::Script::Value::Number] The hue of the color. Should be
+    #     between 0 and 360 degrees, inclusive
+    #   @param $saturation [Sass::Script::Value::Number] The saturation of the
+    #     color. Must be between `0%` and `100%`, inclusive
+    #   @param $lightness [Sass::Script::Value::Number] The lightness of the
+    #     color. Must be between `0%` and `100%`, inclusive
+    #   @param $alpha [Sass::Script::Value::Number] The opacity of the color. Must
+    #     be between 0 and 1, inclusive
+    # @return [Sass::Script::Value::Color]
+    # @raise [ArgumentError] if `$saturation`, `$lightness`, or `$alpha` are out
+    #   of bounds or any parameter is the wrong type
+    def hsla(hue, saturation, lightness, alpha)
+      assert_type hue, :Number, :hue
+      assert_type saturation, :Number, :saturation
+      assert_type lightness, :Number, :lightness
+      assert_type alpha, :Number, :alpha
+      check_alpha_unit alpha, 'hsla'
+
+      h = hue.value
+      s = saturation.value
+      l = lightness.value
+
+      # Don't store the string representation for function-created colors, both
+      # because it's not very useful and because some functions aren't supported
+      # on older browsers.
+      Sass::Script::Value::Color.new(
+        :hue => h, :saturation => s, :lightness => l, :alpha => alpha.value)
+    end
+    declare :hsla, [:hue, :saturation, :lightness, :alpha]
+
+    # Gets the red component of a color. Calculated from HSL where necessary via
+    # [this algorithm][hsl-to-rgb].
+    #
+    # [hsl-to-rgb]: http://www.w3.org/TR/css3-color/#hsl-color
+    #
+    # @overload red($color)
+    #   @param $color [Sass::Script::Value::Color]
+    # @return [Sass::Script::Value::Number] The red component, between 0 and 255
+    #   inclusive
+    # @raise [ArgumentError] if `$color` isn't a color
+    def red(color)
+      assert_type color, :Color, :color
+      number(color.red)
+    end
+    declare :red, [:color]
+
+    # Gets the green component of a color. Calculated from HSL where necessary
+    # via [this algorithm][hsl-to-rgb].
+    #
+    # [hsl-to-rgb]: http://www.w3.org/TR/css3-color/#hsl-color
+    #
+    # @overload green($color)
+    #   @param $color [Sass::Script::Value::Color]
+    # @return [Sass::Script::Value::Number] The green component, between 0 and
+    #   255 inclusive
+    # @raise [ArgumentError] if `$color` isn't a color
+    def green(color)
+      assert_type color, :Color, :color
+      number(color.green)
+    end
+    declare :green, [:color]
+
+    # Gets the blue component of a color. Calculated from HSL where necessary
+    # via [this algorithm][hsl-to-rgb].
+    #
+    # [hsl-to-rgb]: http://www.w3.org/TR/css3-color/#hsl-color
+    #
+    # @overload blue($color)
+    #   @param $color [Sass::Script::Value::Color]
+    # @return [Sass::Script::Value::Number] The blue component, between 0 and
+    #   255 inclusive
+    # @raise [ArgumentError] if `$color` isn't a color
+    def blue(color)
+      assert_type color, :Color, :color
+      number(color.blue)
+    end
+    declare :blue, [:color]
+
+    # Returns the hue component of a color. See [the CSS3 HSL
+    # specification][hsl]. Calculated from RGB where necessary via [this
+    # algorithm][rgb-to-hsl].
+    #
+    # [hsl]: http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV
+    # [rgb-to-hsl]: http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV
+    #
+    # @overload hue($color)
+    #   @param $color [Sass::Script::Value::Color]
+    # @return [Sass::Script::Value::Number] The hue component, between 0deg and
+    #   360deg
+    # @raise [ArgumentError] if `$color` isn't a color
+    def hue(color)
+      assert_type color, :Color, :color
+      number(color.hue, "deg")
+    end
+    declare :hue, [:color]
+
+    # Returns the saturation component of a color. See [the CSS3 HSL
+    # specification][hsl]. Calculated from RGB where necessary via [this
+    # algorithm][rgb-to-hsl].
+    #
+    # [hsl]: http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV
+    # [rgb-to-hsl]: http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV
+    #
+    # @overload saturation($color)
+    #   @param $color [Sass::Script::Value::Color]
+    # @return [Sass::Script::Value::Number] The saturation component, between 0%
+    #   and 100%
+    # @raise [ArgumentError] if `$color` isn't a color
+    def saturation(color)
+      assert_type color, :Color, :color
+      number(color.saturation, "%")
+    end
+    declare :saturation, [:color]
+
+    # Returns the lightness component of a color. See [the CSS3 HSL
+    # specification][hsl]. Calculated from RGB where necessary via [this
+    # algorithm][rgb-to-hsl].
+    #
+    # [hsl]: http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV
+    # [rgb-to-hsl]: http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV
+    #
+    # @overload lightness($color)
+    #   @param $color [Sass::Script::Value::Color]
+    # @return [Sass::Script::Value::Number] The lightness component, between 0%
+    #   and 100%
+    # @raise [ArgumentError] if `$color` isn't a color
+    def lightness(color)
+      assert_type color, :Color, :color
+      number(color.lightness, "%")
+    end
+    declare :lightness, [:color]
+
+    # Returns the alpha component (opacity) of a color. This is 1 unless
+    # otherwise specified.
+    #
+    # This function also supports the proprietary Microsoft `alpha(opacity=20)`
+    # syntax as a special case.
+    #
+    # @overload alpha($color)
+    #   @param $color [Sass::Script::Value::Color]
+    # @return [Sass::Script::Value::Number] The alpha component, between 0 and 1
+    # @raise [ArgumentError] if `$color` isn't a color
+    def alpha(*args)
+      if args.all? do |a|
+           a.is_a?(Sass::Script::Value::String) && a.type == :identifier &&
+             a.value =~ /^[a-zA-Z]+\s*=/
+         end
+        # Support the proprietary MS alpha() function
+        return identifier("alpha(#{args.map {|a| a.to_s}.join(", ")})")
+      end
+
+      raise ArgumentError.new("wrong number of arguments (#{args.size} for 1)") if args.size != 1
+
+      assert_type args.first, :Color, :color
+      number(args.first.alpha)
+    end
+    declare :alpha, [:color]
+
+    # Returns the alpha component (opacity) of a color. This is 1 unless
+    # otherwise specified.
+    #
+    # @overload opacity($color)
+    #   @param $color [Sass::Script::Value::Color]
+    # @return [Sass::Script::Value::Number] The alpha component, between 0 and 1
+    # @raise [ArgumentError] if `$color` isn't a color
+    def opacity(color)
+      if color.is_a?(Sass::Script::Value::Number)
+        return identifier("opacity(#{color})")
+      end
+      assert_type color, :Color, :color
+      number(color.alpha)
+    end
+    declare :opacity, [:color]
+
+    # Makes a color more opaque. Takes a color and a number between 0 and 1, and
+    # returns a color with the opacity increased by that amount.
+    #
+    # @see #transparentize
+    # @example
+    #   opacify(rgba(0, 0, 0, 0.5), 0.1) => rgba(0, 0, 0, 0.6)
+    #   opacify(rgba(0, 0, 17, 0.8), 0.2) => #001
+    # @overload opacify($color, $amount)
+    #   @param $color [Sass::Script::Value::Color]
+    #   @param $amount [Sass::Script::Value::Number] The amount to increase the
+    #     opacity by, between 0 and 1
+    # @return [Sass::Script::Value::Color]
+    # @raise [ArgumentError] if `$amount` is out of bounds, or either parameter
+    #   is the wrong type
+    def opacify(color, amount)
+      _adjust(color, amount, :alpha, 0..1, :+)
+    end
+    declare :opacify, [:color, :amount]
+
+    alias_method :fade_in, :opacify
+    declare :fade_in, [:color, :amount]
+
+    # Makes a color more transparent. Takes a color and a number between 0 and
+    # 1, and returns a color with the opacity decreased by that amount.
+    #
+    # @see #opacify
+    # @example
+    #   transparentize(rgba(0, 0, 0, 0.5), 0.1) => rgba(0, 0, 0, 0.4)
+    #   transparentize(rgba(0, 0, 0, 0.8), 0.2) => rgba(0, 0, 0, 0.6)
+    # @overload transparentize($color, $amount)
+    #   @param $color [Sass::Script::Value::Color]
+    #   @param $amount [Sass::Script::Value::Number] The amount to decrease the
+    #     opacity by, between 0 and 1
+    # @return [Sass::Script::Value::Color]
+    # @raise [ArgumentError] if `$amount` is out of bounds, or either parameter
+    #   is the wrong type
+    def transparentize(color, amount)
+      _adjust(color, amount, :alpha, 0..1, :-)
+    end
+    declare :transparentize, [:color, :amount]
+
+    alias_method :fade_out, :transparentize
+    declare :fade_out, [:color, :amount]
+
+    # Makes a color lighter. Takes a color and a number between `0%` and `100%`,
+    # and returns a color with the lightness increased by that amount.
+    #
+    # @see #darken
+    # @example
+    #   lighten(hsl(0, 0%, 0%), 30%) => hsl(0, 0, 30)
+    #   lighten(#800, 20%) => #e00
+    # @overload lighten($color, $amount)
+    #   @param $color [Sass::Script::Value::Color]
+    #   @param $amount [Sass::Script::Value::Number] The amount to increase the
+    #     lightness by, between `0%` and `100%`
+    # @return [Sass::Script::Value::Color]
+    # @raise [ArgumentError] if `$amount` is out of bounds, or either parameter
+    #   is the wrong type
+    def lighten(color, amount)
+      _adjust(color, amount, :lightness, 0..100, :+, "%")
+    end
+    declare :lighten, [:color, :amount]
+
+    # Makes a color darker. Takes a color and a number between 0% and 100%, and
+    # returns a color with the lightness decreased by that amount.
+    #
+    # @see #lighten
+    # @example
+    #   darken(hsl(25, 100%, 80%), 30%) => hsl(25, 100%, 50%)
+    #   darken(#800, 20%) => #200
+    # @overload darken($color, $amount)
+    #   @param $color [Sass::Script::Value::Color]
+    #   @param $amount [Sass::Script::Value::Number] The amount to decrease the
+    #     lightness by, between `0%` and `100%`
+    # @return [Sass::Script::Value::Color]
+    # @raise [ArgumentError] if `$amount` is out of bounds, or either parameter
+    #   is the wrong type
+    def darken(color, amount)
+      _adjust(color, amount, :lightness, 0..100, :-, "%")
+    end
+    declare :darken, [:color, :amount]
+
+    # Makes a color more saturated. Takes a color and a number between 0% and
+    # 100%, and returns a color with the saturation increased by that amount.
+    #
+    # @see #desaturate
+    # @example
+    #   saturate(hsl(120, 30%, 90%), 20%) => hsl(120, 50%, 90%)
+    #   saturate(#855, 20%) => #9e3f3f
+    # @overload saturate($color, $amount)
+    #   @param $color [Sass::Script::Value::Color]
+    #   @param $amount [Sass::Script::Value::Number] The amount to increase the
+    #     saturation by, between `0%` and `100%`
+    # @return [Sass::Script::Value::Color]
+    # @raise [ArgumentError] if `$amount` is out of bounds, or either parameter
+    #   is the wrong type
+    def saturate(color, amount = nil)
+      # Support the filter effects definition of saturate.
+      # https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html
+      return identifier("saturate(#{color})") if amount.nil?
+      _adjust(color, amount, :saturation, 0..100, :+, "%")
+    end
+    declare :saturate, [:color, :amount]
+    declare :saturate, [:amount]
+
+    # Makes a color less saturated. Takes a color and a number between 0% and
+    # 100%, and returns a color with the saturation decreased by that value.
+    #
+    # @see #saturate
+    # @example
+    #   desaturate(hsl(120, 30%, 90%), 20%) => hsl(120, 10%, 90%)
+    #   desaturate(#855, 20%) => #726b6b
+    # @overload desaturate($color, $amount)
+    #   @param $color [Sass::Script::Value::Color]
+    #   @param $amount [Sass::Script::Value::Number] The amount to decrease the
+    #     saturation by, between `0%` and `100%`
+    # @return [Sass::Script::Value::Color]
+    # @raise [ArgumentError] if `$amount` is out of bounds, or either parameter
+    #   is the wrong type
+    def desaturate(color, amount)
+      _adjust(color, amount, :saturation, 0..100, :-, "%")
+    end
+    declare :desaturate, [:color, :amount]
+
+    # Changes the hue of a color. Takes a color and a number of degrees (usually
+    # between `-360deg` and `360deg`), and returns a color with the hue rotated
+    # along the color wheel by that amount.
+    #
+    # @example
+    #   adjust-hue(hsl(120, 30%, 90%), 60deg) => hsl(180, 30%, 90%)
+    #   adjust-hue(hsl(120, 30%, 90%), -60deg) => hsl(60, 30%, 90%)
+    #   adjust-hue(#811, 45deg) => #886a11
+    # @overload adjust_hue($color, $degrees)
+    #   @param $color [Sass::Script::Value::Color]
+    #   @param $degrees [Sass::Script::Value::Number] The number of degrees to
+    #     rotate the hue
+    # @return [Sass::Script::Value::Color]
+    # @raise [ArgumentError] if either parameter is the wrong type
+    def adjust_hue(color, degrees)
+      assert_type color, :Color, :color
+      assert_type degrees, :Number, :degrees
+      color.with(:hue => color.hue + degrees.value)
+    end
+    declare :adjust_hue, [:color, :degrees]
+
+    # Converts a color into the format understood by IE filters.
+    #
+    # @example
+    #   ie-hex-str(#abc) => #FFAABBCC
+    #   ie-hex-str(#3322BB) => #FF3322BB
+    #   ie-hex-str(rgba(0, 255, 0, 0.5)) => #8000FF00
+    # @overload ie_hex_str($color)
+    #   @param $color [Sass::Script::Value::Color]
+    # @return [Sass::Script::Value::String] The IE-formatted string
+    #   representation of the color
+    # @raise [ArgumentError] if `$color` isn't a color
+    def ie_hex_str(color)
+      assert_type color, :Color, :color
+      alpha = (color.alpha * 255).round.to_s(16).rjust(2, '0')
+      identifier("##{alpha}#{color.send(:hex_str)[1..-1]}".upcase)
+    end
+    declare :ie_hex_str, [:color]
+
+    # Increases or decreases one or more properties of a color. This can change
+    # the red, green, blue, hue, saturation, value, and alpha properties. The
+    # properties are specified as keyword arguments, and are added to or
+    # subtracted from the color's current value for that property.
+    #
+    # All properties are optional. You can't specify both RGB properties
+    # (`$red`, `$green`, `$blue`) and HSL properties (`$hue`, `$saturation`,
+    # `$value`) at the same time.
+    #
+    # @example
+    #   adjust-color(#102030, $blue: 5) => #102035
+    #   adjust-color(#102030, $red: -5, $blue: 5) => #0b2035
+    #   adjust-color(hsl(25, 100%, 80%), $lightness: -30%, $alpha: -0.4) => hsla(25, 100%, 50%, 0.6)
+    # @comment
+    #   rubocop:disable LineLength
+    # @overload adjust_color($color, [$red], [$green], [$blue], [$hue], [$saturation], [$lightness], 
[$alpha])
+    #   @comment
+    #     rubocop:disable LineLength
+    #   @param $color [Sass::Script::Value::Color]
+    #   @param $red [Sass::Script::Value::Number] The adjustment to make on the
+    #     red component, between -255 and 255 inclusive
+    #   @param $green [Sass::Script::Value::Number] The adjustment to make on the
+    #     green component, between -255 and 255 inclusive
+    #   @param $blue [Sass::Script::Value::Number] The adjustment to make on the
+    #     blue component, between -255 and 255 inclusive
+    #   @param $hue [Sass::Script::Value::Number] The adjustment to make on the
+    #     hue component, in degrees
+    #   @param $saturation [Sass::Script::Value::Number] The adjustment to make on
+    #     the saturation component, between `-100%` and `100%` inclusive
+    #   @param $lightness [Sass::Script::Value::Number] The adjustment to make on
+    #     the lightness component, between `-100%` and `100%` inclusive
+    #   @param $alpha [Sass::Script::Value::Number] The adjustment to make on the
+    #     alpha component, between -1 and 1 inclusive
+    # @return [Sass::Script::Value::Color]
+    # @raise [ArgumentError] if any parameter is the wrong type or out-of
+    #   bounds, or if RGB properties and HSL properties are adjusted at the
+    #   same time
+    def adjust_color(color, kwargs)
+      assert_type color, :Color, :color
+      with = Sass::Util.map_hash(
+          "red" => [-255..255, ""],
+          "green" => [-255..255, ""],
+          "blue" => [-255..255, ""],
+          "hue" => nil,
+          "saturation" => [-100..100, "%"],
+          "lightness" => [-100..100, "%"],
+          "alpha" => [-1..1, ""]
+        ) do |name, (range, units)|
+
+        val = kwargs.delete(name)
+        next unless val
+        assert_type val, :Number, name
+        Sass::Util.check_range("$#{name}: Amount", range, val, units) if range
+        adjusted = color.send(name) + val.value
+        adjusted = [0, Sass::Util.restrict(adjusted, range)].max if range
+        [name.to_sym, adjusted]
+      end
+
+      unless kwargs.empty?
+        name, val = kwargs.to_a.first
+        raise ArgumentError.new("Unknown argument $#{name} (#{val})")
+      end
+
+      color.with(with)
+    end
+    declare :adjust_color, [:color], :var_kwargs => true
+
+    # Fluidly scales one or more properties of a color. Unlike
+    # \{#adjust_color adjust-color}, which changes a color's properties by fixed
+    # amounts, \{#scale_color scale-color} fluidly changes them based on how
+    # high or low they already are. That means that lightening an already-light
+    # color with \{#scale_color scale-color} won't change the lightness much,
+    # but lightening a dark color by the same amount will change it more
+    # dramatically. This has the benefit of making `scale-color($color, ...)`
+    # have a similar effect regardless of what `$color` is.
+    #
+    # For example, the lightness of a color can be anywhere between `0%` and
+    # `100%`. If `scale-color($color, $lightness: 40%)` is called, the resulting
+    # color's lightness will be 40% of the way between its original lightness
+    # and 100. If `scale-color($color, $lightness: -40%)` is called instead, the
+    # lightness will be 40% of the way between the original and 0.
+    #
+    # This can change the red, green, blue, saturation, value, and alpha
+    # properties. The properties are specified as keyword arguments. All
+    # arguments should be percentages between `0%` and `100%`.
+    #
+    # All properties are optional. You can't specify both RGB properties
+    # (`$red`, `$green`, `$blue`) and HSL properties (`$saturation`, `$value`)
+    # at the same time.
+    #
+    # @example
+    #   scale-color(hsl(120, 70%, 80%), $lightness: 50%) => hsl(120, 70%, 90%)
+    #   scale-color(rgb(200, 150%, 170%), $green: -40%, $blue: 70%) => rgb(200, 90, 229)
+    #   scale-color(hsl(200, 70%, 80%), $saturation: -90%, $alpha: -30%) => hsla(200, 7%, 80%, 0.7)
+    # @comment
+    #   rubocop:disable LineLength
+    # @overload scale_color($color, [$red], [$green], [$blue], [$saturation], [$lightness], [$alpha])
+    #   @comment
+    #     rubocop:disable LineLength
+    #   @param $color [Sass::Script::Value::Color]
+    #   @param $red [Sass::Script::Value::Number]
+    #   @param $green [Sass::Script::Value::Number]
+    #   @param $blue [Sass::Script::Value::Number]
+    #   @param $saturation [Sass::Script::Value::Number]
+    #   @param $lightness [Sass::Script::Value::Number]
+    #   @param $alpha [Sass::Script::Value::Number]
+    # @return [Sass::Script::Value::Color]
+    # @raise [ArgumentError] if any parameter is the wrong type or out-of
+    #   bounds, or if RGB properties and HSL properties are adjusted at the
+    #   same time
+    def scale_color(color, kwargs)
+      assert_type color, :Color, :color
+      with = Sass::Util.map_hash(
+          "red" => 255,
+          "green" => 255,
+          "blue" => 255,
+          "saturation" => 100,
+          "lightness" => 100,
+          "alpha" => 1
+        ) do |name, max|
+
+        val = kwargs.delete(name)
+        next unless val
+        assert_type val, :Number, name
+        assert_unit val, '%', name
+        Sass::Util.check_range("$#{name}: Amount", -100..100, val, '%')
+
+        current = color.send(name)
+        scale = val.value / 100.0
+        diff = scale > 0 ? max - current : current
+        [name.to_sym, current + diff * scale]
+      end
+
+      unless kwargs.empty?
+        name, val = kwargs.to_a.first
+        raise ArgumentError.new("Unknown argument $#{name} (#{val})")
+      end
+
+      color.with(with)
+    end
+    declare :scale_color, [:color], :var_kwargs => true
+
+    # Changes one or more properties of a color. This can change the red, green,
+    # blue, hue, saturation, value, and alpha properties. The properties are
+    # specified as keyword arguments, and replace the color's current value for
+    # that property.
+    #
+    # All properties are optional. You can't specify both RGB properties
+    # (`$red`, `$green`, `$blue`) and HSL properties (`$hue`, `$saturation`,
+    # `$value`) at the same time.
+    #
+    # @example
+    #   change-color(#102030, $blue: 5) => #102005
+    #   change-color(#102030, $red: 120, $blue: 5) => #782005
+    #   change-color(hsl(25, 100%, 80%), $lightness: 40%, $alpha: 0.8) => hsla(25, 100%, 40%, 0.8)
+    # @comment
+    #   rubocop:disable LineLength
+    # @overload change_color($color, [$red], [$green], [$blue], [$hue], [$saturation], [$lightness], 
[$alpha])
+    #   @comment
+    #     rubocop:disable LineLength
+    #   @param $color [Sass::Script::Value::Color]
+    #   @param $red [Sass::Script::Value::Number] The new red component for the
+    #     color, within 0 and 255 inclusive
+    #   @param $green [Sass::Script::Value::Number] The new green component for
+    #     the color, within 0 and 255 inclusive
+    #   @param $blue [Sass::Script::Value::Number] The new blue component for the
+    #     color, within 0 and 255 inclusive
+    #   @param $hue [Sass::Script::Value::Number] The new hue component for the
+    #     color, in degrees
+    #   @param $saturation [Sass::Script::Value::Number] The new saturation
+    #     component for the color, between `0%` and `100%` inclusive
+    #   @param $lightness [Sass::Script::Value::Number] The new lightness
+    #     component for the color, within `0%` and `100%` inclusive
+    #   @param $alpha [Sass::Script::Value::Number] The new alpha component for
+    #     the color, within 0 and 1 inclusive
+    # @return [Sass::Script::Value::Color]
+    # @raise [ArgumentError] if any parameter is the wrong type or out-of
+    #   bounds, or if RGB properties and HSL properties are adjusted at the
+    #   same time
+    def change_color(color, kwargs)
+      assert_type color, :Color, :color
+      with = Sass::Util.map_hash(
+        'red' => ['Red value', 0..255],
+        'green' => ['Green value', 0..255],
+        'blue' => ['Blue value', 0..255],
+        'hue' => [],
+        'saturation' => ['Saturation', 0..100, '%'],
+        'lightness' => ['Lightness', 0..100, '%'],
+        'alpha' => ['Alpha channel', 0..1]
+      ) do |name, (desc, range, unit)|
+        val = kwargs.delete(name)
+        next unless val
+        assert_type val, :Number, name
+
+        if range
+          val = Sass::Util.check_range(desc, range, val, unit)
+        else
+          val = val.value
+        end
+
+        [name.to_sym, val]
+      end
+
+      unless kwargs.empty?
+        name, val = kwargs.to_a.first
+        raise ArgumentError.new("Unknown argument $#{name} (#{val})")
+      end
+
+      color.with(with)
+    end
+    declare :change_color, [:color], :var_kwargs => true
+
+    # Mixes two colors together. Specifically, takes the average of each of the
+    # RGB components, optionally weighted by the given percentage. The opacity
+    # of the colors is also considered when weighting the components.
+    #
+    # The weight specifies the amount of the first color that should be included
+    # in the returned color. The default, `50%`, means that half the first color
+    # and half the second color should be used. `25%` means that a quarter of
+    # the first color and three quarters of the second color should be used.
+    #
+    # @example
+    #   mix(#f00, #00f) => #7f007f
+    #   mix(#f00, #00f, 25%) => #3f00bf
+    #   mix(rgba(255, 0, 0, 0.5), #00f) => rgba(63, 0, 191, 0.75)
+    # @overload mix($color1, $color2, $weight: 50%)
+    #   @param $color1 [Sass::Script::Value::Color]
+    #   @param $color2 [Sass::Script::Value::Color]
+    #   @param $weight [Sass::Script::Value::Number] The relative weight of each
+    #     color. Closer to `0%` gives more weight to `$color1`, closer to `100%`
+    #     gives more weight to `$color2`
+    # @return [Sass::Script::Value::Color]
+    # @raise [ArgumentError] if `$weight` is out of bounds or any parameter is
+    #   the wrong type
+    def mix(color1, color2, weight = number(50))
+      assert_type color1, :Color, :color1
+      assert_type color2, :Color, :color2
+      assert_type weight, :Number, :weight
+
+      Sass::Util.check_range("Weight", 0..100, weight, '%')
+
+      # This algorithm factors in both the user-provided weight (w) and the
+      # difference between the alpha values of the two colors (a) to decide how
+      # to perform the weighted average of the two RGB values.
+      #
+      # It works by first normalizing both parameters to be within [-1, 1],
+      # where 1 indicates "only use color1", -1 indicates "only use color2", and
+      # all values in between indicated a proportionately weighted average.
+      #
+      # Once we have the normalized variables w and a, we apply the formula
+      # (w + a)/(1 + w*a) to get the combined weight (in [-1, 1]) of color1.
+      # This formula has two especially nice properties:
+      #
+      #   * When either w or a are -1 or 1, the combined weight is also that number
+      #     (cases where w * a == -1 are undefined, and handled as a special case).
+      #
+      #   * When a is 0, the combined weight is w, and vice versa.
+      #
+      # Finally, the weight of color1 is renormalized to be within [0, 1]
+      # and the weight of color2 is given by 1 minus the weight of color1.
+      p = (weight.value / 100.0).to_f
+      w = p * 2 - 1
+      a = color1.alpha - color2.alpha
+
+      w1 = ((w * a == -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0
+      w2 = 1 - w1
+
+      rgba = color1.rgb.zip(color2.rgb).map {|v1, v2| v1 * w1 + v2 * w2}
+      rgba << color1.alpha * p + color2.alpha * (1 - p)
+      rgb_color(*rgba)
+    end
+    declare :mix, [:color1, :color2]
+    declare :mix, [:color1, :color2, :weight]
+
+    # Converts a color to grayscale. This is identical to `desaturate(color,
+    # 100%)`.
+    #
+    # @see #desaturate
+    # @overload grayscale($color)
+    #   @param $color [Sass::Script::Value::Color]
+    # @return [Sass::Script::Value::Color]
+    # @raise [ArgumentError] if `$color` isn't a color
+    def grayscale(color)
+      if color.is_a?(Sass::Script::Value::Number)
+        return identifier("grayscale(#{color})")
+      end
+      desaturate color, number(100)
+    end
+    declare :grayscale, [:color]
+
+    # Returns the complement of a color. This is identical to `adjust-hue(color,
+    # 180deg)`.
+    #
+    # @see #adjust_hue #adjust-hue
+    # @overload complement($color)
+    #   @param $color [Sass::Script::Value::Color]
+    # @return [Sass::Script::Value::Color]
+    # @raise [ArgumentError] if `$color` isn't a color
+    def complement(color)
+      adjust_hue color, number(180)
+    end
+    declare :complement, [:color]
+
+    # Returns the inverse (negative) of a color. The red, green, and blue values
+    # are inverted, while the opacity is left alone.
+    #
+    # @overload invert($color)
+    #   @param $color [Sass::Script::Value::Color]
+    # @return [Sass::Script::Value::Color]
+    # @raise [ArgumentError] if `$color` isn't a color
+    def invert(color)
+      if color.is_a?(Sass::Script::Value::Number)
+        return identifier("invert(#{color})")
+      end
+
+      assert_type color, :Color, :color
+      color.with(
+        :red => (255 - color.red),
+        :green => (255 - color.green),
+        :blue => (255 - color.blue))
+    end
+    declare :invert, [:color]
+
+    # Removes quotes from a string. If the string is already unquoted, this will
+    # return it unmodified.
+    #
+    # @see #quote
+    # @example
+    #   unquote("foo") => foo
+    #   unquote(foo) => foo
+    # @overload unquote($string)
+    #   @param $string [Sass::Script::Value::String]
+    # @return [Sass::Script::Value::String]
+    # @raise [ArgumentError] if `$string` isn't a string
+    def unquote(string)
+      if string.is_a?(Sass::Script::Value::String) && string.type != :identifier
+        identifier(string.value)
+      else
+        string
+      end
+    end
+    declare :unquote, [:string]
+
+    # Add quotes to a string if the string isn't quoted,
+    # or returns the same string if it is.
+    #
+    # @see #unquote
+    # @example
+    #   quote("foo") => "foo"
+    #   quote(foo) => "foo"
+    # @overload quote($string)
+    #   @param $string [Sass::Script::Value::String]
+    # @return [Sass::Script::Value::String]
+    # @raise [ArgumentError] if `$string` isn't a string
+    def quote(string)
+      assert_type string, :String, :string
+      if string.type != :string
+        quoted_string(string.value)
+      else
+        string
+      end
+    end
+    declare :quote, [:string]
+
+    # Returns the number of characters in a string.
+    #
+    # @example
+    #   str-length("foo") => 3
+    # @overload str_length($string)
+    #   @param $string [Sass::Script::Value::String]
+    # @return [Sass::Script::Value::Number]
+    # @raise [ArgumentError] if `$string` isn't a string
+    def str_length(string)
+      assert_type string, :String, :string
+      number(string.value.size)
+    end
+    declare :str_length, [:string]
+
+    # Inserts `$insert` into `$string` at `$index`.
+    #
+    # Note that unlike some languages, the first character in a Sass string is
+    # number 1, the second number 2, and so forth.
+    #
+    # @example
+    #   str-insert("abcd", "X", 1) => "Xabcd"
+    #   str-insert("abcd", "X", 4) => "abcXd"
+    #   str-insert("abcd", "X", 5) => "abcdX"
+    #
+    # @overload str_insert($string, $insert, $index)
+    #   @param $string [Sass::Script::Value::String]
+    #   @param $insert [Sass::Script::Value::String]
+    #   @param $index [Sass::Script::Value::Number] The position at which
+    #     `$insert` will be inserted. Negative indices count from the end of
+    #     `$string`. An index that's outside the bounds of the string will insert
+    #     `$insert` at the front or back of the string
+    # @return [Sass::Script::Value::String] The result string. This will be
+    #   quoted if and only if `$string` was quoted
+    # @raise [ArgumentError] if any parameter is the wrong type
+    def str_insert(original, insert, index)
+      assert_type original, :String, :string
+      assert_type insert, :String, :insert
+      assert_integer index, :index
+      assert_unit index, nil, :index
+      insertion_point = if index.value > 0
+                          [index.value - 1, original.value.size].min
+                        else
+                          [index.value, -original.value.size - 1].max
+                        end
+      result = original.value.dup.insert(insertion_point, insert.value)
+      Sass::Script::Value::String.new(result, original.type)
+    end
+    declare :str_insert, [:string, :insert, :index]
+
+    # Returns the index of the first occurrence of `$substring` in `$string`. If
+    # there is no such occurrence, returns `null`.
+    #
+    # Note that unlike some languages, the first character in a Sass string is
+    # number 1, the second number 2, and so forth.
+    #
+    # @example
+    #   str-index(abcd, a)  => 1
+    #   str-index(abcd, ab) => 1
+    #   str-index(abcd, X)  => null
+    #   str-index(abcd, c)  => 3
+    #
+    # @overload str_index($string, $substring)
+    #   @param $string [Sass::Script::Value::String]
+    #   @param $substring [Sass::Script::Value::String]
+    # @return [Sass::Script::Value::Number, Sass::Script::Value::Null]
+    # @raise [ArgumentError] if any parameter is the wrong type
+    def str_index(string, substring)
+      assert_type string, :String, :string
+      assert_type substring, :String, :substring
+      index = string.value.index(substring.value)
+      index ? number(index + 1) : null
+    end
+    declare :str_index, [:string, :substring]
+
+    # Extracts a substring from `$string`. The substring will begin at index
+    # `$start-at` and ends at index `$end-at`.
+    #
+    # Note that unlike some languages, the first character in a Sass string is
+    # number 1, the second number 2, and so forth.
+    #
+    # @example
+    #  str-slice("abcd", 2, 3)   => "bc"
+    #  str-slice("abcd", 2)      => "bcd"
+    #  str-slice("abcd", -3, -2) => "bc"
+    #  str-slice("abcd", 2, -2)  => "bc"
+    #
+    # @overload str_slice($string, $start-at, $end-at: -1)
+    #   @param $start-at [Sass::Script::Value::Number] The index of the first
+    #     character of the substring. If this is negative, it counts from the end
+    #     of `$string`
+    #   @param $end-before [Sass::Script::Value::Number] The index of the last
+    #     character of the substring. If this is negative, it counts from the end
+    #     of `$string`. Defaults to -1
+    #   @return [Sass::Script::Value::String] The substring. This will be quoted
+    #     if and only if `$string` was quoted
+    # @raise [ArgumentError] if any parameter is the wrong type
+    def str_slice(string, start_at, end_at = nil)
+      assert_type string, :String, :string
+      assert_unit start_at, nil, "start-at"
+
+      end_at = number(-1) if end_at.nil?
+      assert_unit end_at, nil, "end-at"
+
+      return Sass::Script::Value::String.new("", string.type) if end_at.value == 0
+      s = start_at.value > 0 ? start_at.value - 1 : start_at.value
+      e = end_at.value > 0 ? end_at.value - 1 : end_at.value
+      s = string.value.length + s if s < 0
+      s = 0 if s < 0
+      e = string.value.length + e if e < 0
+      e = 0 if s < 0
+      extracted = string.value.slice(s..e)
+      Sass::Script::Value::String.new(extracted || "", string.type)
+    end
+    declare :str_slice, [:string, :start_at]
+    declare :str_slice, [:string, :start_at, :end_at]
+
+    # Converts a string to upper case.
+    #
+    # @example
+    #   to-upper-case(abcd) => ABCD
+    #
+    # @overload to_upper_case($string)
+    #   @param $string [Sass::Script::Value::String]
+    # @return [Sass::Script::Value::String]
+    # @raise [ArgumentError] if `$string` isn't a string
+    def to_upper_case(string)
+      assert_type string, :String, :string
+      Sass::Script::Value::String.new(string.value.upcase, string.type)
+    end
+    declare :to_upper_case, [:string]
+
+    # Convert a string to lower case,
+    #
+    # @example
+    #   to-lower-case(ABCD) => abcd
+    #
+    # @overload to_lower_case($string)
+    #   @param $string [Sass::Script::Value::String]
+    # @return [Sass::Script::Value::String]
+    # @raise [ArgumentError] if `$string` isn't a string
+    def to_lower_case(string)
+      assert_type string, :String, :string
+      Sass::Script::Value::String.new(string.value.downcase, string.type)
+    end
+    declare :to_lower_case, [:string]
+
+    # Returns the type of a value.
+    #
+    # @example
+    #   type-of(100px)  => number
+    #   type-of(asdf)   => string
+    #   type-of("asdf") => string
+    #   type-of(true)   => bool
+    #   type-of(#fff)   => color
+    #   type-of(blue)   => color
+    # @overload type_of($value)
+    #   @param $value [Sass::Script::Value::Base] The value to inspect
+    # @return [Sass::Script::Value::String] The unquoted string name of the
+    #   value's type
+    def type_of(value)
+      identifier(value.class.name.gsub(/Sass::Script::Value::/, '').downcase)
+    end
+    declare :type_of, [:value]
+
+    # Returns whether a feature exists in the current Sass runtime.
+    #
+    # The following features are supported:
+    #
+    # * `global-variable-shadowing` indicates that a local variable will shadow
+    #   a global variable unless `!global` is used.
+    #
+    # * `extend-selector-pseudoclass` indicates that ` extend` will reach into
+    #   selector pseudoclasses like `:not`.
+    #
+    # * `units-level-3` indicates full support for unit arithmetic using units
+    #   defined in the [Values and Units Level 3][] spec.
+    #
+    # [Values and Units Level 3]: http://www.w3.org/TR/css3-values/
+    #
+    # * `at-error` indicates that the Sass ` error` directive is supported.
+    #
+    # @example
+    #   feature-exists(some-feature-that-exists) => true
+    #   feature-exists(what-is-this-i-dont-know) => false
+    #
+    # @overload feature_exists($feature)
+    #   @param $feature [Sass::Script::Value::String] The name of the feature
+    # @return [Sass::Script::Value::Bool] Whether the feature is supported in this version of Sass
+    # @raise [ArgumentError] if `$feature` isn't a string
+    def feature_exists(feature)
+      assert_type feature, :String, :feature
+      bool(Sass.has_feature?(feature.value))
+    end
+    declare :feature_exists, [:feature]
+
+    # Returns the unit(s) associated with a number. Complex units are sorted in
+    # alphabetical order by numerator and denominator.
+    #
+    # @example
+    #   unit(100) => ""
+    #   unit(100px) => "px"
+    #   unit(3em) => "em"
+    #   unit(10px * 5em) => "em*px"
+    #   unit(10px * 5em / 30cm / 1rem) => "em*px/cm*rem"
+    # @overload unit($number)
+    #   @param $number [Sass::Script::Value::Number]
+    # @return [Sass::Script::Value::String] The unit(s) of the number, as a
+    #   quoted string
+    # @raise [ArgumentError] if `$number` isn't a number
+    def unit(number)
+      assert_type number, :Number, :number
+      quoted_string(number.unit_str)
+    end
+    declare :unit, [:number]
+
+    # Returns whether a number has units.
+    #
+    # @example
+    #   unitless(100) => true
+    #   unitless(100px) => false
+    # @overload unitless($number)
+    #   @param $number [Sass::Script::Value::Number]
+    # @return [Sass::Script::Value::Bool]
+    # @raise [ArgumentError] if `$number` isn't a number
+    def unitless(number)
+      assert_type number, :Number, :number
+      bool(number.unitless?)
+    end
+    declare :unitless, [:number]
+
+    # Returns whether two numbers can added, subtracted, or compared.
+    #
+    # @example
+    #   comparable(2px, 1px) => true
+    #   comparable(100px, 3em) => false
+    #   comparable(10cm, 3mm) => true
+    # @overload comparable($number1, $number2)
+    #   @param $number1 [Sass::Script::Value::Number]
+    #   @param $number2 [Sass::Script::Value::Number]
+    # @return [Sass::Script::Value::Bool]
+    # @raise [ArgumentError] if either parameter is the wrong type
+    def comparable(number1, number2)
+      assert_type number1, :Number, :number1
+      assert_type number2, :Number, :number2
+      bool(number1.comparable_to?(number2))
+    end
+    declare :comparable, [:number1, :number2]
+
+    # Converts a unitless number to a percentage.
+    #
+    # @example
+    #   percentage(0.2) => 20%
+    #   percentage(100px / 50px) => 200%
+    # @overload percentage($number)
+    #   @param $number [Sass::Script::Value::Number]
+    # @return [Sass::Script::Value::Number]
+    # @raise [ArgumentError] if `$number` isn't a unitless number
+    def percentage(number)
+      unless number.is_a?(Sass::Script::Value::Number) && number.unitless?
+        raise ArgumentError.new("$number: #{number.inspect} is not a unitless number")
+      end
+      number(number.value * 100, '%')
+    end
+    declare :percentage, [:number]
+
+    # Rounds a number to the nearest whole number.
+    #
+    # @example
+    #   round(10.4px) => 10px
+    #   round(10.6px) => 11px
+    # @overload round($number)
+    #   @param $number [Sass::Script::Value::Number]
+    # @return [Sass::Script::Value::Number]
+    # @raise [ArgumentError] if `$number` isn't a number
+    def round(number)
+      numeric_transformation(number) {|n| n.round}
+    end
+    declare :round, [:number]
+
+    # Rounds a number up to the next whole number.
+    #
+    # @example
+    #   ceil(10.4px) => 11px
+    #   ceil(10.6px) => 11px
+    # @overload ceil($number)
+    #   @param $number [Sass::Script::Value::Number]
+    # @return [Sass::Script::Value::Number]
+    # @raise [ArgumentError] if `$number` isn't a number
+    def ceil(number)
+      numeric_transformation(number) {|n| n.ceil}
+    end
+    declare :ceil, [:number]
+
+    # Rounds a number down to the previous whole number.
+    #
+    # @example
+    #   floor(10.4px) => 10px
+    #   floor(10.6px) => 10px
+    # @overload floor($number)
+    #   @param $number [Sass::Script::Value::Number]
+    # @return [Sass::Script::Value::Number]
+    # @raise [ArgumentError] if `$number` isn't a number
+    def floor(number)
+      numeric_transformation(number) {|n| n.floor}
+    end
+    declare :floor, [:number]
+
+    # Returns the absolute value of a number.
+    #
+    # @example
+    #   abs(10px) => 10px
+    #   abs(-10px) => 10px
+    # @overload abs($number)
+    #   @param $number [Sass::Script::Value::Number]
+    # @return [Sass::Script::Value::Number]
+    # @raise [ArgumentError] if `$number` isn't a number
+    def abs(number)
+      numeric_transformation(number) {|n| n.abs}
+    end
+    declare :abs, [:number]
+
+    # Finds the minimum of several numbers. This function takes any number of
+    # arguments.
+    #
+    # @example
+    #   min(1px, 4px) => 1px
+    #   min(5em, 3em, 4em) => 3em
+    # @overload min($numbers...)
+    #   @param $numbers [[Sass::Script::Value::Number]]
+    # @return [Sass::Script::Value::Number]
+    # @raise [ArgumentError] if any argument isn't a number, or if not all of
+    #   the arguments have comparable units
+    def min(*numbers)
+      numbers.each {|n| assert_type n, :Number}
+      numbers.inject {|min, num| min.lt(num).to_bool ? min : num}
+    end
+    declare :min, [], :var_args => :true
+
+    # Finds the maximum of several numbers. This function takes any number of
+    # arguments.
+    #
+    # @example
+    #   max(1px, 4px) => 4px
+    #   max(5em, 3em, 4em) => 5em
+    # @overload max($numbers...)
+    #   @param $numbers [[Sass::Script::Value::Number]]
+    # @return [Sass::Script::Value::Number]
+    # @raise [ArgumentError] if any argument isn't a number, or if not all of
+    #   the arguments have comparable units
+    def max(*values)
+      values.each {|v| assert_type v, :Number}
+      values.inject {|max, val| max.gt(val).to_bool ? max : val}
+    end
+    declare :max, [], :var_args => :true
+
+    # Return the length of a list.
+    #
+    # This can return the number of pairs in a map as well.
+    #
+    # @example
+    #   length(10px) => 1
+    #   length(10px 20px 30px) => 3
+    #   length((width: 10px, height: 20px)) => 2
+    # @overload length($list)
+    #   @param $list [Sass::Script::Value::Base]
+    # @return [Sass::Script::Value::Number]
+    def length(list)
+      number(list.to_a.size)
+    end
+    declare :length, [:list]
+
+    # Return a new list, based on the list provided, but with the nth
+    # element changed to the value given.
+    #
+    # Note that unlike some languages, the first item in a Sass list is number
+    # 1, the second number 2, and so forth.
+    #
+    # Negative index values address elements in reverse order, starting with the last element
+    # in the list.
+    #
+    # @example
+    #   set-nth($list: 10px 20px 30px, $n: 2, $value: -20px) => 10px -20px 30px
+    # @overload set-nth($list, $n, $value)
+    #   @param $list [Sass::Script::Value::Base] The list that will be copied, having the element
+    #     at index `$n` changed.
+    #   @param $n [Sass::Script::Value::Number] The index of the item to set.
+    #     Negative indices count from the end of the list.
+    #   @param $value [Sass::Script::Value::Base] The new value at index `$n`.
+    # @return [Sass::Script::Value::List]
+    # @raise [ArgumentError] if `$n` isn't an integer between 1 and the length
+    #   of `$list`
+    def set_nth(list, n, value)
+      assert_type n, :Number, :n
+      Sass::Script::Value::List.assert_valid_index(list, n)
+      index = n.to_i > 0 ? n.to_i - 1 : n.to_i
+      new_list = list.to_a.dup
+      new_list[index] = value
+      Sass::Script::Value::List.new(new_list, list.separator)
+    end
+    declare :set_nth, [:list, :n, :value]
+
+    # Gets the nth item in a list.
+    #
+    # Note that unlike some languages, the first item in a Sass list is number
+    # 1, the second number 2, and so forth.
+    #
+    # This can return the nth pair in a map as well.
+    #
+    # Negative index values address elements in reverse order, starting with the last element in
+    # the list.
+    #
+    # @example
+    #   nth(10px 20px 30px, 1) => 10px
+    #   nth((Helvetica, Arial, sans-serif), 3) => sans-serif
+    #   nth((width: 10px, length: 20px), 2) => length, 20px
+    # @overload nth($list, $n)
+    #   @param $list [Sass::Script::Value::Base]
+    #   @param $n [Sass::Script::Value::Number] The index of the item to get.
+    #     Negative indices count from the end of the list.
+    # @return [Sass::Script::Value::Base]
+    # @raise [ArgumentError] if `$n` isn't an integer between 1 and the length
+    #   of `$list`
+    def nth(list, n)
+      assert_type n, :Number, :n
+      Sass::Script::Value::List.assert_valid_index(list, n)
+
+      index = n.to_i > 0 ? n.to_i - 1 : n.to_i
+      list.to_a[index]
+    end
+    declare :nth, [:list, :n]
+
+    # Joins together two lists into one.
+    #
+    # Unless `$separator` is passed, if one list is comma-separated and one is
+    # space-separated, the first parameter's separator is used for the resulting
+    # list. If both lists have fewer than two items, spaces are used for the
+    # resulting list.
+    #
+    # @example
+    #   join(10px 20px, 30px 40px) => 10px 20px 30px 40px
+    #   join((blue, red), (#abc, #def)) => blue, red, #abc, #def
+    #   join(10px, 20px) => 10px 20px
+    #   join(10px, 20px, comma) => 10px, 20px
+    #   join((blue, red), (#abc, #def), space) => blue red #abc #def
+    # @overload join($list1, $list2, $separator: auto)
+    #   @param $list1 [Sass::Script::Value::Base]
+    #   @param $list2 [Sass::Script::Value::Base]
+    #   @param $separator [Sass::Script::Value::String] The list separator to use.
+    #     If this is `comma` or `space`, that separator will be used. If this is
+    #     `auto` (the default), the separator is determined as explained above.
+    # @return [Sass::Script::Value::List]
+    def join(list1, list2, separator = identifier("auto"))
+      assert_type separator, :String, :separator
+      unless %w[auto space comma].include?(separator.value)
+        raise ArgumentError.new("Separator name must be space, comma, or auto")
+      end
+      sep = if separator.value == 'auto'
+              list1.separator || list2.separator || :space
+            else
+              separator.value.to_sym
+            end
+      list(list1.to_a + list2.to_a, sep)
+    end
+    declare :join, [:list1, :list2]
+    declare :join, [:list1, :list2, :separator]
+
+    # Appends a single value onto the end of a list.
+    #
+    # Unless the `$separator` argument is passed, if the list had only one item,
+    # the resulting list will be space-separated.
+    #
+    # @example
+    #   append(10px 20px, 30px) => 10px 20px 30px
+    #   append((blue, red), green) => blue, red, green
+    #   append(10px 20px, 30px 40px) => 10px 20px (30px 40px)
+    #   append(10px, 20px, comma) => 10px, 20px
+    #   append((blue, red), green, space) => blue red green
+    # @overload append($list, $val, $separator: auto)
+    #   @param $list [Sass::Script::Value::Base]
+    #   @param $val [Sass::Script::Value::Base]
+    #   @param $separator [Sass::Script::Value::String] The list separator to use.
+    #     If this is `comma` or `space`, that separator will be used. If this is
+    #     `auto` (the default), the separator is determined as explained above.
+    # @return [Sass::Script::Value::List]
+    def append(list, val, separator = identifier("auto"))
+      assert_type separator, :String, :separator
+      unless %w[auto space comma].include?(separator.value)
+        raise ArgumentError.new("Separator name must be space, comma, or auto")
+      end
+      sep = if separator.value == 'auto'
+              list.separator || :space
+            else
+              separator.value.to_sym
+            end
+      list(list.to_a + [val], sep)
+    end
+    declare :append, [:list, :val]
+    declare :append, [:list, :val, :separator]
+
+    # Combines several lists into a single multidimensional list. The nth value
+    # of the resulting list is a space separated list of the source lists' nth
+    # values.
+    #
+    # The length of the resulting list is the length of the
+    # shortest list.
+    #
+    # @example
+    #   zip(1px 1px 3px, solid dashed solid, red green blue)
+    #   => 1px solid red, 1px dashed green, 3px solid blue
+    # @overload zip($lists...)
+    #   @param $lists [[Sass::Script::Value::Base]]
+    # @return [Sass::Script::Value::List]
+    def zip(*lists)
+      length = nil
+      values = []
+      lists.each do |list|
+        array = list.to_a
+        values << array.dup
+        length = length.nil? ? array.length : [length, array.length].min
+      end
+      values.each do |value|
+        value.slice!(length)
+      end
+      new_list_value = values.first.zip(*values[1..-1])
+      list(new_list_value.map {|list| list(list, :space)}, :comma)
+    end
+    declare :zip, [], :var_args => true
+
+    # Returns the position of a value within a list. If the value isn't found,
+    # returns `null` instead.
+    #
+    # Note that unlike some languages, the first item in a Sass list is number
+    # 1, the second number 2, and so forth.
+    #
+    # This can return the position of a pair in a map as well.
+    #
+    # @example
+    #   index(1px solid red, solid) => 2
+    #   index(1px solid red, dashed) => null
+    #   index((width: 10px, height: 20px), (height 20px)) => 2
+    # @overload index($list, $value)
+    #   @param $list [Sass::Script::Value::Base]
+    #   @param $value [Sass::Script::Value::Base]
+    # @return [Sass::Script::Value::Number, Sass::Script::Value::Null] The
+    #   1-based index of `$value` in `$list`, or `null`
+    def index(list, value)
+      index = list.to_a.index {|e| e.eq(value).to_bool}
+      index ? number(index + 1) : null
+    end
+    declare :index, [:list, :value]
+
+    # Returns the separator of a list. If the list doesn't have a separator due
+    # to having fewer than two elements, returns `space`.
+    #
+    # @example
+    #   list-separator(1px 2px 3px) => space
+    #   list-separator(1px, 2px, 3px) => comma
+    #   list-separator('foo') => space
+    # @overload list_separator($list)
+    #   @param $list [Sass::Script::Value::Base]
+    # @return [Sass::Script::Value::String] `comma` or `space`
+    def list_separator(list)
+      identifier((list.separator || :space).to_s)
+    end
+    declare :separator, [:list]
+
+    # Returns the value in a map associated with the given key. If the map
+    # doesn't have such a key, returns `null`.
+    #
+    # @example
+    #   map-get(("foo": 1, "bar": 2), "foo") => 1
+    #   map-get(("foo": 1, "bar": 2), "bar") => 2
+    #   map-get(("foo": 1, "bar": 2), "baz") => null
+    # @overload map_get($map, $key)
+    #   @param $map [Sass::Script::Value::Map]
+    #   @param $key [Sass::Script::Value::Base]
+    # @return [Sass::Script::Value::Base] The value indexed by `$key`, or `null`
+    #   if the map doesn't contain the given key
+    # @raise [ArgumentError] if `$map` is not a map
+    def map_get(map, key)
+      assert_type map, :Map, :map
+      map.to_h[key] || null
+    end
+    declare :map_get, [:map, :key]
+
+    # Merges two maps together into a new map. Keys in `$map2` will take
+    # precedence over keys in `$map1`.
+    #
+    # This is the best way to add new values to a map.
+    #
+    # All keys in the returned map that also appear in `$map1` will have the
+    # same order as in `$map1`. New keys from `$map2` will be placed at the end
+    # of the map.
+    #
+    # @example
+    #   map-merge(("foo": 1), ("bar": 2)) => ("foo": 1, "bar": 2)
+    #   map-merge(("foo": 1, "bar": 2), ("bar": 3)) => ("foo": 1, "bar": 3)
+    # @overload map_merge($map1, $map2)
+    #   @param $map1 [Sass::Script::Value::Map]
+    #   @param $map2 [Sass::Script::Value::Map]
+    # @return [Sass::Script::Value::Map]
+    # @raise [ArgumentError] if either parameter is not a map
+    def map_merge(map1, map2)
+      assert_type map1, :Map, :map1
+      assert_type map2, :Map, :map2
+      map(map1.to_h.merge(map2.to_h))
+    end
+    declare :map_merge, [:map1, :map2]
+
+    # Returns a new map with keys removed.
+    #
+    # @example
+    #   map-remove(("foo": 1, "bar": 2), "bar") => ("foo": 1)
+    #   map-remove(("foo": 1, "bar": 2, "baz": 3), "bar", "baz") => ("foo": 1)
+    #   map-remove(("foo": 1, "bar": 2), "baz") => ("foo": 1, "bar": 2)
+    # @overload map_remove($map, $keys...)
+    #   @param $map  [Sass::Script::Value::Map]
+    #   @param $keys [[Sass::Script::Value::Base]]
+    # @return [Sass::Script::Value::Map]
+    # @raise [ArgumentError] if `$map` is not a map
+    def map_remove(map, *keys)
+      assert_type map, :Map, :map
+      hash = map.to_h.dup
+      hash.delete_if {|key, _| keys.include?(key)}
+      map(hash)
+    end
+    declare :map_remove, [:map, :key], :var_args => true
+
+    # Returns a list of all keys in a map.
+    #
+    # @example
+    #   map-keys(("foo": 1, "bar": 2)) => "foo", "bar"
+    # @overload map_keys($map)
+    #   @param $map [Map]
+    # @return [List] the list of keys, comma-separated
+    # @raise [ArgumentError] if `$map` is not a map
+    def map_keys(map)
+      assert_type map, :Map, :map
+      list(map.to_h.keys, :comma)
+    end
+    declare :map_keys, [:map]
+
+    # Returns a list of all values in a map. This list may include duplicate
+    # values, if multiple keys have the same value.
+    #
+    # @example
+    #   map-values(("foo": 1, "bar": 2)) => 1, 2
+    #   map-values(("foo": 1, "bar": 2, "baz": 1)) => 1, 2, 1
+    # @overload map_values($map)
+    #   @param $map [Map]
+    # @return [List] the list of values, comma-separated
+    # @raise [ArgumentError] if `$map` is not a map
+    def map_values(map)
+      assert_type map, :Map, :map
+      list(map.to_h.values, :comma)
+    end
+    declare :map_values, [:map]
+
+    # Returns whether a map has a value associated with a given key.
+    #
+    # @example
+    #   map-has-key(("foo": 1, "bar": 2), "foo") => true
+    #   map-has-key(("foo": 1, "bar": 2), "baz") => false
+    # @overload map_has_key($map, $key)
+    #   @param $map [Sass::Script::Value::Map]
+    #   @param $key [Sass::Script::Value::Base]
+    # @return [Sass::Script::Value::Bool]
+    # @raise [ArgumentError] if `$map` is not a map
+    def map_has_key(map, key)
+      assert_type map, :Map, :map
+      bool(map.to_h.has_key?(key))
+    end
+    declare :map_has_key, [:map, :key]
+
+    # Returns the map of named arguments passed to a function or mixin that
+    # takes a variable argument list. The argument names are strings, and they
+    # do not contain the leading `$`.
+    #
+    # @example
+    #   @mixin foo($args...) {
+    #     @debug keywords($args); //=> (arg1: val, arg2: val)
+    #   }
+    #
+    #   @include foo($arg1: val, $arg2: val);
+    # @overload keywords($args)
+    #   @param $args [Sass::Script::Value::ArgList]
+    # @return [Sass::Script::Value::Map]
+    # @raise [ArgumentError] if `$args` isn't a variable argument list
+    def keywords(args)
+      assert_type args, :ArgList, :args
+      map(Sass::Util.map_keys(args.keywords.as_stored) {|k| Sass::Script::Value::String.new(k)})
+    end
+    declare :keywords, [:args]
+
+    # Returns one of two values, depending on whether or not `$condition` is
+    # true. Just like in ` if`, all values other than `false` and `null` are
+    # considered to be true.
+    #
+    # @example
+    #   if(true, 1px, 2px) => 1px
+    #   if(false, 1px, 2px) => 2px
+    # @overload if($condition, $if-true, $if-false)
+    #   @param $condition [Sass::Script::Value::Base] Whether the `$if-true` or
+    #     `$if-false` will be returned
+    #   @param $if-true [Sass::Script::Tree::Node]
+    #   @param $if-false [Sass::Script::Tree::Node]
+    # @return [Sass::Script::Value::Base] `$if-true` or `$if-false`
+    def if(condition, if_true, if_false)
+      if condition.to_bool
+        perform(if_true)
+      else
+        perform(if_false)
+      end
+    end
+    declare :if, [:condition, :"&if_true", :"&if_false"]
+
+    # Returns a unique CSS identifier. The identifier is returned as an unquoted
+    # string. The identifier returned is only guaranteed to be unique within the
+    # scope of a single Sass run.
+    #
+    # @overload unique_id()
+    # @return [Sass::Script::Value::String]
+    def unique_id
+      generator = Sass::Script::Functions.random_number_generator
+      Thread.current[:sass_last_unique_id] ||= generator.rand(36**8)
+      # avoid the temptation of trying to guess the next unique value.
+      value = (Thread.current[:sass_last_unique_id] += (generator.rand(10) + 1))
+      # the u makes this a legal identifier if it would otherwise start with a number.
+      identifier("u" + value.to_s(36).rjust(8, '0'))
+    end
+    declare :unique_id, []
+
+    # Dynamically calls a function. This can call user-defined
+    # functions, built-in functions, or plain CSS functions. It will
+    # pass along all arguments, including keyword arguments, to the
+    # called function.
+    #
+    # @example
+    #   call(rgb, 10, 100, 255) => #0a64ff
+    #   call(scale-color, #0a64ff, $lightness: -10%) => #0058ef
+    #
+    #   $fn: nth;
+    #   call($fn, (a b c), 2) => b
+    #
+    # @overload call($name, $args...)
+    #   @param $name [String] The name of the function to call.
+    def call(name, *args)
+      assert_type name, :String, :name
+      kwargs = args.last.is_a?(Hash) ? args.pop : {}
+      funcall = Sass::Script::Tree::Funcall.new(
+        name.value,
+        args.map {|a| Sass::Script::Tree::Literal.new(a)},
+        Sass::Util.map_vals(kwargs) {|v| Sass::Script::Tree::Literal.new(v)},
+        nil,
+        nil)
+      funcall.options = options
+      perform(funcall)
+    end
+    declare :call, [:name], :var_args => true, :var_kwargs => true
+
+    # This function only exists as a workaround for IE7's [`content:
+    # counter` bug](http://jes.st/2013/ie7s-css-breaking-content-counter-bug/).
+    # It works identically to any other plain-CSS function, except it
+    # avoids adding spaces between the argument commas.
+    #
+    # @example
+    #   counter(item, ".") => counter(item,".")
+    # @overload counter($args...)
+    # @return [Sass::Script::Value::String]
+    def counter(*args)
+      identifier("counter(#{args.map {|a| a.to_s(options)}.join(',')})")
+    end
+    declare :counter, [], :var_args => true
+
+    # This function only exists as a workaround for IE7's [`content:
+    # counter` bug](http://jes.st/2013/ie7s-css-breaking-content-counter-bug/).
+    # It works identically to any other plain-CSS function, except it
+    # avoids adding spaces between the argument commas.
+    #
+    # @example
+    #   counters(item, ".") => counters(item,".")
+    # @overload counters($args...)
+    # @return [Sass::Script::Value::String]
+    def counters(*args)
+      identifier("counters(#{args.map {|a| a.to_s(options)}.join(',')})")
+    end
+    declare :counters, [], :var_args => true
+
+    # Check whether a variable with the given name exists in the current
+    # scope or in the global scope.
+    #
+    # @example
+    #   $a-false-value: false;
+    #   variable-exists(a-false-value) => true
+    #
+    #   variable-exists(nonexistent) => false
+    #
+    # @overload variable_exists($name)
+    #   @param $name [Sass::Script::Value::String] The name of the variable to
+    #     check. The name should not include the `$`.
+    # @return [Sass::Script::Value::Bool] Whether the variable is defined in
+    #   the current scope.
+    def variable_exists(name)
+      assert_type name, :String, :name
+      bool(environment.caller.var(name.value))
+    end
+    declare :variable_exists, [:name]
+
+    # Check whether a variable with the given name exists in the global
+    # scope (at the top level of the file).
+    #
+    # @example
+    #   $a-false-value: false;
+    #   global-variable-exists(a-false-value) => true
+    #
+    #   .foo {
+    #     $some-var: false;
+    #     @if global-variable-exists(some-var) { /* false, doesn't run */ }
+    #   }
+    #
+    # @overload global_variable_exists($name)
+    #   @param $name [Sass::Script::Value::String] The name of the variable to
+    #     check. The name should not include the `$`.
+    # @return [Sass::Script::Value::Bool] Whether the variable is defined in
+    #   the global scope.
+    def global_variable_exists(name)
+      assert_type name, :String, :name
+      bool(environment.global_env.var(name.value))
+    end
+    declare :global_variable_exists, [:name]
+
+    # Check whether a function with the given name exists.
+    #
+    # @example
+    #   function-exists(lighten) => true
+    #
+    #   @function myfunc { @return "something"; }
+    #   function-exists(myfunc) => true
+    #
+    # @overload function_exists($name)
+    #   @param name [Sass::Script::Value::String] The name of the function to
+    #     check.
+    # @return [Sass::Script::Value::Bool] Whether the function is defined.
+    def function_exists(name)
+      assert_type name, :String, :name
+      exists = Sass::Script::Functions.callable?(name.value.tr("-", "_"))
+      exists ||= environment.function(name.value)
+      bool(exists)
+    end
+    declare :function_exists, [:name]
+
+    # Check whether a mixin with the given name exists.
+    #
+    # @example
+    #   mixin-exists(nonexistent) => false
+    #
+    #   @mixin red-text { color: red; }
+    #   mixin-exists(red-text) => true
+    #
+    # @overload mixin_exists($name)
+    #   @param name [Sass::Script::Value::String] The name of the mixin to
+    #     check.
+    # @return [Sass::Script::Value::Bool] Whether the mixin is defined.
+    def mixin_exists(name)
+      assert_type name, :String, :name
+      bool(environment.mixin(name.value))
+    end
+    declare :mixin_exists, [:name]
+
+    # Return a string containing the value as its Sass representation.
+    #
+    # @overload inspect($value)
+    #   @param $value [Sass::Script::Value::Base] The value to inspect.
+    # @return [Sass::Script::Value::String] A representation of the value as
+    #   it would be written in Sass.
+    def inspect(value)
+      unquoted_string(value.to_sass)
+    end
+    declare :inspect, [:value]
+
+    # @overload random()
+    #   Return a decimal between 0 and 1, inclusive of 0 but not 1.
+    #   @return [Sass::Script::Value::Number] A decimal value.
+    # @overload random($limit)
+    #   Return an integer between 1 and `$limit`, inclusive of 1 but not `$limit`.
+    #   @param $limit [Sass::Script::Value::Number] The maximum of the random integer to be
+    #     returned, a positive integer.
+    #   @return [Sass::Script::Value::Number] An integer.
+    #   @raise [ArgumentError] if the `$limit` is not 1 or greater
+    def random(limit = nil)
+      generator = Sass::Script::Functions.random_number_generator
+      if limit
+        assert_integer limit, "limit"
+        if limit.value < 1
+          raise ArgumentError.new("$limit #{limit} must be greater than or equal to 1")
+        end
+        number(1 + generator.rand(limit.value))
+      else
+        number(generator.rand)
+      end
+    end
+    declare :random, []
+    declare :random, [:limit]
+
+    # Parses a user-provided selector into a list of lists of strings
+    # as returned by `&`.
+    #
+    # @example
+    #   selector-parse(".foo .bar, .baz .bang") => ('.foo' '.bar', '.baz' '.bang')
+    #
+    # @overload selector_parse($selector)
+    #   @param $selector [Sass::Script::Value::String, Sass::Script::Value::List]
+    #     The selector to parse. This can be either a string, a list of
+    #     strings, or a list of lists of strings as returned by `&`.
+    #   @return [Sass::Script::Value::List]
+    #     A list of lists of strings representing `$selector`. This is
+    #     in the same format as a selector returned by `&`.
+    def selector_parse(selector)
+      parse_selector(selector, :selector).to_sass_script
+    end
+    declare :selector_parse, [:selector]
+
+    # Return a new selector with all selectors in `$selectors` nested beneath
+    # one another as though they had been nested in the stylesheet as
+    # `$selector1 { $selector2 { ... } }`.
+    #
+    # Unlike most selector functions, `selector-nest` allows the
+    # parent selector `&` to be used in any selector but the first.
+    #
+    # @example
+    #   selector-nest(".foo", ".bar", ".baz") => .foo .bar .baz
+    #   selector-nest(".a .foo", ".b .bar") => .a .foo .b .bar
+    #   selector-nest(".foo", "&.bar") => .foo.bar
+    #
+    # @overload selector_nest($selectors...)
+    #   @param $selectors [[Sass::Script::Value::String, Sass::Script::Value::List]]
+    #     The selectors to nest. At least one selector must be passed. Each of
+    #     these can be either a string, a list of strings, or a list of lists of
+    #     strings as returned by `&`.
+    #   @return [Sass::Script::Value::List]
+    #     A list of lists of strings representing the result of nesting
+    #     `$selectors`. This is in the same format as a selector returned by
+    #     `&`.
+    def selector_nest(*selectors)
+      if selectors.empty?
+        raise ArgumentError.new("$selectors: At least one selector must be passed")
+      end
+
+      parsed = [parse_selector(selectors.first, :selectors)]
+      parsed += selectors[1..-1].map {|sel| parse_selector(sel, :selectors, !!:parse_parent_ref)}
+      parsed.inject {|result, child| child.resolve_parent_refs(result)}.to_sass_script
+    end
+    declare :selector_nest, [], :var_args => true
+
+    # Return a new selector with all selectors in `$selectors` appended one
+    # another as though they had been nested in the stylesheet as `$selector1 {
+    # &$selector2 { ... } }`.
+    #
+    # @example
+    #   selector-append(".foo", ".bar", ".baz") => .foo.bar.baz
+    #   selector-append(".a .foo", ".b .bar") => "a .foo.b .bar"
+    #   selector-append(".foo", "-suffix") => ".foo-suffix"
+    #
+    # @overload selector_append($selectors...)
+    #   @param $selectors [[Sass::Script::Value::String, Sass::Script::Value::List]]
+    #     The selectors to append. At least one selector must be passed. Each of
+    #     these can be either a string, a list of strings, or a list of lists of
+    #     strings as returned by `&`.
+    #   @return [Sass::Script::Value::List]
+    #     A list of lists of strings representing the result of appending
+    #     `$selectors`. This is in the same format as a selector returned by
+    #     `&`.
+    #   @raise [ArgumentError] if a selector could not be appended.
+    def selector_append(*selectors)
+      if selectors.empty?
+        raise ArgumentError.new("$selectors: At least one selector must be passed")
+      end
+
+      selectors.map {|sel| parse_selector(sel, :selectors)}.inject do |parent, child|
+        child.members.each do |seq|
+          sseq = seq.members.first
+          unless sseq.is_a?(Sass::Selector::SimpleSequence)
+            raise ArgumentError.new("Can't append \"#{seq}\" to \"#{parent}\"")
+          end
+
+          base = sseq.base
+          case base
+          when Sass::Selector::Universal
+            raise ArgumentError.new("Can't append \"#{seq}\" to \"#{parent}\"")
+          when Sass::Selector::Element
+            unless base.namespace.nil?
+              raise ArgumentError.new("Can't append \"#{seq}\" to \"#{parent}\"")
+            end
+            sseq.members[0] = Sass::Selector::Parent.new(base.name)
+          else
+            sseq.members.unshift Sass::Selector::Parent.new
+          end
+        end
+        child.resolve_parent_refs(parent)
+      end.to_sass_script
+    end
+    declare :selector_append, [], :var_args => true
+
+    # Returns a new version of `$selector` with `$extendee` extended
+    # with `$extender`. This works just like the result of
+    #
+    #     $selector { ... }
+    #     $extender { @extend $extendee }
+    #
+    # @example
+    #   selector-extend(".a .b", ".b", ".foo .bar") => .a .b, .a .foo .bar, .foo .a .bar
+    #
+    # @overload selector_extend($selector, $extendee, $extender)
+    #   @param $selector [Sass::Script::Value::String, Sass::Script::Value::List]
+    #     The selector within which `$extendee` is extended with
+    #     `$extender`. This can be either a string, a list of strings,
+    #     or a list of lists of strings as returned by `&`.
+    #   @param $extendee [Sass::Script::Value::String, Sass::Script::Value::List]
+    #     The selector being extended. This can be either a string, a
+    #     list of strings, or a list of lists of strings as returned
+    #     by `&`.
+    #   @param $extender [Sass::Script::Value::String, Sass::Script::Value::List]
+    #     The selector being injected into `$selector`. This can be
+    #     either a string, a list of strings, or a list of lists of
+    #     strings as returned by `&`.
+    #   @return [Sass::Script::Value::List]
+    #     A list of lists of strings representing the result of the
+    #     extension. This is in the same format as a selector returned
+    #     by `&`.
+    #   @raise [ArgumentError] if the extension fails
+    def selector_extend(selector, extendee, extender)
+      selector = parse_selector(selector, :selector)
+      extendee = parse_selector(extendee, :extendee)
+      extender = parse_selector(extender, :extender)
+
+      extends = Sass::Util::SubsetMap.new
+      begin
+        extender.populate_extends(extends, extendee)
+        selector.do_extend(extends).to_sass_script
+      rescue Sass::SyntaxError => e
+        raise ArgumentError.new(e.to_s)
+      end
+    end
+    declare :selector_extend, [:selector, :extendee, :extender]
+
+    # Replaces all instances of `$original` with `$replacement` in `$selector`
+    #
+    # This works by using ` extend` and throwing away the original
+    # selector. This means that it can be used to do very advanced
+    # replacements; see the examples below.
+    #
+    # @example
+    #   selector-replace(".foo .bar", ".bar", ".baz") => ".foo .baz"
+    #   selector-replace(".foo.bar.baz", ".foo.baz", ".qux") => ".bar.qux"
+    #
+    # @overload selector_replace($selector, $original, $replacement)
+    #   @param $selector [Sass::Script::Value::String, Sass::Script::Value::List]
+    #     The selector within which `$original` is replaced with
+    #     `$replacement`. This can be either a string, a list of
+    #     strings, or a list of lists of strings as returned by `&`.
+    #   @param $original [Sass::Script::Value::String, Sass::Script::Value::List]
+    #     The selector being replaced. This can be either a string, a
+    #     list of strings, or a list of lists of strings as returned
+    #     by `&`.
+    #   @param $replacement [Sass::Script::Value::String, Sass::Script::Value::List]
+    #     The selector that `$original` is being replaced with. This
+    #     can be either a string, a list of strings, or a list of
+    #     lists of strings as returned by `&`.
+    #   @return [Sass::Script::Value::List]
+    #     A list of lists of strings representing the result of the
+    #     extension. This is in the same format as a selector returned
+    #     by `&`.
+    #   @raise [ArgumentError] if the replacement fails
+    def selector_replace(selector, original, replacement)
+      selector = parse_selector(selector, :selector)
+      original = parse_selector(original, :original)
+      replacement = parse_selector(replacement, :replacement)
+
+      extends = Sass::Util::SubsetMap.new
+      begin
+        replacement.populate_extends(extends, original)
+        selector.do_extend(extends, [], !!:replace).to_sass_script
+      rescue Sass::SyntaxError => e
+        raise ArgumentError.new(e.to_s)
+      end
+    end
+    declare :selector_replace, [:selector, :original, :replacement]
+
+    # Unifies two selectors into a single selector that matches only
+    # elements matched by both input selectors. Returns `null` if
+    # there is no such selector.
+    #
+    # Like the selector unification done for ` extend`, this doesn't
+    # guarantee that the output selector will match *all* elements
+    # matched by both input selectors. For example, if `.a .b` is
+    # unified with `.x .y`, `.a .x .b.y, .x .a .b.y` will be returned,
+    # but `.a.x .b.y` will not. This avoids exponential output size
+    # while matching all elements that are likely to exist in
+    # practice.
+    #
+    # @example
+    #   selector-unify(".a", ".b") => .a.b
+    #   selector-unify(".a .b", ".x .y") => .a .x .b.y, .x .a .b.y
+    #   selector-unify(".a.b", ".b.c") => .a.b.c
+    #   selector-unify("#a", "#b") => null
+    #
+    # @overload selector_unify($selector1, $selector2)
+    #   @param $selector1 [Sass::Script::Value::String, Sass::Script::Value::List]
+    #     The first selector to be unified. This can be either a
+    #     string, a list of strings, or a list of lists of strings as
+    #     returned by `&`.
+    #   @param $selector2 [Sass::Script::Value::String, Sass::Script::Value::List]
+    #     The second selector to be unified. This can be either a
+    #     string, a list of strings, or a list of lists of strings as
+    #     returned by `&`.
+    #   @return [Sass::Script::Value::List, Sass::Script::Value::Null]
+    #     A list of lists of strings representing the result of the
+    #     unification, or null if no unification exists. This is in
+    #     the same format as a selector returned by `&`.
+    def selector_unify(selector1, selector2)
+      selector1 = parse_selector(selector1, :selector1)
+      selector2 = parse_selector(selector2, :selector2)
+      return null unless (unified = selector1.unify(selector2))
+      unified.to_sass_script
+    end
+    declare :selector_unify, [:selector1, :selector2]
+
+    # Returns the [simple
+    # selectors](http://dev.w3.org/csswg/selectors4/#simple) that
+    # comprise the compound selector `$selector`.
+    #
+    # Note that `$selector` **must be** a [compound
+    # selector](http://dev.w3.org/csswg/selectors4/#compound). That
+    # means it cannot contain commas or spaces. It also means that
+    # unlike other selector functions, this takes only strings, not
+    # lists.
+    #
+    # @example
+    #   simple-selectors(".foo.bar") => ".foo", ".bar"
+    #   simple-selectors(".foo.bar.baz") => ".foo", ".bar", ".baz"
+    #
+    # @overload simple_selectors($selector)
+    #   @param $selector [Sass::Script::Value::String]
+    #     The compound selector whose simple selectors will be extracted.
+    #   @return [Sass::Script::Value::List]
+    #     A list of simple selectors in the compound selector.
+    def simple_selectors(selector)
+      selector = parse_compound_selector(selector, :selector)
+      list(selector.members.map {|simple| unquoted_string(simple.to_s)}, :comma)
+    end
+    declare :simple_selectors, [:selector]
+
+    # Returns whether `$super` is a superselector of `$sub`. This means that
+    # `$super` matches all the elements that `$sub` matches, as well as possibly
+    # additional elements. In general, simpler selectors tend to be
+    # superselectors of more complex oned.
+    #
+    # @example
+    #   is-superselector(".foo", ".foo.bar") => true
+    #   is-superselector(".foo.bar", ".foo") => false
+    #   is-superselector(".bar", ".foo .bar") => true
+    #   is-superselector(".foo .bar", ".bar") => false
+    #
+    # @overload is_superselector($super, $sub)
+    #   @param $super [Sass::Script::Value::String, Sass::Script::Value::List]
+    #     The potential superselector. This can be either a string, a list of
+    #     strings, or a list of lists of strings as returned by `&`.
+    #   @param $sub [Sass::Script::Value::String, Sass::Script::Value::List]
+    #     The potential subselector. This can be either a string, a list of
+    #     strings, or a list of lists of strings as returned by `&`.
+    #   @return [Sass::Script::Value::Bool]
+    #     Whether `$selector1` is a superselector of `$selector2`.
+    def is_superselector(sup, sub)
+      sup = parse_selector(sup, :super)
+      sub = parse_selector(sub, :sub)
+      bool(sup.superselector?(sub))
+    end
+    declare :is_superselector, [:super, :sub]
+
+    private
+
+    # This method implements the pattern of transforming a numeric value into
+    # another numeric value with the same units.
+    # It yields a number to a block to perform the operation and return a number
+    def numeric_transformation(value)
+      assert_type value, :Number, :value
+      Sass::Script::Value::Number.new(
+        yield(value.value), value.numerator_units, value.denominator_units)
+    end
+
+    # @comment
+    #   rubocop:disable ParameterLists
+    def _adjust(color, amount, attr, range, op, units = "")
+      # rubocop:enable ParameterLists
+      assert_type color, :Color, :color
+      assert_type amount, :Number, :amount
+      Sass::Util.check_range('Amount', range, amount, units)
+
+      color.with(attr => color.send(attr).send(op, amount.value))
+    end
+
+    def check_alpha_unit(alpha, function)
+      return if alpha.unitless?
+
+      if alpha.is_unit?("%")
+        Sass::Util.sass_warn(<<WARNING)
+DEPRECATION WARNING: Passing a percentage as the alpha value to #{function}() will be
+interpreted differently in future versions of Sass. For now, use #{alpha.value} instead.
+WARNING
+      else
+        Sass::Util.sass_warn(<<WARNING)
+DEPRECATION WARNING: Passing a number with units as the alpha value to #{function}() is
+deprecated and will be an error in future versions of Sass. Use #{alpha.value} instead.
+WARNING
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/lexer.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/lexer.rb
new file mode 100644
index 0000000..1686501
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/lexer.rb
@@ -0,0 +1,453 @@
+require 'sass/scss/rx'
+
+module Sass
+  module Script
+    # The lexical analyzer for SassScript.
+    # It takes a raw string and converts it to individual tokens
+    # that are easier to parse.
+    class Lexer
+      include Sass::SCSS::RX
+
+      # A struct containing information about an individual token.
+      #
+      # `type`: \[`Symbol`\]
+      # : The type of token.
+      #
+      # `value`: \[`Object`\]
+      # : The Ruby object corresponding to the value of the token.
+      #
+      # `source_range`: \[`Sass::Source::Range`\]
+      # : The range in the source file in which the token appeared.
+      #
+      # `pos`: \[`Fixnum`\]
+      # : The scanner position at which the SassScript token appeared.
+      Token = Struct.new(:type, :value, :source_range, :pos)
+
+      # The line number of the lexer's current position.
+      #
+      # @return [Fixnum]
+      def line
+        return @line unless @tok
+        @tok.source_range.start_pos.line
+      end
+
+      # The number of bytes into the current line
+      # of the lexer's current position (1-based).
+      #
+      # @return [Fixnum]
+      def offset
+        return @offset unless @tok
+        @tok.source_range.start_pos.offset
+      end
+
+      # A hash from operator strings to the corresponding token types.
+      OPERATORS = {
+        '+' => :plus,
+        '-' => :minus,
+        '*' => :times,
+        '/' => :div,
+        '%' => :mod,
+        '=' => :single_eq,
+        ':' => :colon,
+        '(' => :lparen,
+        ')' => :rparen,
+        ',' => :comma,
+        'and' => :and,
+        'or' => :or,
+        'not' => :not,
+        '==' => :eq,
+        '!=' => :neq,
+        '>=' => :gte,
+        '<=' => :lte,
+        '>' => :gt,
+        '<' => :lt,
+        '#{' => :begin_interpolation,
+        '}' => :end_interpolation,
+        ';' => :semicolon,
+        '{' => :lcurly,
+        '...' => :splat,
+      }
+
+      OPERATORS_REVERSE = Sass::Util.map_hash(OPERATORS) {|k, v| [v, k]}
+
+      TOKEN_NAMES = Sass::Util.map_hash(OPERATORS_REVERSE) {|k, v| [k, v.inspect]}.merge(
+          :const => "variable (e.g. $foo)",
+          :ident => "identifier (e.g. middle)")
+
+      # A list of operator strings ordered with longer names first
+      # so that `>` and `<` don't clobber `>=` and `<=`.
+      OP_NAMES = OPERATORS.keys.sort_by {|o| -o.size}
+
+      # A sub-list of {OP_NAMES} that only includes operators
+      # with identifier names.
+      IDENT_OP_NAMES = OP_NAMES.select {|k, v| k =~ /^\w+/}
+
+      PARSEABLE_NUMBER = /(?:(\d*\.\d+)|(\d+))(?:[eE]([+-]?\d+))?(#{UNIT})?/
+
+      # A hash of regular expressions that are used for tokenizing.
+      REGULAR_EXPRESSIONS = {
+        :whitespace => /\s+/,
+        :comment => COMMENT,
+        :single_line_comment => SINGLE_LINE_COMMENT,
+        :variable => /(\$)(#{IDENT})/,
+        :ident => /(#{IDENT})(\()?/,
+        :number => PARSEABLE_NUMBER,
+        :unary_minus_number => /-#{PARSEABLE_NUMBER}/,
+        :color => HEXCOLOR,
+        :id => /##{IDENT}/,
+        :selector => /&/,
+        :ident_op => /(#{Regexp.union(*IDENT_OP_NAMES.map do |s|
+          Regexp.new(Regexp.escape(s) + "(?!#{NMCHAR}|\Z)")
+        end)})/,
+        :op => /(#{Regexp.union(*OP_NAMES)})/,
+      }
+
+      class << self
+        private
+
+        def string_re(open, close)
+          /#{open}((?:\\.|\#(?!\{)|[^#{close}\\#])*)(#{close}|#\{)/m
+        end
+      end
+
+      # A hash of regular expressions that are used for tokenizing strings.
+      #
+      # The key is a `[Symbol, Boolean]` pair.
+      # The symbol represents which style of quotation to use,
+      # while the boolean represents whether or not the string
+      # is following an interpolated segment.
+      STRING_REGULAR_EXPRESSIONS = {
+        :double => {
+          false => string_re('"', '"'),
+          true => string_re('', '"')
+        },
+        :single => {
+          false => string_re("'", "'"),
+          true => string_re('', "'")
+        },
+        :uri => {
+          false => /url\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
+          true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
+        },
+        # Defined in https://developer.mozilla.org/en/CSS/@-moz-document as a
+        # non-standard version of http://www.w3.org/TR/css3-conditional/
+        :url_prefix => {
+          false => /url-prefix\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
+          true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
+        },
+        :domain => {
+          false => /domain\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
+          true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
+        }
+      }
+
+      # @param str [String, StringScanner] The source text to lex
+      # @param line [Fixnum] The 1-based line on which the SassScript appears.
+      #   Used for error reporting and sourcemap building
+      # @param offset [Fixnum] The 1-based character (not byte) offset in the line in the source.
+      #   Used for error reporting and sourcemap building
+      # @param options [{Symbol => Object}] An options hash;
+      #   see {file:SASS_REFERENCE.md#sass_options the Sass options documentation}
+      def initialize(str, line, offset, options)
+        @scanner = str.is_a?(StringScanner) ? str : Sass::Util::MultibyteStringScanner.new(str)
+        @line = line
+        @offset = offset
+        @options = options
+        @interpolation_stack = []
+        @prev = nil
+      end
+
+      # Moves the lexer forward one token.
+      #
+      # @return [Token] The token that was moved past
+      def next
+        @tok ||= read_token
+        @tok, tok = nil, @tok
+        @prev = tok
+        tok
+      end
+
+      # Returns whether or not there's whitespace before the next token.
+      #
+      # @return [Boolean]
+      def whitespace?(tok = @tok)
+        if tok
+          @scanner.string[0...tok.pos] =~ /\s\Z/
+        else
+          @scanner string[ scanner pos, 1] =~ /^\s/ ||
+            @scanner string[ scanner pos - 1, 1] =~ /\s\Z/
+        end
+      end
+
+      # Returns the next token without moving the lexer forward.
+      #
+      # @return [Token] The next token
+      def peek
+        @tok ||= read_token
+      end
+
+      # Rewinds the underlying StringScanner
+      # to before the token returned by \{#peek}.
+      def unpeek!
+        if @tok
+          @scanner.pos = @tok.pos
+          @line = @tok.source_range.start_pos.line
+          @offset = @tok.source_range.start_pos.offset
+        end
+      end
+
+      # @return [Boolean] Whether or not there's more source text to lex.
+      def done?
+        whitespace unless after_interpolation? && @interpolation_stack.last
+        @scanner.eos? && @tok.nil?
+      end
+
+      # @return [Boolean] Whether or not the last token lexed was `:end_interpolation`.
+      def after_interpolation?
+        @prev && @prev.type == :end_interpolation
+      end
+
+      # Raise an error to the effect that `name` was expected in the input stream
+      # and wasn't found.
+      #
+      # This calls \{#unpeek!} to rewind the scanner to immediately after
+      # the last returned token.
+      #
+      # @param name [String] The name of the entity that was expected but not found
+      # @raise [Sass::SyntaxError]
+      def expected!(name)
+        unpeek!
+        Sass::SCSS::Parser.expected(@scanner, name, @line)
+      end
+
+      # Records all non-comment text the lexer consumes within the block
+      # and returns it as a string.
+      #
+      # @yield A block in which text is recorded
+      # @return [String]
+      def str
+        old_pos = @tok ? @tok.pos : @scanner.pos
+        yield
+        new_pos = @tok ? @tok.pos : @scanner.pos
+        @scanner.string[old_pos...new_pos]
+      end
+
+      private
+
+      def read_token
+        return if done?
+        start_pos = source_position
+        value = token
+        return unless value
+        type, val = value
+        Token.new(type, val, range(start_pos), @scanner.pos - @scanner.matched_size)
+      end
+
+      def whitespace
+        nil while scan(REGULAR_EXPRESSIONS[:whitespace]) ||
+          scan(REGULAR_EXPRESSIONS[:comment]) ||
+          scan(REGULAR_EXPRESSIONS[:single_line_comment])
+      end
+
+      def token
+        if after_interpolation? && (interp = @interpolation_stack.pop)
+          interp_type, interp_value = interp
+          if interp_type == :special_fun
+            return special_fun_body(interp_value)
+          else
+            raise "[BUG]: Unknown interp_type #{interp_type}" unless interp_type == :string
+            return string(interp_value, true)
+          end
+        end
+
+        variable || string(:double, false) || string(:single, false) || number || id || color ||
+          selector || string(:uri, false) || raw(UNICODERANGE) || special_fun || special_val ||
+          ident_op || ident || op
+      end
+
+      def variable
+        _variable(REGULAR_EXPRESSIONS[:variable])
+      end
+
+      def _variable(rx)
+        return unless scan(rx)
+
+        [:const, @scanner[2]]
+      end
+
+      def ident
+        return unless scan(REGULAR_EXPRESSIONS[:ident])
+        [ scanner[2] ? :funcall : :ident, @scanner[1]]
+      end
+
+      def string(re, open)
+        line, offset = @line, @offset
+        return unless scan(STRING_REGULAR_EXPRESSIONS[re][open])
+        if @scanner[0] =~ /([^\\]|^)\n/
+          filename = @options[:filename]
+          Sass::Util.sass_warn <<MESSAGE
+DEPRECATION WARNING on line #{line}, column #{offset}#{" of #{filename}" if filename}:
+Unescaped multiline strings are deprecated and will be removed in a future version of Sass.
+To include a newline in a string, use "\\a" or "\\a " as in CSS.
+MESSAGE
+        end
+
+        if @scanner[2] == '#{' # '
+          @scanner.pos -= 2 # Don't actually consume the #{
+          @offset -= 2
+          @interpolation_stack << [:string, re]
+        end
+        str =
+          if re == :uri
+            url = "#{'url(' unless open}#{ scanner[1]}#{')' unless @scanner[2] == '#{'}"
+            Script::Value::String.new(url)
+          else
+            Script::Value::String.new(Sass::Script::Value::String.value(@scanner[1]), :string)
+          end
+        [:string, str]
+      end
+
+      def number
+        # Handling unary minus is complicated by the fact that whitespace is an
+        # operator in SassScript. We want "1-2" to be parsed as "1 - 2", but we
+        # want "1 -2" to be parsed as "1 (-2)". To accomplish this, we only
+        # parse a unary minus as part of a number literal if there's whitespace
+        # before and not after it. Cases like "(-2)" are handled by the unary
+        # minus logic in the parser instead.
+        if @scanner.peek(1) == '-'
+          return if @scanner.pos == 0
+          unary_minus_allowed =
+            case @scanner string[ scanner pos - 1, 1]
+            when /\s/; true
+            when '/'; @scanner.pos != 1 && @scanner string[ scanner pos - 2, 1] == '*'
+            else; false
+            end
+
+          return unless unary_minus_allowed
+          return unless scan(REGULAR_EXPRESSIONS[:unary_minus_number])
+          minus = true
+        else
+          return unless scan(REGULAR_EXPRESSIONS[:number])
+          minus = false
+        end
+
+        value = (@scanner[1] ? @scanner[1].to_f : @scanner[2].to_i) * (minus ? -1 : 1)
+        value *= 10** scanner[3] to_i if @scanner[3]
+        script_number = Script::Value::Number.new(value, Array(@scanner[4]))
+        [:number, script_number]
+      end
+
+      def id
+        # Colors and ids are tough to tell apart, because they overlap but
+        # neither is a superset of the other. "#xyz" is an id but not a color,
+        # "#000" is a color but not an id, "#abc" is both, and "#0" is neither.
+        # We need to handle all these cases correctly.
+        #
+        # To do so, we first try to parse something as an id. If this works and
+        # the id is also a valid color, we return the color. Otherwise, we
+        # return the id. If it didn't parse as an id, we then try to parse it as
+        # a color. If *this* works, we return the color, and if it doesn't we
+        # give up and throw an error.
+        #
+        # IDs in properties are used in the Basic User Interface Module
+        # (http://www.w3.org/TR/css3-ui/).
+        return unless scan(REGULAR_EXPRESSIONS[:id])
+        if @scanner[0] =~ /^\#[0-9a-fA-F]+$/ && (@scanner[0].length == 4 || @scanner[0].length == 7)
+          return [:color, Script::Value::Color.from_hex(@scanner[0])]
+        end
+        [:ident, @scanner[0]]
+      end
+
+      def color
+        return unless @scanner.match?(REGULAR_EXPRESSIONS[:color])
+        return unless @scanner[0].length == 4 || @scanner[0].length == 7
+        script_color = Script::Value::Color.from_hex(scan(REGULAR_EXPRESSIONS[:color]))
+        [:color, script_color]
+      end
+
+      def selector
+        start_pos = source_position
+        return unless scan(REGULAR_EXPRESSIONS[:selector])
+        script_selector = Script::Tree::Selector.new
+        script_selector.source_range = range(start_pos)
+        [:selector, script_selector]
+      end
+
+      def special_fun
+        prefix = scan(/((-[\w-]+-)?(calc|element)|expression|progid:[a-z\.]*)\(/i)
+        return unless prefix
+        special_fun_body(1, prefix)
+      end
+
+      def special_fun_body(parens, prefix = nil)
+        str = prefix || ''
+        while (scanned = scan(/.*?([()]|\#\{)/m))
+          str << scanned
+          if scanned[-1] == ?(
+            parens += 1
+            next
+          elsif scanned[-1] == ?)
+            parens -= 1
+            next unless parens == 0
+          else
+            raise "[BUG] Unreachable" unless @scanner[1] == '#{' # '
+            str.slice!(-2..-1)
+            @scanner.pos -= 2 # Don't actually consume the #{
+            @offset -= 2
+            @interpolation_stack << [:special_fun, parens]
+          end
+
+          return [:special_fun, Sass::Script::Value::String.new(str)]
+        end
+
+        scan(/.*/)
+        expected!('")"')
+      end
+
+      def special_val
+        return unless scan(/!important/i)
+        [:string, Script::Value::String.new("!important")]
+      end
+
+      def ident_op
+        op = scan(REGULAR_EXPRESSIONS[:ident_op])
+        return unless op
+        [OPERATORS[op]]
+      end
+
+      def op
+        op = scan(REGULAR_EXPRESSIONS[:op])
+        return unless op
+        name = OPERATORS[op]
+        if name == :begin_interpolation && ! interpolation_stack empty?
+          [:string_interpolation]
+        else
+          [name]
+        end
+      end
+
+      def raw(rx)
+        val = scan(rx)
+        return unless val
+        [:raw, val]
+      end
+
+      def scan(re)
+        str = @scanner.scan(re)
+        return unless str
+        c = str.count("\n")
+        @line += c
+        @offset = (c == 0 ? @offset + str.size : str.size - str.rindex("\n"))
+        str
+      end
+
+      def range(start_pos, end_pos = source_position)
+        Sass::Source::Range.new(start_pos, end_pos, @options[:filename], @options[:importer])
+      end
+
+      def source_position
+        Sass::Source::Position.new(@line, @offset)
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/parser.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/parser.rb
new file mode 100644
index 0000000..7c50c9a
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/parser.rb
@@ -0,0 +1,638 @@
+require 'sass/script/lexer'
+
+module Sass
+  module Script
+    # The parser for SassScript.
+    # It parses a string of code into a tree of {Script::Tree::Node}s.
+    class Parser
+      # The line number of the parser's current position.
+      #
+      # @return [Fixnum]
+      def line
+        @lexer.line
+      end
+
+      # The column number of the parser's current position.
+      #
+      # @return [Fixnum]
+      def offset
+        @lexer.offset
+      end
+
+      # @param str [String, StringScanner] The source text to parse
+      # @param line [Fixnum] The line on which the SassScript appears.
+      #   Used for error reporting and sourcemap building
+      # @param offset [Fixnum] The character (not byte) offset where the script starts in the line.
+      #   Used for error reporting and sourcemap building
+      # @param options [{Symbol => Object}] An options hash;
+      #   see {file:SASS_REFERENCE.md#sass_options the Sass options documentation}
+      def initialize(str, line, offset, options = {})
+        @options = options
+        @lexer = lexer_class.new(str, line, offset, options)
+      end
+
+      # Parses a SassScript expression within an interpolated segment (`#{}`).
+      # This means that it stops when it comes across an unmatched `}`,
+      # which signals the end of an interpolated segment,
+      # it returns rather than throwing an error.
+      #
+      # @param warn_for_color [Boolean] Whether raw color values passed to
+      #   interoplation should cause a warning.
+      # @return [Script::Tree::Node] The root node of the parse tree
+      # @raise [Sass::SyntaxError] if the expression isn't valid SassScript
+      def parse_interpolated(warn_for_color = false)
+        # Start two characters back to compensate for #{
+        start_pos = Sass::Source::Position.new(line, offset - 2)
+        expr = assert_expr :expr
+        assert_tok :end_interpolation
+        expr = Sass::Script::Tree::Interpolation.new(
+          nil, expr, nil, !:wb, !:wa, !:originally_text, warn_for_color)
+        expr.options = @options
+        node(expr, start_pos)
+      rescue Sass::SyntaxError => e
+        e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
+        raise e
+      end
+
+      # Parses a SassScript expression.
+      #
+      # @return [Script::Tree::Node] The root node of the parse tree
+      # @raise [Sass::SyntaxError] if the expression isn't valid SassScript
+      def parse
+        expr = assert_expr :expr
+        assert_done
+        expr.options = @options
+        expr
+      rescue Sass::SyntaxError => e
+        e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
+        raise e
+      end
+
+      # Parses a SassScript expression,
+      # ending it when it encounters one of the given identifier tokens.
+      #
+      # @param tokens [#include?(String)] A set of strings that delimit the expression.
+      # @return [Script::Tree::Node] The root node of the parse tree
+      # @raise [Sass::SyntaxError] if the expression isn't valid SassScript
+      def parse_until(tokens)
+        @stop_at = tokens
+        expr = assert_expr :expr
+        assert_done
+        expr.options = @options
+        expr
+      rescue Sass::SyntaxError => e
+        e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
+        raise e
+      end
+
+      # Parses the argument list for a mixin include.
+      #
+      # @return [(Array<Script::Tree::Node>,
+      #          {String => Script::Tree::Node},
+      #          Script::Tree::Node,
+      #          Script::Tree::Node)]
+      #   The root nodes of the positional arguments, keyword arguments, and
+      #   splat argument(s). Keyword arguments are in a hash from names to values.
+      # @raise [Sass::SyntaxError] if the argument list isn't valid SassScript
+      def parse_mixin_include_arglist
+        args, keywords = [], {}
+        if try_tok(:lparen)
+          args, keywords, splat, kwarg_splat = mixin_arglist
+          assert_tok(:rparen)
+        end
+        assert_done
+
+        args.each {|a| a.options = @options}
+        keywords.each {|k, v| v.options = @options}
+        splat.options = @options if splat
+        kwarg_splat.options = @options if kwarg_splat
+        return args, keywords, splat, kwarg_splat
+      rescue Sass::SyntaxError => e
+        e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
+        raise e
+      end
+
+      # Parses the argument list for a mixin definition.
+      #
+      # @return [(Array<Script::Tree::Node>, Script::Tree::Node)]
+      #   The root nodes of the arguments, and the splat argument.
+      # @raise [Sass::SyntaxError] if the argument list isn't valid SassScript
+      def parse_mixin_definition_arglist
+        args, splat = defn_arglist!(false)
+        assert_done
+
+        args.each do |k, v|
+          k.options = @options
+          v.options = @options if v
+        end
+        splat.options = @options if splat
+        return args, splat
+      rescue Sass::SyntaxError => e
+        e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
+        raise e
+      end
+
+      # Parses the argument list for a function definition.
+      #
+      # @return [(Array<Script::Tree::Node>, Script::Tree::Node)]
+      #   The root nodes of the arguments, and the splat argument.
+      # @raise [Sass::SyntaxError] if the argument list isn't valid SassScript
+      def parse_function_definition_arglist
+        args, splat = defn_arglist!(true)
+        assert_done
+
+        args.each do |k, v|
+          k.options = @options
+          v.options = @options if v
+        end
+        splat.options = @options if splat
+        return args, splat
+      rescue Sass::SyntaxError => e
+        e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
+        raise e
+      end
+
+      # Parse a single string value, possibly containing interpolation.
+      # Doesn't assert that the scanner is finished after parsing.
+      #
+      # @return [Script::Tree::Node] The root node of the parse tree.
+      # @raise [Sass::SyntaxError] if the string isn't valid SassScript
+      def parse_string
+        unless (peek = @lexer.peek) &&
+            (peek.type == :string ||
+            (peek.type == :funcall && peek.value.downcase == 'url'))
+          lexer.expected!("string")
+        end
+
+        expr = assert_expr :funcall
+        expr.options = @options
+        @lexer.unpeek!
+        expr
+      rescue Sass::SyntaxError => e
+        e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
+        raise e
+      end
+
+      # Parses a SassScript expression.
+      #
+      # @overload parse(str, line, offset, filename = nil)
+      # @return [Script::Tree::Node] The root node of the parse tree
+      # @see Parser#initialize
+      # @see Parser#parse
+      def self.parse(*args)
+        new(*args).parse
+      end
+
+      PRECEDENCE = [
+        :comma, :single_eq, :space, :or, :and,
+        [:eq, :neq],
+        [:gt, :gte, :lt, :lte],
+        [:plus, :minus],
+        [:times, :div, :mod],
+      ]
+
+      ASSOCIATIVE = [:plus, :times]
+
+      class << self
+        # Returns an integer representing the precedence
+        # of the given operator.
+        # A lower integer indicates a looser binding.
+        #
+        # @private
+        def precedence_of(op)
+          PRECEDENCE.each_with_index do |e, i|
+            return i if Array(e).include?(op)
+          end
+          raise "[BUG] Unknown operator #{op.inspect}"
+        end
+
+        # Returns whether or not the given operation is associative.
+        #
+        # @private
+        def associative?(op)
+          ASSOCIATIVE.include?(op)
+        end
+
+        private
+
+        # Defines a simple left-associative production.
+        # name is the name of the production,
+        # sub is the name of the production beneath it,
+        # and ops is a list of operators for this precedence level
+        def production(name, sub, *ops)
+          class_eval <<RUBY, __FILE__, __LINE__ + 1
+            def #{name}
+              interp = try_ops_after_interp(#{ops.inspect}, #{name.inspect})
+              return interp if interp
+              return unless e = #{sub}
+              while tok = try_toks(#{ops.map {|o| o.inspect}.join(', ')})
+                if interp = try_op_before_interp(tok, e)
+                  other_interp = try_ops_after_interp(#{ops.inspect}, #{name.inspect}, interp)
+                  return interp unless other_interp
+                  return other_interp
+                end
+
+                e = node(Tree::Operation.new(e, assert_expr(#{sub.inspect}), tok.type),
+                         e.source_range.start_pos)
+              end
+              e
+            end
+RUBY
+        end
+
+        def unary(op, sub)
+          class_eval <<RUBY, __FILE__, __LINE__ + 1
+            def unary_#{op}
+              return #{sub} unless tok = try_tok(:#{op})
+              interp = try_op_before_interp(tok)
+              return interp if interp
+              start_pos = source_position
+              node(Tree::UnaryOperation.new(assert_expr(:unary_#{op}), :#{op}), start_pos)
+            end
+RUBY
+        end
+      end
+
+      private
+
+      def source_position
+        Sass::Source::Position.new(line, offset)
+      end
+
+      def range(start_pos, end_pos = source_position)
+        Sass::Source::Range.new(start_pos, end_pos, @options[:filename], @options[:importer])
+      end
+
+      # @private
+      def lexer_class; Lexer; end
+
+      def map
+        start_pos = source_position
+        e = interpolation
+        return unless e
+        return list e, start_pos unless @lexer.peek && @lexer.peek.type == :colon
+
+        pair = map_pair(e)
+        map = node(Sass::Script::Tree::MapLiteral.new([pair]), start_pos)
+        while try_tok(:comma)
+          pair = map_pair
+          return map unless pair
+          map.pairs << pair
+        end
+        map
+      end
+
+      def map_pair(key = nil)
+        return unless key ||= interpolation
+        assert_tok :colon
+        return key, assert_expr(:interpolation)
+      end
+
+      def expr
+        start_pos = source_position
+        e = interpolation
+        return unless e
+        list e, start_pos
+      end
+
+      def list(first, start_pos)
+        return first unless @lexer.peek && @lexer.peek.type == :comma
+
+        list = node(Sass::Script::Tree::ListLiteral.new([first], :comma), start_pos)
+        while (tok = try_tok(:comma))
+          element_before_interp = list.elements.length == 1 ? list.elements.first : list
+          if (interp = try_op_before_interp(tok, element_before_interp))
+            other_interp = try_ops_after_interp([:comma], :expr, interp)
+            return interp unless other_interp
+            return other_interp
+          end
+          return list unless (e = interpolation)
+          list.elements << e
+        end
+        list
+      end
+
+      production :equals, :interpolation, :single_eq
+
+      def try_op_before_interp(op, prev = nil)
+        return unless @lexer.peek && @lexer.peek.type == :begin_interpolation
+        wb = @lexer.whitespace?(op)
+        str = literal_node(Script::Value::String.new(Lexer::OPERATORS_REVERSE[op.type]),
+                           op.source_range)
+        interp = node(
+          Script::Tree::Interpolation.new(prev, str, nil, wb, !:wa, :originally_text),
+          (prev || str).source_range.start_pos)
+        interpolation(interp)
+      end
+
+      def try_ops_after_interp(ops, name, prev = nil)
+        return unless @lexer.after_interpolation?
+        op = try_toks(*ops)
+        return unless op
+        interp = try_op_before_interp(op, prev)
+        return interp if interp
+
+        wa = @lexer.whitespace?
+        str = literal_node(Script::Value::String.new(Lexer::OPERATORS_REVERSE[op.type]),
+                           op.source_range)
+        str.line = @lexer.line
+        interp = node(
+          Script::Tree::Interpolation.new(prev, str, assert_expr(name), !:wb, wa, :originally_text),
+          (prev || str).source_range.start_pos)
+        interp
+      end
+
+      def interpolation(first = space)
+        e = first
+        while (interp = try_tok(:begin_interpolation))
+          wb = @lexer.whitespace?(interp)
+          mid = assert_expr :expr
+          assert_tok :end_interpolation
+          wa = @lexer.whitespace?
+          e = node(
+            Script::Tree::Interpolation.new(e, mid, space, wb, wa),
+            (e || mid).source_range.start_pos)
+        end
+        e
+      end
+
+      def space
+        start_pos = source_position
+        e = or_expr
+        return unless e
+        arr = [e]
+        while (e = or_expr)
+          arr << e
+        end
+        if arr.size == 1
+          arr.first
+        else
+          node(Sass::Script::Tree::ListLiteral.new(arr, :space), start_pos)
+        end
+      end
+
+      production :or_expr, :and_expr, :or
+      production :and_expr, :eq_or_neq, :and
+      production :eq_or_neq, :relational, :eq, :neq
+      production :relational, :plus_or_minus, :gt, :gte, :lt, :lte
+      production :plus_or_minus, :times_div_or_mod, :plus, :minus
+      production :times_div_or_mod, :unary_plus, :times, :div, :mod
+
+      unary :plus, :unary_minus
+      unary :minus, :unary_div
+      unary :div, :unary_not # For strings, so /foo/bar works
+      unary :not, :ident
+
+      def ident
+        return funcall unless @lexer.peek && @lexer.peek.type == :ident
+        return if @stop_at && @stop_at.include?(@lexer.peek.value)
+
+        name = @lexer.next
+        if (color = Sass::Script::Value::Color::COLOR_NAMES[name.value.downcase])
+          literal_node(Sass::Script::Value::Color.new(color, name.value), name.source_range)
+        elsif name.value == "true"
+          literal_node(Sass::Script::Value::Bool.new(true), name.source_range)
+        elsif name.value == "false"
+          literal_node(Sass::Script::Value::Bool.new(false), name.source_range)
+        elsif name.value == "null"
+          literal_node(Sass::Script::Value::Null.new, name.source_range)
+        else
+          literal_node(Sass::Script::Value::String.new(name.value, :identifier), name.source_range)
+        end
+      end
+
+      def funcall
+        tok = try_tok(:funcall)
+        return raw unless tok
+        args, keywords, splat, kwarg_splat = fn_arglist
+        assert_tok(:rparen)
+        node(Script::Tree::Funcall.new(tok.value, args, keywords, splat, kwarg_splat),
+          tok.source_range.start_pos, source_position)
+      end
+
+      def defn_arglist!(must_have_parens)
+        if must_have_parens
+          assert_tok(:lparen)
+        else
+          return [], nil unless try_tok(:lparen)
+        end
+        return [], nil if try_tok(:rparen)
+
+        res = []
+        splat = nil
+        must_have_default = false
+        loop do
+          c = assert_tok(:const)
+          var = node(Script::Tree::Variable.new(c.value), c.source_range)
+          if try_tok(:colon)
+            val = assert_expr(:space)
+            must_have_default = true
+          elsif try_tok(:splat)
+            splat = var
+            break
+          elsif must_have_default
+            raise SyntaxError.new(
+              "Required argument #{var.inspect} must come before any optional arguments.")
+          end
+          res << [var, val]
+          break unless try_tok(:comma)
+        end
+        assert_tok(:rparen)
+        return res, splat
+      end
+
+      def fn_arglist
+        arglist(:equals, "function argument")
+      end
+
+      def mixin_arglist
+        arglist(:interpolation, "mixin argument")
+      end
+
+      def arglist(subexpr, description)
+        args = []
+        keywords = Sass::Util::NormalizedMap.new
+        e = send(subexpr)
+
+        return [args, keywords] unless e
+
+        splat = nil
+        loop do
+          if @lexer.peek && @lexer.peek.type == :colon
+            name = e
+            @lexer.expected!("comma") unless name.is_a?(Tree::Variable)
+            assert_tok(:colon)
+            value = assert_expr(subexpr, description)
+
+            if keywords[name.name]
+              raise SyntaxError.new("Keyword argument \"#{name.to_sass}\" passed more than once")
+            end
+
+            keywords[name.name] = value
+          else
+            if try_tok(:splat)
+              return args, keywords, splat, e if splat
+              splat, e = e, nil
+            elsif splat
+              raise SyntaxError.new("Only keyword arguments may follow variable arguments (...).")
+            elsif !keywords.empty?
+              raise SyntaxError.new("Positional arguments must come before keyword arguments.")
+            end
+
+            args << e if e
+          end
+
+          return args, keywords, splat unless try_tok(:comma)
+          e = assert_expr(subexpr, description)
+        end
+      end
+
+      def raw
+        tok = try_tok(:raw)
+        return special_fun unless tok
+        literal_node(Script::Value::String.new(tok.value), tok.source_range)
+      end
+
+      def special_fun
+        first = try_tok(:special_fun)
+        return paren unless first
+        str = literal_node(first.value, first.source_range)
+        return str unless try_tok(:string_interpolation)
+        mid = assert_expr :expr
+        assert_tok :end_interpolation
+        last = assert_expr(:special_fun)
+        node(Tree::Interpolation.new(str, mid, last, false, false),
+            first.source_range.start_pos)
+      end
+
+      def paren
+        return variable unless try_tok(:lparen)
+        was_in_parens = @in_parens
+        @in_parens = true
+        start_pos = source_position
+        e = map
+        end_pos = source_position
+        assert_tok(:rparen)
+        return e || node(Sass::Script::Tree::ListLiteral.new([], nil), start_pos, end_pos)
+      ensure
+        @in_parens = was_in_parens
+      end
+
+      def variable
+        start_pos = source_position
+        c = try_tok(:const)
+        return string unless c
+        node(Tree::Variable.new(*c.value), start_pos)
+      end
+
+      def string
+        first = try_tok(:string)
+        return number unless first
+        str = literal_node(first.value, first.source_range)
+        return str unless try_tok(:string_interpolation)
+        mid = assert_expr :expr
+        assert_tok :end_interpolation
+        last = assert_expr(:string)
+        node(Tree::StringInterpolation.new(str, mid, last), first.source_range.start_pos)
+      end
+
+      def number
+        tok = try_tok(:number)
+        return selector unless tok
+        num = tok.value
+        num.original = num.to_s unless @in_parens
+        literal_node(num, tok.source_range.start_pos)
+      end
+
+      def selector
+        tok = try_tok(:selector)
+        return literal unless tok
+        node(tok.value, tok.source_range.start_pos)
+      end
+
+      def literal
+        t = try_tok(:color)
+        return literal_node(t.value, t.source_range) if t
+      end
+
+      # It would be possible to have unified #assert and #try methods,
+      # but detecting the method/token difference turns out to be quite expensive.
+
+      EXPR_NAMES = {
+        :string => "string",
+        :default => "expression (e.g. 1px, bold)",
+        :mixin_arglist => "mixin argument",
+        :fn_arglist => "function argument",
+        :splat => "...",
+        :special_fun => '")"',
+      }
+
+      def assert_expr(name, expected = nil)
+        e = send(name)
+        return e if e
+        @lexer.expected!(expected || EXPR_NAMES[name] || EXPR_NAMES[:default])
+      end
+
+      def assert_tok(name)
+        # Avoids an array allocation caused by argument globbing in assert_toks.
+        t = try_tok(name)
+        return t if t
+        @lexer.expected!(Lexer::TOKEN_NAMES[name] || name.to_s)
+      end
+
+      def assert_toks(*names)
+        t = try_toks(*names)
+        return t if t
+        @lexer.expected!(names.map {|tok| Lexer::TOKEN_NAMES[tok] || tok}.join(" or "))
+      end
+
+      def try_tok(name)
+        # Avoids an array allocation caused by argument globbing in the try_toks method.
+        peeked = @lexer.peek
+        peeked && name == peeked.type && @lexer.next
+      end
+
+      def try_toks(*names)
+        peeked = @lexer.peek
+        peeked && names.include?(peeked.type) && @lexer.next
+      end
+
+      def assert_done
+        return if @lexer.done?
+        @lexer.expected!(EXPR_NAMES[:default])
+      end
+
+      # @overload node(value, source_range)
+      #   @param value [Sass::Script::Value::Base]
+      #   @param source_range [Sass::Source::Range]
+      # @overload node(value, start_pos, end_pos = source_position)
+      #   @param value [Sass::Script::Value::Base]
+      #   @param start_pos [Sass::Source::Position]
+      #   @param end_pos [Sass::Source::Position]
+      def literal_node(value, source_range_or_start_pos, end_pos = source_position)
+        node(Sass::Script::Tree::Literal.new(value), source_range_or_start_pos, end_pos)
+      end
+
+      # @overload node(node, source_range)
+      #   @param node [Sass::Script::Tree::Node]
+      #   @param source_range [Sass::Source::Range]
+      # @overload node(node, start_pos, end_pos = source_position)
+      #   @param node [Sass::Script::Tree::Node]
+      #   @param start_pos [Sass::Source::Position]
+      #   @param end_pos [Sass::Source::Position]
+      def node(node, source_range_or_start_pos, end_pos = source_position)
+        source_range =
+          if source_range_or_start_pos.is_a?(Sass::Source::Range)
+            source_range_or_start_pos
+          else
+            range(source_range_or_start_pos, end_pos)
+          end
+
+        node.line = source_range.start_pos.line
+        node.source_range = source_range
+        node.filename = @options[:filename]
+        node
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/tree.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/tree.rb
new file mode 100644
index 0000000..8bd4686
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/tree.rb
@@ -0,0 +1,16 @@
+# The module containing nodes in the SassScript parse tree. These nodes are
+# all subclasses of {Sass::Script::Tree::Node}.
+module Sass::Script::Tree
+end
+
+require 'sass/script/tree/node'
+require 'sass/script/tree/variable'
+require 'sass/script/tree/funcall'
+require 'sass/script/tree/operation'
+require 'sass/script/tree/unary_operation'
+require 'sass/script/tree/interpolation'
+require 'sass/script/tree/string_interpolation'
+require 'sass/script/tree/literal'
+require 'sass/script/tree/list_literal'
+require 'sass/script/tree/map_literal'
+require 'sass/script/tree/selector'
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/tree/funcall.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/tree/funcall.rb
new file mode 100644
index 0000000..8a590dc
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/tree/funcall.rb
@@ -0,0 +1,306 @@
+require 'sass/script/functions'
+require 'sass/util/normalized_map'
+
+module Sass::Script::Tree
+  # A SassScript parse node representing a function call.
+  #
+  # A function call either calls one of the functions in
+  # {Sass::Script::Functions}, or if no function with the given name exists it
+  # returns a string representation of the function call.
+  class Funcall < Node
+    # The name of the function.
+    #
+    # @return [String]
+    attr_reader :name
+
+    # The arguments to the function.
+    #
+    # @return [Array<Node>]
+    attr_reader :args
+
+    # The keyword arguments to the function.
+    #
+    # @return [Sass::Util::NormalizedMap<Node>]
+    attr_reader :keywords
+
+    # The first splat argument for this function, if one exists.
+    #
+    # This could be a list of positional arguments, a map of keyword
+    # arguments, or an arglist containing both.
+    #
+    # @return [Node?]
+    attr_accessor :splat
+
+    # The second splat argument for this function, if one exists.
+    #
+    # If this exists, it's always a map of keyword arguments, and
+    # \{#splat} is always either a list or an arglist.
+    #
+    # @return [Node?]
+    attr_accessor :kwarg_splat
+
+    # @param name [String] See \{#name}
+    # @param args [Array<Node>] See \{#args}
+    # @param keywords [Sass::Util::NormalizedMap<Node>] See \{#keywords}
+    # @param splat [Node] See \{#splat}
+    # @param kwarg_splat [Node] See \{#kwarg_splat}
+    def initialize(name, args, keywords, splat, kwarg_splat)
+      @name = name
+      @args = args
+      @keywords = keywords
+      @splat = splat
+      @kwarg_splat = kwarg_splat
+      super()
+    end
+
+    # @return [String] A string representation of the function call
+    def inspect
+      args = @args.map {|a| a.inspect}.join(', ')
+      keywords = Sass::Util.hash_to_a(@keywords.as_stored).
+          map {|k, v| "$#{k}: #{v.inspect}"}.join(', ')
+      # rubocop:disable RedundantSelf
+      if self.splat
+        splat = args.empty? && keywords.empty? ? "" : ", "
+        splat = "#{splat}#{self.splat.inspect}..."
+        splat = "#{splat}, #{kwarg_splat.inspect}..." if kwarg_splat
+      end
+      # rubocop:enable RedundantSelf
+      "#{name}(#{args}#{', ' unless args.empty? || keywords.empty?}#{keywords}#{splat})"
+    end
+
+    # @see Node#to_sass
+    def to_sass(opts = {})
+      arg_to_sass = lambda do |arg|
+        sass = arg.to_sass(opts)
+        sass = "(#{sass})" if arg.is_a?(Sass::Script::Tree::ListLiteral) && arg.separator == :comma
+        sass
+      end
+
+      args = @args.map(&arg_to_sass)
+      keywords = Sass::Util.hash_to_a(@keywords.as_stored).
+        map {|k, v| "$#{dasherize(k, opts)}: #{arg_to_sass[v]}"}
+
+      # rubocop:disable RedundantSelf
+      if self.splat
+        splat = "#{arg_to_sass[self.splat]}..."
+        kwarg_splat = "#{arg_to_sass[self.kwarg_splat]}..." if self.kwarg_splat
+      end
+      # rubocop:enable RedundantSelf
+
+      arglist = [args, splat, keywords, kwarg_splat].flatten.compact.join(', ')
+      "#{dasherize(name, opts)}(#{arglist})"
+    end
+
+    # Returns the arguments to the function.
+    #
+    # @return [Array<Node>]
+    # @see Node#children
+    def children
+      res = @args + @keywords.values
+      res << @splat if @splat
+      res << @kwarg_splat if @kwarg_splat
+      res
+    end
+
+    # @see Node#deep_copy
+    def deep_copy
+      node = dup
+      node.instance_variable_set('@args', args.map {|a| a.deep_copy})
+      copied_keywords = Sass::Util::NormalizedMap.new
+      @keywords.as_stored.each {|k, v| copied_keywords[k] = v.deep_copy}
+      node.instance_variable_set('@keywords', copied_keywords)
+      node
+    end
+
+    protected
+
+    # Evaluates the function call.
+    #
+    # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
+    # @return [Sass::Script::Value] The SassScript object that is the value of the function call
+    # @raise [Sass::SyntaxError] if the function call raises an ArgumentError
+    def _perform(environment)
+      args = Sass::Util.enum_with_index(@args).
+        map {|a, i| perform_arg(a, environment, signature && signature.args[i])}
+      keywords = Sass::Util.map_hash(@keywords) do |k, v|
+        [k, perform_arg(v, environment, k.tr('-', '_'))]
+      end
+      splat = Sass::Tree::Visitors::Perform.perform_splat(
+        @splat, keywords, @kwarg_splat, environment)
+      if (fn = environment.function(@name))
+        return without_original(perform_sass_fn(fn, args, splat, environment))
+      end
+
+      args = construct_ruby_args(ruby_name, args, splat, environment)
+
+      if Sass::Script::Functions.callable?(ruby_name)
+        local_environment = Sass::Environment.new(environment.global_env, environment.options)
+        local_environment.caller = Sass::ReadOnlyEnvironment.new(environment, environment.options)
+        result = opts(Sass::Script::Functions::EvaluationContext.new(
+          local_environment).send(ruby_name, *args))
+        without_original(result)
+      else
+        opts(to_literal(args))
+      end
+    rescue ArgumentError => e
+      reformat_argument_error(e)
+    end
+
+    # Compass historically overrode this before it changed name to {Funcall#to_value}.
+    # We should get rid of it in the future.
+    def to_literal(args)
+      to_value(args)
+    end
+
+    # This method is factored out from `_perform` so that compass can override
+    # it with a cross-browser implementation for functions that require vendor prefixes
+    # in the generated css.
+    def to_value(args)
+      Sass::Script::Value::String.new("#{name}(#{args.join(', ')})")
+    end
+
+    private
+
+    def ruby_name
+      @ruby_name ||= @name.tr('-', '_')
+    end
+
+    def perform_arg(argument, environment, name)
+      return argument if signature && signature.delayed_args.include?(name)
+      argument.perform(environment)
+    end
+
+    def signature
+      @signature ||= Sass::Script::Functions.signature(name.to_sym, @args.size, @keywords.size)
+    end
+
+    def without_original(value)
+      return value unless value.is_a?(Sass::Script::Value::Number)
+      value = value.dup
+      value.original = nil
+      value
+    end
+
+    def construct_ruby_args(name, args, splat, environment)
+      args += splat.to_a if splat
+
+      # All keywords are contained in splat.keywords for consistency,
+      # even if there were no splats passed in.
+      old_keywords_accessed = splat.keywords_accessed
+      keywords = splat.keywords
+      splat.keywords_accessed = old_keywords_accessed
+
+      unless (signature = Sass::Script::Functions.signature(name.to_sym, args.size, keywords.size))
+        return args if keywords.empty?
+        raise Sass::SyntaxError.new("Function #{name} doesn't support keyword arguments")
+      end
+
+      # If the user passes more non-keyword args than the function expects,
+      # but it does expect keyword args, Ruby's arg handling won't raise an error.
+      # Since we don't want to make functions think about this,
+      # we'll handle it for them here.
+      if signature.var_kwargs && !signature.var_args && args.size > signature.args.size
+        raise Sass::SyntaxError.new(
+          "#{args[signature.args.size].inspect} is not a keyword argument for `#{name}'")
+      elsif keywords.empty?
+        return args
+      end
+
+      argnames = signature.args[args.size..-1] || []
+      deprecated_argnames = (signature.deprecated && signature.deprecated[args.size..-1]) || []
+      args = args + argnames.zip(deprecated_argnames).map do |(argname, deprecated_argname)|
+        if keywords.has_key?(argname)
+          keywords.delete(argname)
+        elsif deprecated_argname && keywords.has_key?(deprecated_argname)
+          deprecated_argname = keywords.denormalize(deprecated_argname)
+          Sass::Util.sass_warn("DEPRECATION WARNING: The `$#{deprecated_argname}' argument for " +
+            "`#{ name}()' has been renamed to `$#{argname}'.")
+          keywords.delete(deprecated_argname)
+        else
+          raise Sass::SyntaxError.new("Function #{name} requires an argument named $#{argname}")
+        end
+      end
+
+      if keywords.size > 0
+        if signature.var_kwargs
+          # Don't pass a NormalizedMap to a Ruby function.
+          args << keywords.to_hash
+        else
+          argname = keywords.keys.sort.first
+          if signature.args.include?(argname)
+            raise Sass::SyntaxError.new(
+              "Function #{name} was passed argument $#{argname} both by position and by name")
+          else
+            raise Sass::SyntaxError.new(
+              "Function #{name} doesn't have an argument named $#{argname}")
+          end
+        end
+      end
+
+      args
+    end
+
+    def perform_sass_fn(function, args, splat, environment)
+      Sass::Tree::Visitors::Perform.perform_arguments(function, args, splat, environment) do |env|
+        env.caller = Sass::Environment.new(environment)
+
+        val = catch :_sass_return do
+          function.tree.each {|c| Sass::Tree::Visitors::Perform.visit(c, env)}
+          raise Sass::SyntaxError.new("Function #{ name} finished without @return")
+        end
+        val
+      end
+    end
+
+    def reformat_argument_error(e)
+      message = e.message
+
+      # If this is a legitimate Ruby-raised argument error, re-raise it.
+      # Otherwise, it's an error in the user's stylesheet, so wrap it.
+      if Sass::Util.rbx?
+        # Rubinius has a different error report string than vanilla Ruby. It
+        # also doesn't put the actual method for which the argument error was
+        # thrown in the backtrace, nor does it include `send`, so we look for
+        # `_perform`.
+        if e.message =~ /^method '([^']+)': given (\d+), expected (\d+)/
+          error_name, given, expected = $1, $2, $3
+          raise e if error_name != ruby_name || e.backtrace[0] !~ /:in `_perform'$/
+          message = "wrong number of arguments (#{given} for #{expected})"
+        end
+      elsif Sass::Util.jruby?
+        if Sass::Util.jruby1_6?
+          should_maybe_raise = e.message =~ /^wrong number of arguments \((\d+) for (\d+)\)/ &&
+            # The one case where JRuby does include the Ruby name of the function
+            # is manually-thrown ArgumentErrors, which are indistinguishable from
+            # legitimate ArgumentErrors. We treat both of these as
+            # Sass::SyntaxErrors even though it can hide Ruby errors.
+            e.backtrace[0] !~ /:in `(block in )?#{ruby_name}'$/
+        else
+          should_maybe_raise =
+            e.message =~ /^wrong number of arguments calling `[^`]+` \((\d+) for (\d+)\)/
+          given, expected = $1, $2
+        end
+
+        if should_maybe_raise
+          # JRuby 1.7 includes __send__ before send and _perform.
+          trace = e.backtrace.dup
+          raise e if !Sass::Util.jruby1_6? && trace.shift !~ /:in `__send__'$/
+
+          # JRuby (as of 1.7.2) doesn't put the actual method
+          # for which the argument error was thrown in the backtrace, so we
+          # detect whether our send threw an argument error.
+          if !(trace[0] =~ /:in `send'$/ && trace[1] =~ /:in `_perform'$/)
+            raise e
+          elsif !Sass::Util.jruby1_6?
+            # JRuby 1.7 doesn't use standard formatting for its ArgumentErrors.
+            message = "wrong number of arguments (#{given} for #{expected})"
+          end
+        end
+      elsif e.message =~ /^wrong number of arguments \(\d+ for \d+\)/ &&
+          e.backtrace[0] !~ /:in `(block in )?#{ruby_name}'$/
+        raise e
+      end
+      raise Sass::SyntaxError.new("#{message} for `#{name}'")
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/tree/interpolation.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/tree/interpolation.rb
new file mode 100644
index 0000000..e619df4
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/tree/interpolation.rb
@@ -0,0 +1,118 @@
+module Sass::Script::Tree
+  # A SassScript object representing `#{}` interpolation outside a string.
+  #
+  # @see StringInterpolation
+  class Interpolation < Node
+    # @return [Node] The SassScript before the interpolation
+    attr_reader :before
+
+    # @return [Node] The SassScript within the interpolation
+    attr_reader :mid
+
+    # @return [Node] The SassScript after the interpolation
+    attr_reader :after
+
+    # @return [Boolean] Whether there was whitespace between `before` and `#{`
+    attr_reader :whitespace_before
+
+    # @return [Boolean] Whether there was whitespace between `}` and `after`
+    attr_reader :whitespace_after
+
+    # @return [Boolean] Whether the original format of the interpolation was
+    #   plain text, not an interpolation. This is used when converting back to
+    #   SassScript.
+    attr_reader :originally_text
+
+    # @return [Boolean] Whether a color value passed to the interpolation should
+    #   generate a warning.
+    attr_reader :warn_for_color
+
+    # Interpolation in a property is of the form `before #{mid} after`.
+    #
+    # @param before [Node] See {Interpolation#before}
+    # @param mid [Node] See {Interpolation#mid}
+    # @param after [Node] See {Interpolation#after}
+    # @param wb [Boolean] See {Interpolation#whitespace_before}
+    # @param wa [Boolean] See {Interpolation#whitespace_after}
+    # @param originally_text [Boolean] See {Interpolation#originally_text}
+    # @param warn_for_color [Boolean] See {Interpolation#warn_for_color}
+    # @comment
+    #   rubocop:disable ParameterLists
+    def initialize(before, mid, after, wb, wa, originally_text = false, warn_for_color = false)
+      # rubocop:enable ParameterLists
+      @before = before
+      @mid = mid
+      @after = after
+      @whitespace_before = wb
+      @whitespace_after = wa
+      @originally_text = originally_text
+      @warn_for_color = warn_for_color
+    end
+
+    # @return [String] A human-readable s-expression representation of the interpolation
+    def inspect
+      "(interpolation #{ before inspect} #{ mid inspect} #{ after inspect})"
+    end
+
+    # @see Node#to_sass
+    def to_sass(opts = {})
+      res = ""
+      res << @before.to_sass(opts) if @before
+      res << ' ' if @before && @whitespace_before
+      res << '#{' unless @originally_text
+      res << @mid.to_sass(opts)
+      res << '}' unless @originally_text
+      res << ' ' if @after && @whitespace_after
+      res << @after.to_sass(opts) if @after
+      res
+    end
+
+    # Returns the three components of the interpolation, `before`, `mid`, and `after`.
+    #
+    # @return [Array<Node>]
+    # @see #initialize
+    # @see Node#children
+    def children
+      [ before, @mid, @after].compact
+    end
+
+    # @see Node#deep_copy
+    def deep_copy
+      node = dup
+      node.instance_variable_set('@before', @before.deep_copy) if @before
+      node.instance_variable_set('@mid', @mid.deep_copy)
+      node.instance_variable_set('@after', @after.deep_copy) if @after
+      node
+    end
+
+    protected
+
+    # Evaluates the interpolation.
+    #
+    # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
+    # @return [Sass::Script::Value::String]
+    #   The SassScript string that is the value of the interpolation
+    def _perform(environment)
+      res = ""
+      res << @before.perform(environment).to_s if @before
+      res << " " if @before && @whitespace_before
+
+      val = @mid.perform(environment)
+      if @warn_for_color && val.is_a?(Sass::Script::Value::Color) && val.name
+        alternative = Operation.new(Sass::Script::Value::String.new("", :string), @mid, :plus)
+        Sass::Util.sass_warn <<MESSAGE
+WARNING on line #{line}, column #{source_range.start_pos.offset}#{" of #{filename}" if filename}:
+You probably don't mean to use the color value `#{val}' in interpolation here.
+It may end up represented as #{val.inspect}, which will likely produce invalid CSS.
+Always quote color names when using them as strings (for example, "#{val}").
+If you really want to use the color value here, use `#{alternative.to_sass}'.
+MESSAGE
+      end
+
+      res << val.to_s(:quote => :none)
+      res << " " if @after && @whitespace_after
+      res << @after.perform(environment).to_s if @after
+      opts(Sass::Script::Value::String.new(res))
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/tree/list_literal.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/tree/list_literal.rb
new file mode 100644
index 0000000..292e719
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/tree/list_literal.rb
@@ -0,0 +1,77 @@
+module Sass::Script::Tree
+  # A parse tree node representing a list literal. When resolved, this returns a
+  # {Sass::Tree::Value::List}.
+  class ListLiteral < Node
+    # The parse nodes for members of this list.
+    #
+    # @return [Array<Node>]
+    attr_reader :elements
+
+    # The operator separating the values of the list. Either `:comma` or
+    # `:space`.
+    #
+    # @return [Symbol]
+    attr_reader :separator
+
+    # Creates a new list literal.
+    #
+    # @param elements [Array<Node>] See \{#elements}
+    # @param separator [Symbol] See \{#separator}
+    def initialize(elements, separator)
+      @elements = elements
+      @separator = separator
+    end
+
+    # @see Node#children
+    def children; elements; end
+
+    # @see Value#to_sass
+    def to_sass(opts = {})
+      return "()" if elements.empty?
+      precedence = Sass::Script::Parser.precedence_of(separator)
+      members = elements.map do |v|
+        if v.is_a?(ListLiteral) && Sass::Script::Parser.precedence_of(v.separator) <= precedence ||
+            separator == :space && v.is_a?(UnaryOperation) &&
+            (v.operator == :minus || v.operator == :plus)
+          "(#{v.to_sass(opts)})"
+        else
+          v.to_sass(opts)
+        end
+      end
+
+      return "(#{members.first},)" if separator == :comma && members.length == 1
+
+      members.join(sep_str(nil))
+    end
+
+    # @see Node#deep_copy
+    def deep_copy
+      node = dup
+      node.instance_variable_set('@elements', elements.map {|e| e.deep_copy})
+      node
+    end
+
+    def inspect
+      "(#{elements.map {|e| e.inspect}.join(separator == :space ? ' ' : ', ')})"
+    end
+
+    protected
+
+    def _perform(environment)
+      list = Sass::Script::Value::List.new(
+        elements.map {|e| e.perform(environment)},
+        separator)
+      list.source_range = source_range
+      list.options = options
+      list
+    end
+
+    private
+
+    def sep_str(opts = options)
+      return ' ' if separator == :space
+      return ',' if opts && opts[:style] == :compressed
+      ', '
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/tree/literal.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/tree/literal.rb
new file mode 100644
index 0000000..4dd3ca0
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/tree/literal.rb
@@ -0,0 +1,45 @@
+module Sass::Script::Tree
+  # The parse tree node for a literal scalar value. This wraps an instance of
+  # {Sass::Script::Value::Base}.
+  #
+  # List literals should use {ListLiteral} instead.
+  class Literal < Node
+    # The wrapped value.
+    #
+    # @return [Sass::Script::Value::Base]
+    attr_reader :value
+
+    # Creates a new literal value.
+    #
+    # @param value [Sass::Script::Value::Base]
+    # @see #value
+    def initialize(value)
+      @value = value
+    end
+
+    # @see Node#children
+    def children; []; end
+
+    # @see Node#to_sass
+    def to_sass(opts = {}); value.to_sass(opts); end
+
+    # @see Node#deep_copy
+    def deep_copy; dup; end
+
+    # @see Node#options=
+    def options=(options)
+      value.options = options
+    end
+
+    def inspect
+      value.inspect
+    end
+
+    protected
+
+    def _perform(environment)
+      value.source_range = source_range
+      value
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/tree/map_literal.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/tree/map_literal.rb
new file mode 100644
index 0000000..a2f8856
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/tree/map_literal.rb
@@ -0,0 +1,64 @@
+module Sass::Script::Tree
+  # A class representing a map literal. When resolved, this returns a
+  # {Sass::Script::Node::Map}.
+  class MapLiteral < Node
+    # The key/value pairs that make up this map node. This isn't a Hash so that
+    # we can detect key collisions once all the keys have been performed.
+    #
+    # @return [Array<(Node, Node)>]
+    attr_reader :pairs
+
+    # Creates a new map literal.
+    #
+    # @param pairs [Array<(Node, Node)>] See \{#pairs}
+    def initialize(pairs)
+      @pairs = pairs
+    end
+
+    # @see Node#children
+    def children
+      @pairs.flatten
+    end
+
+    # @see Node#to_sass
+    def to_sass(opts = {})
+      return "()" if pairs.empty?
+
+      to_sass = lambda do |value|
+        if value.is_a?(ListLiteral) && value.separator == :comma
+          "(#{value.to_sass(opts)})"
+        else
+          value.to_sass(opts)
+        end
+      end
+
+      "(" + pairs.map {|(k, v)| "#{to_sass[k]}: #{to_sass[v]}"}.join(', ') + ")"
+    end
+    alias_method :inspect, :to_sass
+
+    # @see Node#deep_copy
+    def deep_copy
+      node = dup
+      node.instance_variable_set('@pairs',
+        pairs.map {|(k, v)| [k.deep_copy, v.deep_copy]})
+      node
+    end
+
+    protected
+
+    # @see Node#_perform
+    def _perform(environment)
+      keys = Set.new
+      map = Sass::Script::Value::Map.new(Sass::Util.to_hash(pairs.map do |(k, v)|
+        k, v = k.perform(environment), v.perform(environment)
+        if keys.include?(k)
+          raise Sass::SyntaxError.new("Duplicate key #{k.inspect} in map #{to_sass}.")
+        end
+        keys << k
+        [k, v]
+      end))
+      map.options = options
+      map
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/tree/node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/tree/node.rb
new file mode 100644
index 0000000..953e121
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/tree/node.rb
@@ -0,0 +1,109 @@
+module Sass::Script::Tree
+  # The abstract superclass for SassScript parse tree nodes.
+  #
+  # Use \{#perform} to evaluate a parse tree.
+  class Node
+    # The options hash for this node.
+    #
+    # @return [{Symbol => Object}]
+    attr_reader :options
+
+    # The line of the document on which this node appeared.
+    #
+    # @return [Fixnum]
+    attr_accessor :line
+
+    # The source range in the document on which this node appeared.
+    #
+    # @return [Sass::Source::Range]
+    attr_accessor :source_range
+
+    # The file name of the document on which this node appeared.
+    #
+    # @return [String]
+    attr_accessor :filename
+
+    # Sets the options hash for this node,
+    # as well as for all child nodes.
+    # See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
+    #
+    # @param options [{Symbol => Object}] The options
+    def options=(options)
+      @options = options
+      children.each do |c|
+        if c.is_a? Hash
+          c.values.each {|v| v.options = options}
+        else
+          c.options = options
+        end
+      end
+    end
+
+    # Evaluates the node.
+    #
+    # \{#perform} shouldn't be overridden directly;
+    # instead, override \{#\_perform}.
+    #
+    # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
+    # @return [Sass::Script::Value] The SassScript object that is the value of the SassScript
+    def perform(environment)
+      _perform(environment)
+    rescue Sass::SyntaxError => e
+      e.modify_backtrace(:line => line)
+      raise e
+    end
+
+    # Returns all child nodes of this node.
+    #
+    # @return [Array<Node>]
+    def children
+      Sass::Util.abstract(self)
+    end
+
+    # Returns the text of this SassScript expression.
+    #
+    # @return [String]
+    def to_sass(opts = {})
+      Sass::Util.abstract(self)
+    end
+
+    # Returns a deep clone of this node.
+    # The child nodes are cloned, but options are not.
+    #
+    # @return [Node]
+    def deep_copy
+      Sass::Util.abstract(self)
+    end
+
+    protected
+
+    # Converts underscores to dashes if the :dasherize option is set.
+    def dasherize(s, opts)
+      if opts[:dasherize]
+        s.gsub(/_/, '-')
+      else
+        s
+      end
+    end
+
+    # Evaluates this node.
+    # Note that all {Sass::Script::Value} objects created within this method
+    # should have their \{#options} attribute set, probably via \{#opts}.
+    #
+    # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
+    # @return [Sass::Script::Value] The SassScript object that is the value of the SassScript
+    # @see #perform
+    def _perform(environment)
+      Sass::Util.abstract(self)
+    end
+
+    # Sets the \{#options} field on the given value and returns it.
+    #
+    # @param value [Sass::Script::Value]
+    # @return [Sass::Script::Value]
+    def opts(value)
+      value.options = options
+      value
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/tree/operation.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/tree/operation.rb
new file mode 100644
index 0000000..859bb45
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/tree/operation.rb
@@ -0,0 +1,115 @@
+module Sass::Script::Tree
+  # A SassScript parse node representing a binary operation,
+  # such as `$a + $b` or `"foo" + 1`.
+  class Operation < Node
+    attr_reader :operand1
+    attr_reader :operand2
+    attr_reader :operator
+
+    # @param operand1 [Sass::Script::Tree::Node] The parse-tree node
+    #   for the right-hand side of the operator
+    # @param operand2 [Sass::Script::Tree::Node] The parse-tree node
+    #   for the left-hand side of the operator
+    # @param operator [Symbol] The operator to perform.
+    #   This should be one of the binary operator names in {Sass::Script::Lexer::OPERATORS}
+    def initialize(operand1, operand2, operator)
+      @operand1 = operand1
+      @operand2 = operand2
+      @operator = operator
+      super()
+    end
+
+    # @return [String] A human-readable s-expression representation of the operation
+    def inspect
+      "(#{ operator inspect} #{ operand1 inspect} #{ operand2 inspect})"
+    end
+
+    # @see Node#to_sass
+    def to_sass(opts = {})
+      o1 = operand_to_sass @operand1, :left, opts
+      o2 = operand_to_sass @operand2, :right, opts
+      sep =
+        case @operator
+        when :comma; ", "
+        when :space; " "
+        else; " #{Sass::Script::Lexer::OPERATORS_REVERSE[ operator]} "
+        end
+      "#{o1}#{sep}#{o2}"
+    end
+
+    # Returns the operands for this operation.
+    #
+    # @return [Array<Node>]
+    # @see Node#children
+    def children
+      [ operand1, @operand2]
+    end
+
+    # @see Node#deep_copy
+    def deep_copy
+      node = dup
+      node.instance_variable_set('@operand1', @operand1.deep_copy)
+      node.instance_variable_set('@operand2', @operand2.deep_copy)
+      node
+    end
+
+    protected
+
+    # Evaluates the operation.
+    #
+    # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
+    # @return [Sass::Script::Value] The SassScript object that is the value of the operation
+    # @raise [Sass::SyntaxError] if the operation is undefined for the operands
+    def _perform(environment)
+      value1 = @operand1.perform(environment)
+
+      # Special-case :and and :or to support short-circuiting.
+      if @operator == :and
+        return value1.to_bool ? @operand2.perform(environment) : value1
+      elsif @operator == :or
+        return value1.to_bool ? value1 : @operand2.perform(environment)
+      end
+
+      value2 = @operand2.perform(environment)
+
+      if (value1.is_a?(Sass::Script::Value::Null) || value2.is_a?(Sass::Script::Value::Null)) &&
+          @operator != :eq && @operator != :neq
+        raise Sass::SyntaxError.new(
+          "Invalid null operation: \"#{value1.inspect} #{ operator} #{value2.inspect}\".")
+      end
+
+      begin
+        result = opts(value1.send(@operator, value2))
+      rescue NoMethodError => e
+        raise e unless e.name.to_s == @operator.to_s
+        raise Sass::SyntaxError.new("Undefined operation: \"#{value1} #{ operator} #{value2}\".")
+      end
+
+      if @operator == :eq && value1.is_a?(Sass::Script::Value::Number) &&
+          value2.is_a?(Sass::Script::Value::Number) && result == Sass::Script::Value::Bool::TRUE &&
+          value1.unitless? != value2.unitless?
+        Sass::Util.sass_warn <<WARNING
+DEPRECATION WARNING on line #{line}#{" of #{filename}" if filename}:
+The result of `#{value1} == #{value2}` will be `false` in future releases of Sass.
+Unitless numbers will no longer be equal to the same numbers with units.
+WARNING
+      end
+
+      result
+    end
+
+    private
+
+    def operand_to_sass(op, side, opts)
+      return "(#{op.to_sass(opts)})" if op.is_a?(Sass::Script::Tree::ListLiteral)
+      return op.to_sass(opts) unless op.is_a?(Operation)
+
+      pred = Sass::Script::Parser.precedence_of(@operator)
+      sub_pred = Sass::Script::Parser.precedence_of(op.operator)
+      assoc = Sass::Script::Parser.associative?(@operator)
+      return "(#{op.to_sass(opts)})" if sub_pred < pred ||
+        (side == :right && sub_pred == pred && !assoc)
+      op.to_sass(opts)
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/tree/selector.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/tree/selector.rb
new file mode 100644
index 0000000..4a852cd
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/tree/selector.rb
@@ -0,0 +1,26 @@
+module Sass::Script::Tree
+  # A SassScript node that will resolve to the current selector.
+  class Selector < Node
+    def initialize; end
+
+    def children
+      []
+    end
+
+    def to_sass(opts = {})
+      '&'
+    end
+
+    def deep_copy
+      dup
+    end
+
+    protected
+
+    def _perform(environment)
+      selector = environment.selector
+      return opts(Sass::Script::Value::Null.new) unless selector
+      opts(selector.to_sass_script)
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/tree/string_interpolation.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/tree/string_interpolation.rb
new file mode 100644
index 0000000..6c7575d
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/tree/string_interpolation.rb
@@ -0,0 +1,104 @@
+module Sass::Script::Tree
+  # A SassScript object representing `#{}` interpolation within a string.
+  #
+  # @see Interpolation
+  class StringInterpolation < Node
+    # Interpolation in a string is of the form `"before #{mid} after"`,
+    # where `before` and `after` may include more interpolation.
+    #
+    # @param before [Node] The string before the interpolation
+    # @param mid [Node] The SassScript within the interpolation
+    # @param after [Node] The string after the interpolation
+    def initialize(before, mid, after)
+      @before = before
+      @mid = mid
+      @after = after
+    end
+
+    # @return [String] A human-readable s-expression representation of the interpolation
+    def inspect
+      "(string_interpolation #{ before inspect} #{ mid inspect} #{ after inspect})"
+    end
+
+    # @see Node#to_sass
+    def to_sass(opts = {})
+      # We can get rid of all of this when we remove the deprecated :equals context
+      # XXX CE: It's gone now but I'm not sure what can be removed now.
+      before_unquote, before_quote_char, before_str = parse_str(@before.to_sass(opts))
+      after_unquote, after_quote_char, after_str = parse_str(@after.to_sass(opts))
+      unquote = before_unquote || after_unquote ||
+        (before_quote_char && !after_quote_char && !after_str.empty?) ||
+        (!before_quote_char && after_quote_char && !before_str.empty?)
+      quote_char =
+        if before_quote_char && after_quote_char && before_quote_char != after_quote_char
+          before_str.gsub!("\\'", "'")
+          before_str.gsub!('"', "\\\"")
+          after_str.gsub!("\\'", "'")
+          after_str.gsub!('"', "\\\"")
+          '"'
+        else
+          before_quote_char || after_quote_char
+        end
+
+      res = ""
+      res << 'unquote(' if unquote
+      res << quote_char if quote_char
+      res << before_str
+      res << '#{' << @mid.to_sass(opts) << '}'
+      res << after_str
+      res << quote_char if quote_char
+      res << ')' if unquote
+      res
+    end
+
+    # Returns the three components of the interpolation, `before`, `mid`, and `after`.
+    #
+    # @return [Array<Node>]
+    # @see #initialize
+    # @see Node#children
+    def children
+      [ before, @mid, @after].compact
+    end
+
+    # @see Node#deep_copy
+    def deep_copy
+      node = dup
+      node.instance_variable_set('@before', @before.deep_copy) if @before
+      node.instance_variable_set('@mid', @mid.deep_copy)
+      node.instance_variable_set('@after', @after.deep_copy) if @after
+      node
+    end
+
+    protected
+
+    # Evaluates the interpolation.
+    #
+    # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
+    # @return [Sass::Script::Value::String]
+    #   The SassScript string that is the value of the interpolation
+    def _perform(environment)
+      res = ""
+      before = @before.perform(environment)
+      res << before.value
+      mid = @mid.perform(environment)
+      res << (mid.is_a?(Sass::Script::Value::String) ? mid.value : mid.to_s(:quote => :none))
+      res << @after.perform(environment).value
+      opts(Sass::Script::Value::String.new(res, before.type))
+    end
+
+    private
+
+    def parse_str(str)
+      case str
+      when /^unquote\((["'])(.*)\1\)$/
+        return true, $1, $2
+      when '""'
+        return false, nil, ""
+      when /^(["'])(.*)\1$/
+        return false, $1, $2
+      else
+        return false, nil, str
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/tree/unary_operation.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/tree/unary_operation.rb
new file mode 100644
index 0000000..b32da08
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/tree/unary_operation.rb
@@ -0,0 +1,69 @@
+module Sass::Script::Tree
+  # A SassScript parse node representing a unary operation,
+  # such as `-$b` or `not true`.
+  #
+  # Currently only `-`, `/`, and `not` are unary operators.
+  class UnaryOperation < Node
+    # @return [Symbol] The operation to perform
+    attr_reader :operator
+
+    # @return [Script::Node] The parse-tree node for the object of the operator
+    attr_reader :operand
+
+    # @param operand [Script::Node] See \{#operand}
+    # @param operator [Symbol] See \{#operator}
+    def initialize(operand, operator)
+      @operand = operand
+      @operator = operator
+      super()
+    end
+
+    # @return [String] A human-readable s-expression representation of the operation
+    def inspect
+      "(#{ operator inspect} #{ operand inspect})"
+    end
+
+    # @see Node#to_sass
+    def to_sass(opts = {})
+      operand = @operand.to_sass(opts)
+      if @operand.is_a?(Operation) ||
+          (@operator == :minus &&
+           (operand =~ Sass::SCSS::RX::IDENT) == 0)
+        operand = "(#{ operand to_sass(opts)})"
+      end
+      op = Sass::Script::Lexer::OPERATORS_REVERSE[ operator]
+      op + (op =~ /[a-z]/ ? " " : "") + operand
+    end
+
+    # Returns the operand of the operation.
+    #
+    # @return [Array<Node>]
+    # @see Node#children
+    def children
+      [ operand]
+    end
+
+    # @see Node#deep_copy
+    def deep_copy
+      node = dup
+      node.instance_variable_set('@operand', @operand.deep_copy)
+      node
+    end
+
+    protected
+
+    # Evaluates the operation.
+    #
+    # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
+    # @return [Sass::Script::Value] The SassScript object that is the value of the operation
+    # @raise [Sass::SyntaxError] if the operation is undefined for the operand
+    def _perform(environment)
+      operator = "unary_#{ operator}"
+      value = @operand.perform(environment)
+      value.send(operator)
+    rescue NoMethodError => e
+      raise e unless e.name.to_s == operator.to_s
+      raise Sass::SyntaxError.new("Undefined unary operation: \"#{ operator} #{value}\".")
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/tree/variable.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/tree/variable.rb
new file mode 100644
index 0000000..3480db5
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/tree/variable.rb
@@ -0,0 +1,57 @@
+module Sass::Script::Tree
+  # A SassScript parse node representing a variable.
+  class Variable < Node
+    # The name of the variable.
+    #
+    # @return [String]
+    attr_reader :name
+
+    # The underscored name of the variable.
+    #
+    # @return [String]
+    attr_reader :underscored_name
+
+    # @param name [String] See \{#name}
+    def initialize(name)
+      @name = name
+      @underscored_name = name.gsub(/-/, "_")
+      super()
+    end
+
+    # @return [String] A string representation of the variable
+    def inspect(opts = {})
+      "$#{dasherize(name, opts)}"
+    end
+    alias_method :to_sass, :inspect
+
+    # Returns an empty array.
+    #
+    # @return [Array<Node>] empty
+    # @see Node#children
+    def children
+      []
+    end
+
+    # @see Node#deep_copy
+    def deep_copy
+      dup
+    end
+
+    protected
+
+    # Evaluates the variable.
+    #
+    # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
+    # @return [Sass::Script::Value] The SassScript object that is the value of the variable
+    # @raise [Sass::SyntaxError] if the variable is undefined
+    def _perform(environment)
+      val = environment.var(name)
+      raise Sass::SyntaxError.new("Undefined variable: \"$#{name}\".") unless val
+      if val.is_a?(Sass::Script::Value::Number) && val.original
+        val = val.dup
+        val.original = nil
+      end
+      val
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/value.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/value.rb
new file mode 100644
index 0000000..0842b58
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/value.rb
@@ -0,0 +1,11 @@
+module Sass::Script::Value; end
+
+require 'sass/script/value/base'
+require 'sass/script/value/string'
+require 'sass/script/value/number'
+require 'sass/script/value/color'
+require 'sass/script/value/bool'
+require 'sass/script/value/null'
+require 'sass/script/value/list'
+require 'sass/script/value/arg_list'
+require 'sass/script/value/map'
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/value/arg_list.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/value/arg_list.rb
new file mode 100644
index 0000000..2b09882
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/value/arg_list.rb
@@ -0,0 +1,36 @@
+module Sass::Script::Value
+  # A SassScript object representing a variable argument list. This works just
+  # like a normal list, but can also contain keyword arguments.
+  #
+  # The keyword arguments attached to this list are unused except when this is
+  # passed as a glob argument to a function or mixin.
+  class ArgList < List
+    # Whether \{#keywords} has been accessed. If so, we assume that all keywords
+    # were valid for the function that created this ArgList.
+    #
+    # @return [Boolean]
+    attr_accessor :keywords_accessed
+
+    # Creates a new argument list.
+    #
+    # @param value [Array<Value>] See \{List#value}.
+    # @param keywords [Hash<String, Value>, NormalizedMap<Value>] See \{#keywords}
+    # @param separator [String] See \{List#separator}.
+    def initialize(value, keywords, separator)
+      super(value, separator)
+      if keywords.is_a?(Sass::Util::NormalizedMap)
+        @keywords = keywords
+      else
+        @keywords = Sass::Util::NormalizedMap.new(keywords)
+      end
+    end
+
+    # The keyword arguments attached to this list.
+    #
+    # @return [NormalizedMap<Value>]
+    def keywords
+      @keywords_accessed = true
+      @keywords
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/value/base.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/value/base.rb
new file mode 100644
index 0000000..4cdcbed
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/value/base.rb
@@ -0,0 +1,240 @@
+module Sass::Script::Value
+  # The abstract superclass for SassScript objects.
+  #
+  # Many of these methods, especially the ones that correspond to SassScript operations,
+  # are designed to be overridden by subclasses which may change the semantics somewhat.
+  # The operations listed here are just the defaults.
+  class Base
+    # Returns the Ruby value of the value.
+    # The type of this value varies based on the subclass.
+    #
+    # @return [Object]
+    attr_reader :value
+
+    # The source range in the document on which this node appeared.
+    #
+    # @return [Sass::Source::Range]
+    attr_accessor :source_range
+
+    # Creates a new value.
+    #
+    # @param value [Object] The object for \{#value}
+    def initialize(value = nil)
+      value.freeze unless value.nil? || value == true || value == false
+      @value = value
+    end
+
+    # Sets the options hash for this node,
+    # as well as for all child nodes.
+    # See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
+    #
+    # @param options [{Symbol => Object}] The options
+    attr_writer :options
+
+    # Returns the options hash for this node.
+    #
+    # @return [{Symbol => Object}]
+    # @raise [Sass::SyntaxError] if the options hash hasn't been set.
+    #   This should only happen when the value was created
+    #   outside of the parser and \{#to\_s} was called on it
+    def options
+      return @options if @options
+      raise Sass::SyntaxError.new(<<MSG)
+The #options attribute is not set on this #{self.class}.
+  This error is probably occurring because #to_s was called
+  on this value within a custom Sass function without first
+  setting the #options attribute.
+MSG
+    end
+
+    # The SassScript `==` operation.
+    # **Note that this returns a {Sass::Script::Value::Bool} object,
+    # not a Ruby boolean**.
+    #
+    # @param other [Value] The right-hand side of the operator
+    # @return [Sass::Script::Value::Bool] True if this value is the same as the other,
+    #   false otherwise
+    def eq(other)
+      Sass::Script::Value::Bool.new(self.class == other.class && value == other.value)
+    end
+
+    # The SassScript `!=` operation.
+    # **Note that this returns a {Sass::Script::Value::Bool} object,
+    # not a Ruby boolean**.
+    #
+    # @param other [Value] The right-hand side of the operator
+    # @return [Sass::Script::Value::Bool] False if this value is the same as the other,
+    #   true otherwise
+    def neq(other)
+      Sass::Script::Value::Bool.new(!eq(other).to_bool)
+    end
+
+    # The SassScript `==` operation.
+    # **Note that this returns a {Sass::Script::Value::Bool} object,
+    # not a Ruby boolean**.
+    #
+    # @param other [Value] The right-hand side of the operator
+    # @return [Sass::Script::Value::Bool] True if this value is the same as the other,
+    #   false otherwise
+    def unary_not
+      Sass::Script::Value::Bool.new(!to_bool)
+    end
+
+    # The SassScript `=` operation
+    # (used for proprietary MS syntax like `alpha(opacity=20)`).
+    #
+    # @param other [Value] The right-hand side of the operator
+    # @return [Script::Value::String] A string containing both values
+    #   separated by `"="`
+    def single_eq(other)
+      Sass::Script::Value::String.new("#{to_s}=#{other.to_s}")
+    end
+
+    # The SassScript `+` operation.
+    #
+    # @param other [Value] The right-hand side of the operator
+    # @return [Script::Value::String] A string containing both values
+    #   without any separation
+    def plus(other)
+      type = other.is_a?(Sass::Script::Value::String) ? other.type : :identifier
+      Sass::Script::Value::String.new(to_s(:quote => :none) + other.to_s(:quote => :none), type)
+    end
+
+    # The SassScript `-` operation.
+    #
+    # @param other [Value] The right-hand side of the operator
+    # @return [Script::Value::String] A string containing both values
+    #   separated by `"-"`
+    def minus(other)
+      Sass::Script::Value::String.new("#{to_s}-#{other.to_s}")
+    end
+
+    # The SassScript `/` operation.
+    #
+    # @param other [Value] The right-hand side of the operator
+    # @return [Script::Value::String] A string containing both values
+    #   separated by `"/"`
+    def div(other)
+      Sass::Script::Value::String.new("#{to_s}/#{other.to_s}")
+    end
+
+    # The SassScript unary `+` operation (e.g. `+$a`).
+    #
+    # @param other [Value] The right-hand side of the operator
+    # @return [Script::Value::String] A string containing the value
+    #   preceded by `"+"`
+    def unary_plus
+      Sass::Script::Value::String.new("+#{to_s}")
+    end
+
+    # The SassScript unary `-` operation (e.g. `-$a`).
+    #
+    # @param other [Value] The right-hand side of the operator
+    # @return [Script::Value::String] A string containing the value
+    #   preceded by `"-"`
+    def unary_minus
+      Sass::Script::Value::String.new("-#{to_s}")
+    end
+
+    # The SassScript unary `/` operation (e.g. `/$a`).
+    #
+    # @param other [Value] The right-hand side of the operator
+    # @return [Script::Value::String] A string containing the value
+    #   preceded by `"/"`
+    def unary_div
+      Sass::Script::Value::String.new("/#{to_s}")
+    end
+
+    # Returns the hash code of this value. Two objects' hash codes should be
+    # equal if the objects are equal.
+    #
+    # @return [Fixnum] The hash code.
+    def hash
+      value.hash
+    end
+
+    def eql?(other)
+      self == other
+    end
+
+    # @return [String] A readable representation of the value
+    def inspect
+      value.inspect
+    end
+
+    # @return [Boolean] `true` (the Ruby boolean value)
+    def to_bool
+      true
+    end
+
+    # Compares this object with another.
+    #
+    # @param other [Object] The object to compare with
+    # @return [Boolean] Whether or not this value is equivalent to `other`
+    def ==(other)
+      eq(other).to_bool
+    end
+
+    # @return [Fixnum] The integer value of this value
+    # @raise [Sass::SyntaxError] if this value isn't an integer
+    def to_i
+      raise Sass::SyntaxError.new("#{inspect} is not an integer.")
+    end
+
+    # @raise [Sass::SyntaxError] if this value isn't an integer
+    def assert_int!; to_i; end
+
+    # Returns the separator for this value. For non-list-like values or the
+    # empty list, this will be `nil`. For lists or maps, it will be `:space` or
+    # `:comma`.
+    #
+    # @return [Symbol]
+    def separator; nil; end
+
+    # Returns the value of this value as a list.
+    # Single values are considered the same as single-element lists.
+    #
+    # @return [Array<Value>] This value as a list
+    def to_a
+      [self]
+    end
+
+    # Returns the value of this value as a hash. Most values don't have hash
+    # representations, but [Map]s and empty [List]s do.
+    #
+    # @return [Hash<Value, Value>] This value as a hash
+    # @raise [Sass::SyntaxError] if this value doesn't have a hash representation
+    def to_h
+      raise Sass::SyntaxError.new("#{inspect} is not a map.")
+    end
+
+    # Returns the string representation of this value
+    # as it would be output to the CSS document.
+    #
+    # @options opts :quote [String]
+    #   The preferred quote style for quoted strings. If `:none`, strings are
+    #   always emitted unquoted.
+    # @return [String]
+    def to_s(opts = {})
+      Sass::Util.abstract(self)
+    end
+    alias_method :to_sass, :to_s
+
+    # Returns whether or not this object is null.
+    #
+    # @return [Boolean] `false`
+    def null?
+      false
+    end
+
+    protected
+
+    # Evaluates the value.
+    #
+    # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
+    # @return [Value] This value
+    def _perform(environment)
+      self
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/value/bool.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/value/bool.rb
new file mode 100644
index 0000000..fd1789b
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/value/bool.rb
@@ -0,0 +1,35 @@
+module Sass::Script::Value
+  # A SassScript object representing a boolean (true or false) value.
+  class Bool < Base
+    # The true value in SassScript.
+    #
+    # This is assigned before new is overridden below so that we use the default implementation.
+    TRUE  = new(true)
+
+    # The false value in SassScript.
+    #
+    # This is assigned before new is overridden below so that we use the default implementation.
+    FALSE = new(false)
+
+    # We override object creation so that users of the core API
+    # will not need to know that booleans are specific constants.
+    #
+    # @param value A ruby value that will be tested for truthiness.
+    # @return [Bool] TRUE if value is truthy, FALSE if value is falsey
+    def self.new(value)
+      value ? TRUE : FALSE
+    end
+
+    # The Ruby value of the boolean.
+    #
+    # @return [Boolean]
+    attr_reader :value
+    alias_method :to_bool, :value
+
+    # @return [String] "true" or "false"
+    def to_s(opts = {})
+      @value.to_s
+    end
+    alias_method :to_sass, :to_s
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/value/color.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/value/color.rb
new file mode 100644
index 0000000..884936a
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/value/color.rb
@@ -0,0 +1,680 @@
+module Sass::Script::Value
+  # A SassScript object representing a CSS color.
+  #
+  # A color may be represented internally as RGBA, HSLA, or both.
+  # It's originally represented as whatever its input is;
+  # if it's created with RGB values, it's represented as RGBA,
+  # and if it's created with HSL values, it's represented as HSLA.
+  # Once a property is accessed that requires the other representation --
+  # for example, \{#red} for an HSL color --
+  # that component is calculated and cached.
+  #
+  # The alpha channel of a color is independent of its RGB or HSL representation.
+  # It's always stored, as 1 if nothing else is specified.
+  # If only the alpha channel is modified using \{#with},
+  # the cached RGB and HSL values are retained.
+  class Color < Base
+    # @private
+    #
+    # Convert a ruby integer to a rgba components
+    # @param color [Fixnum]
+    # @return [Array<Fixnum>] Array of 4 numbers representing r,g,b and alpha
+    def self.int_to_rgba(color)
+      rgba = (0..3).map {|n| color >> (n << 3) & 0xff}.reverse
+      rgba[-1] = rgba[-1] / 255.0
+      rgba
+    end
+
+    ALTERNATE_COLOR_NAMES = Sass::Util.map_vals({
+        'aqua'                 => 0x00FFFFFF,
+        'darkgrey'             => 0xA9A9A9FF,
+        'darkslategrey'        => 0x2F4F4FFF,
+        'dimgrey'              => 0x696969FF,
+        'fuchsia'              => 0xFF00FFFF,
+        'grey'                 => 0x808080FF,
+        'lightgrey'            => 0xD3D3D3FF,
+        'lightslategrey'       => 0x778899FF,
+        'slategrey'            => 0x708090FF,
+    }, &method(:int_to_rgba))
+
+    # A hash from color names to `[red, green, blue]` value arrays.
+    COLOR_NAMES = Sass::Util.map_vals({
+        'aliceblue'            => 0xF0F8FFFF,
+        'antiquewhite'         => 0xFAEBD7FF,
+        'aquamarine'           => 0x7FFFD4FF,
+        'azure'                => 0xF0FFFFFF,
+        'beige'                => 0xF5F5DCFF,
+        'bisque'               => 0xFFE4C4FF,
+        'black'                => 0x000000FF,
+        'blanchedalmond'       => 0xFFEBCDFF,
+        'blue'                 => 0x0000FFFF,
+        'blueviolet'           => 0x8A2BE2FF,
+        'brown'                => 0xA52A2AFF,
+        'burlywood'            => 0xDEB887FF,
+        'cadetblue'            => 0x5F9EA0FF,
+        'chartreuse'           => 0x7FFF00FF,
+        'chocolate'            => 0xD2691EFF,
+        'coral'                => 0xFF7F50FF,
+        'cornflowerblue'       => 0x6495EDFF,
+        'cornsilk'             => 0xFFF8DCFF,
+        'crimson'              => 0xDC143CFF,
+        'cyan'                 => 0x00FFFFFF,
+        'darkblue'             => 0x00008BFF,
+        'darkcyan'             => 0x008B8BFF,
+        'darkgoldenrod'        => 0xB8860BFF,
+        'darkgray'             => 0xA9A9A9FF,
+        'darkgreen'            => 0x006400FF,
+        'darkkhaki'            => 0xBDB76BFF,
+        'darkmagenta'          => 0x8B008BFF,
+        'darkolivegreen'       => 0x556B2FFF,
+        'darkorange'           => 0xFF8C00FF,
+        'darkorchid'           => 0x9932CCFF,
+        'darkred'              => 0x8B0000FF,
+        'darksalmon'           => 0xE9967AFF,
+        'darkseagreen'         => 0x8FBC8FFF,
+        'darkslateblue'        => 0x483D8BFF,
+        'darkslategray'        => 0x2F4F4FFF,
+        'darkturquoise'        => 0x00CED1FF,
+        'darkviolet'           => 0x9400D3FF,
+        'deeppink'             => 0xFF1493FF,
+        'deepskyblue'          => 0x00BFFFFF,
+        'dimgray'              => 0x696969FF,
+        'dodgerblue'           => 0x1E90FFFF,
+        'firebrick'            => 0xB22222FF,
+        'floralwhite'          => 0xFFFAF0FF,
+        'forestgreen'          => 0x228B22FF,
+        'gainsboro'            => 0xDCDCDCFF,
+        'ghostwhite'           => 0xF8F8FFFF,
+        'gold'                 => 0xFFD700FF,
+        'goldenrod'            => 0xDAA520FF,
+        'gray'                 => 0x808080FF,
+        'green'                => 0x008000FF,
+        'greenyellow'          => 0xADFF2FFF,
+        'honeydew'             => 0xF0FFF0FF,
+        'hotpink'              => 0xFF69B4FF,
+        'indianred'            => 0xCD5C5CFF,
+        'indigo'               => 0x4B0082FF,
+        'ivory'                => 0xFFFFF0FF,
+        'khaki'                => 0xF0E68CFF,
+        'lavender'             => 0xE6E6FAFF,
+        'lavenderblush'        => 0xFFF0F5FF,
+        'lawngreen'            => 0x7CFC00FF,
+        'lemonchiffon'         => 0xFFFACDFF,
+        'lightblue'            => 0xADD8E6FF,
+        'lightcoral'           => 0xF08080FF,
+        'lightcyan'            => 0xE0FFFFFF,
+        'lightgoldenrodyellow' => 0xFAFAD2FF,
+        'lightgreen'           => 0x90EE90FF,
+        'lightgray'            => 0xD3D3D3FF,
+        'lightpink'            => 0xFFB6C1FF,
+        'lightsalmon'          => 0xFFA07AFF,
+        'lightseagreen'        => 0x20B2AAFF,
+        'lightskyblue'         => 0x87CEFAFF,
+        'lightslategray'       => 0x778899FF,
+        'lightsteelblue'       => 0xB0C4DEFF,
+        'lightyellow'          => 0xFFFFE0FF,
+        'lime'                 => 0x00FF00FF,
+        'limegreen'            => 0x32CD32FF,
+        'linen'                => 0xFAF0E6FF,
+        'magenta'              => 0xFF00FFFF,
+        'maroon'               => 0x800000FF,
+        'mediumaquamarine'     => 0x66CDAAFF,
+        'mediumblue'           => 0x0000CDFF,
+        'mediumorchid'         => 0xBA55D3FF,
+        'mediumpurple'         => 0x9370DBFF,
+        'mediumseagreen'       => 0x3CB371FF,
+        'mediumslateblue'      => 0x7B68EEFF,
+        'mediumspringgreen'    => 0x00FA9AFF,
+        'mediumturquoise'      => 0x48D1CCFF,
+        'mediumvioletred'      => 0xC71585FF,
+        'midnightblue'         => 0x191970FF,
+        'mintcream'            => 0xF5FFFAFF,
+        'mistyrose'            => 0xFFE4E1FF,
+        'moccasin'             => 0xFFE4B5FF,
+        'navajowhite'          => 0xFFDEADFF,
+        'navy'                 => 0x000080FF,
+        'oldlace'              => 0xFDF5E6FF,
+        'olive'                => 0x808000FF,
+        'olivedrab'            => 0x6B8E23FF,
+        'orange'               => 0xFFA500FF,
+        'orangered'            => 0xFF4500FF,
+        'orchid'               => 0xDA70D6FF,
+        'palegoldenrod'        => 0xEEE8AAFF,
+        'palegreen'            => 0x98FB98FF,
+        'paleturquoise'        => 0xAFEEEEFF,
+        'palevioletred'        => 0xDB7093FF,
+        'papayawhip'           => 0xFFEFD5FF,
+        'peachpuff'            => 0xFFDAB9FF,
+        'peru'                 => 0xCD853FFF,
+        'pink'                 => 0xFFC0CBFF,
+        'plum'                 => 0xDDA0DDFF,
+        'powderblue'           => 0xB0E0E6FF,
+        'purple'               => 0x800080FF,
+        'red'                  => 0xFF0000FF,
+        'rebeccapurple'        => 0x663399FF,
+        'rosybrown'            => 0xBC8F8FFF,
+        'royalblue'            => 0x4169E1FF,
+        'saddlebrown'          => 0x8B4513FF,
+        'salmon'               => 0xFA8072FF,
+        'sandybrown'           => 0xF4A460FF,
+        'seagreen'             => 0x2E8B57FF,
+        'seashell'             => 0xFFF5EEFF,
+        'sienna'               => 0xA0522DFF,
+        'silver'               => 0xC0C0C0FF,
+        'skyblue'              => 0x87CEEBFF,
+        'slateblue'            => 0x6A5ACDFF,
+        'slategray'            => 0x708090FF,
+        'snow'                 => 0xFFFAFAFF,
+        'springgreen'          => 0x00FF7FFF,
+        'steelblue'            => 0x4682B4FF,
+        'tan'                  => 0xD2B48CFF,
+        'teal'                 => 0x008080FF,
+        'thistle'              => 0xD8BFD8FF,
+        'tomato'               => 0xFF6347FF,
+        'transparent'          => 0x00000000,
+        'turquoise'            => 0x40E0D0FF,
+        'violet'               => 0xEE82EEFF,
+        'wheat'                => 0xF5DEB3FF,
+        'white'                => 0xFFFFFFFF,
+        'whitesmoke'           => 0xF5F5F5FF,
+        'yellow'               => 0xFFFF00FF,
+        'yellowgreen'          => 0x9ACD32FF
+     }, &method(:int_to_rgba))
+
+    # A hash from `[red, green, blue, alpha]` value arrays to color names.
+    COLOR_NAMES_REVERSE = COLOR_NAMES.invert.freeze
+
+    # We add the alternate color names after inverting because
+    # different ruby implementations and versions vary on the ordering of the result of invert.
+    COLOR_NAMES.update(ALTERNATE_COLOR_NAMES).freeze
+
+    # The user's original representation of the color.
+    #
+    # @return [String]
+    attr_reader :representation
+
+    # Constructs an RGB or HSL color object,
+    # optionally with an alpha channel.
+    #
+    # RGB values are clipped within 0 and 255.
+    # Saturation and lightness values are clipped within 0 and 100.
+    # The alpha value is clipped within 0 and 1.
+    #
+    # @raise [Sass::SyntaxError] if any color value isn't in the specified range
+    #
+    # @overload initialize(attrs)
+    #   The attributes are specified as a hash. This hash must contain either
+    #   `:hue`, `:saturation`, and `:value` keys, or `:red`, `:green`, and
+    #   `:blue` keys. It cannot contain both HSL and RGB keys. It may also
+    #   optionally contain an `:alpha` key, and a `:representation` key
+    #   indicating the original representation of the color that the user wrote
+    #   in their stylesheet.
+    #
+    #   @param attrs [{Symbol => Numeric}] A hash of color attributes to values
+    #   @raise [ArgumentError] if not enough attributes are specified,
+    #     or both RGB and HSL attributes are specified
+    #
+    # @overload initialize(rgba, [representation])
+    #   The attributes are specified as an array.
+    #   This overload only supports RGB or RGBA colors.
+    #
+    #   @param rgba [Array<Numeric>] A three- or four-element array
+    #     of the red, green, blue, and optionally alpha values (respectively)
+    #     of the color
+    #   @param representation [String] The original representation of the color
+    #     that the user wrote in their stylesheet.
+    #   @raise [ArgumentError] if not enough attributes are specified
+    def initialize(attrs, representation = nil, allow_both_rgb_and_hsl = false)
+      super(nil)
+
+      if attrs.is_a?(Array)
+        unless (3..4).include?(attrs.size)
+          raise ArgumentError.new("Color.new(array) expects a three- or four-element array")
+        end
+
+        red, green, blue = attrs[0...3].map {|c| c.to_i}
+        @attrs = {:red => red, :green => green, :blue => blue}
+        @attrs[:alpha] = attrs[3] ? attrs[3].to_f : 1
+        @representation = representation
+      else
+        attrs = attrs.reject {|k, v| v.nil?}
+        hsl = [:hue, :saturation, :lightness] & attrs.keys
+        rgb = [:red, :green, :blue] & attrs.keys
+        if !allow_both_rgb_and_hsl && !hsl.empty? && !rgb.empty?
+          raise ArgumentError.new("Color.new(hash) may not have both HSL and RGB keys specified")
+        elsif hsl.empty? && rgb.empty?
+          raise ArgumentError.new("Color.new(hash) must have either HSL or RGB keys specified")
+        elsif !hsl.empty? && hsl.size != 3
+          raise ArgumentError.new("Color.new(hash) must have all three HSL values specified")
+        elsif !rgb.empty? && rgb.size != 3
+          raise ArgumentError.new("Color.new(hash) must have all three RGB values specified")
+        end
+
+        @attrs = attrs
+        @attrs[:hue] %= 360 if @attrs[:hue]
+        @attrs[:alpha] ||= 1
+        @representation = @attrs.delete(:representation)
+      end
+
+      [:red, :green, :blue].each do |k|
+        next if @attrs[k].nil?
+        @attrs[k] = Sass::Util.restrict(@attrs[k].to_i, 0..255)
+      end
+
+      [:saturation, :lightness].each do |k|
+        next if @attrs[k].nil?
+        @attrs[k] = Sass::Util.restrict(@attrs[k], 0..100)
+      end
+
+      @attrs[:alpha] = Sass::Util.restrict(@attrs[:alpha], 0..1)
+    end
+
+    # Create a new color from a valid CSS hex string.
+    #
+    # The leading hash is optional.
+    #
+    # @return [Color]
+    def self.from_hex(hex_string, alpha = nil)
+      unless hex_string =~ /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i ||
+             hex_string =~ /^#?([0-9a-f])([0-9a-f])([0-9a-f])$/i
+        raise ArgumentError.new("#{hex_string.inspect} is not a valid hex color.")
+      end
+      red   = $1.ljust(2, $1).to_i(16)
+      green = $2.ljust(2, $2).to_i(16)
+      blue  = $3.ljust(2, $3).to_i(16)
+
+      hex_string = '##{hex_string}' unless hex_string[0] == ?#
+      attrs = {:red => red, :green => green, :blue => blue, :representation => hex_string}
+      attrs[:alpha] = alpha if alpha
+      new(attrs)
+    end
+
+    # The red component of the color.
+    #
+    # @return [Fixnum]
+    def red
+      hsl_to_rgb!
+      @attrs[:red]
+    end
+
+    # The green component of the color.
+    #
+    # @return [Fixnum]
+    def green
+      hsl_to_rgb!
+      @attrs[:green]
+    end
+
+    # The blue component of the color.
+    #
+    # @return [Fixnum]
+    def blue
+      hsl_to_rgb!
+      @attrs[:blue]
+    end
+
+    # The hue component of the color.
+    #
+    # @return [Numeric]
+    def hue
+      rgb_to_hsl!
+      @attrs[:hue]
+    end
+
+    # The saturation component of the color.
+    #
+    # @return [Numeric]
+    def saturation
+      rgb_to_hsl!
+      @attrs[:saturation]
+    end
+
+    # The lightness component of the color.
+    #
+    # @return [Numeric]
+    def lightness
+      rgb_to_hsl!
+      @attrs[:lightness]
+    end
+
+    # The alpha channel (opacity) of the color.
+    # This is 1 unless otherwise defined.
+    #
+    # @return [Fixnum]
+    def alpha
+      @attrs[:alpha].to_f
+    end
+
+    # Returns whether this color object is translucent;
+    # that is, whether the alpha channel is non-1.
+    #
+    # @return [Boolean]
+    def alpha?
+      alpha < 1
+    end
+
+    # Returns the red, green, and blue components of the color.
+    #
+    # @return [Array<Fixnum>] A frozen three-element array of the red, green, and blue
+    #   values (respectively) of the color
+    def rgb
+      [red, green, blue].freeze
+    end
+
+    # Returns the red, green, blue, and alpha components of the color.
+    #
+    # @return [Array<Fixnum>] A frozen four-element array of the red, green,
+    #   blue, and alpha values (respectively) of the color
+    def rgba
+      [red, green, blue, alpha].freeze
+    end
+
+    # Returns the hue, saturation, and lightness components of the color.
+    #
+    # @return [Array<Fixnum>] A frozen three-element array of the
+    #   hue, saturation, and lightness values (respectively) of the color
+    def hsl
+      [hue, saturation, lightness].freeze
+    end
+
+    # Returns the hue, saturation, lightness, and alpha components of the color.
+    #
+    # @return [Array<Fixnum>] A frozen four-element array of the hue,
+    #   saturation, lightness, and alpha values (respectively) of the color
+    def hsla
+      [hue, saturation, lightness].freeze
+    end
+
+    # The SassScript `==` operation.
+    # **Note that this returns a {Sass::Script::Value::Bool} object,
+    # not a Ruby boolean**.
+    #
+    # @param other [Value] The right-hand side of the operator
+    # @return [Bool] True if this value is the same as the other,
+    #   false otherwise
+    def eq(other)
+      Sass::Script::Value::Bool.new(
+        other.is_a?(Color) && rgb == other.rgb && alpha == other.alpha)
+    end
+
+    def hash
+      [rgb, alpha].hash
+    end
+
+    # Returns a copy of this color with one or more channels changed.
+    # RGB or HSL colors may be changed, but not both at once.
+    #
+    # For example:
+    #
+    #     Color.new([10, 20, 30]).with(:blue => 40)
+    #       #=> rgb(10, 40, 30)
+    #     Color.new([126, 126, 126]).with(:red => 0, :green => 255)
+    #       #=> rgb(0, 255, 126)
+    #     Color.new([255, 0, 127]).with(:saturation => 60)
+    #       #=> rgb(204, 51, 127)
+    #     Color.new([1, 2, 3]).with(:alpha => 0.4)
+    #       #=> rgba(1, 2, 3, 0.4)
+    #
+    # @param attrs [{Symbol => Numeric}]
+    #   A map of channel names (`:red`, `:green`, `:blue`,
+    #   `:hue`, `:saturation`, `:lightness`, or `:alpha`) to values
+    # @return [Color] The new Color object
+    # @raise [ArgumentError] if both RGB and HSL keys are specified
+    def with(attrs)
+      attrs = attrs.reject {|k, v| v.nil?}
+      hsl = !([:hue, :saturation, :lightness] & attrs.keys).empty?
+      rgb = !([:red, :green, :blue] & attrs.keys).empty?
+      if hsl && rgb
+        raise ArgumentError.new("Cannot specify HSL and RGB values for a color at the same time")
+      end
+
+      if hsl
+        [:hue, :saturation, :lightness].each {|k| attrs[k] ||= send(k)}
+      elsif rgb
+        [:red, :green, :blue].each {|k| attrs[k] ||= send(k)}
+      else
+        # If we're just changing the alpha channel,
+        # keep all the HSL/RGB stuff we've calculated
+        attrs = @attrs.merge(attrs)
+      end
+      attrs[:alpha] ||= alpha
+
+      Color.new(attrs, nil, :allow_both_rgb_and_hsl)
+    end
+
+    # The SassScript `+` operation.
+    # Its functionality depends on the type of its argument:
+    #
+    # {Number}
+    # : Adds the number to each of the RGB color channels.
+    #
+    # {Color}
+    # : Adds each of the RGB color channels together.
+    #
+    # {Value}
+    # : See {Value::Base#plus}.
+    #
+    # @param other [Value] The right-hand side of the operator
+    # @return [Color] The resulting color
+    # @raise [Sass::SyntaxError] if `other` is a number with units
+    def plus(other)
+      if other.is_a?(Sass::Script::Value::Number) || other.is_a?(Sass::Script::Value::Color)
+        piecewise(other, :+)
+      else
+        super
+      end
+    end
+
+    # The SassScript `-` operation.
+    # Its functionality depends on the type of its argument:
+    #
+    # {Number}
+    # : Subtracts the number from each of the RGB color channels.
+    #
+    # {Color}
+    # : Subtracts each of the other color's RGB color channels from this color's.
+    #
+    # {Value}
+    # : See {Value::Base#minus}.
+    #
+    # @param other [Value] The right-hand side of the operator
+    # @return [Color] The resulting color
+    # @raise [Sass::SyntaxError] if `other` is a number with units
+    def minus(other)
+      if other.is_a?(Sass::Script::Value::Number) || other.is_a?(Sass::Script::Value::Color)
+        piecewise(other, :-)
+      else
+        super
+      end
+    end
+
+    # The SassScript `*` operation.
+    # Its functionality depends on the type of its argument:
+    #
+    # {Number}
+    # : Multiplies the number by each of the RGB color channels.
+    #
+    # {Color}
+    # : Multiplies each of the RGB color channels together.
+    #
+    # @param other [Number, Color] The right-hand side of the operator
+    # @return [Color] The resulting color
+    # @raise [Sass::SyntaxError] if `other` is a number with units
+    def times(other)
+      if other.is_a?(Sass::Script::Value::Number) || other.is_a?(Sass::Script::Value::Color)
+        piecewise(other, :*)
+      else
+        raise NoMethodError.new(nil, :times)
+      end
+    end
+
+    # The SassScript `/` operation.
+    # Its functionality depends on the type of its argument:
+    #
+    # {Number}
+    # : Divides each of the RGB color channels by the number.
+    #
+    # {Color}
+    # : Divides each of this color's RGB color channels by the other color's.
+    #
+    # {Value}
+    # : See {Value::Base#div}.
+    #
+    # @param other [Value] The right-hand side of the operator
+    # @return [Color] The resulting color
+    # @raise [Sass::SyntaxError] if `other` is a number with units
+    def div(other)
+      if other.is_a?(Sass::Script::Value::Number) ||
+          other.is_a?(Sass::Script::Value::Color)
+        piecewise(other, :/)
+      else
+        super
+      end
+    end
+
+    # The SassScript `%` operation.
+    # Its functionality depends on the type of its argument:
+    #
+    # {Number}
+    # : Takes each of the RGB color channels module the number.
+    #
+    # {Color}
+    # : Takes each of this color's RGB color channels modulo the other color's.
+    #
+    # @param other [Number, Color] The right-hand side of the operator
+    # @return [Color] The resulting color
+    # @raise [Sass::SyntaxError] if `other` is a number with units
+    def mod(other)
+      if other.is_a?(Sass::Script::Value::Number) ||
+          other.is_a?(Sass::Script::Value::Color)
+        piecewise(other, :%)
+      else
+        raise NoMethodError.new(nil, :mod)
+      end
+    end
+
+    # Returns a string representation of the color.
+    # This is usually the color's hex value,
+    # but if the color has a name that's used instead.
+    #
+    # @return [String] The string representation
+    def to_s(opts = {})
+      return smallest if options[:style] == :compressed
+      return representation if representation
+      return name if name
+      alpha? ? rgba_str : hex_str
+    end
+    alias_method :to_sass, :to_s
+
+    # Returns a string representation of the color.
+    #
+    # @return [String] The hex value
+    def inspect
+      alpha? ? rgba_str : hex_str
+    end
+
+    # Returns the color's name, if it has one.
+    #
+    # @return [String, nil]
+    def name
+      COLOR_NAMES_REVERSE[rgba]
+    end
+
+    private
+
+    def smallest
+      small_explicit_str = alpha? ? rgba_str : hex_str.gsub(/^#(.)\1(.)\2(.)\3$/, '#\1\2\3')
+      [representation, COLOR_NAMES_REVERSE[rgba], small_explicit_str].
+          compact.min_by {|str| str.size}
+    end
+
+    def rgba_str
+      split = options[:style] == :compressed ? ',' : ', '
+      "rgba(#{rgb.join(split)}#{split}#{Number.round(alpha)})"
+    end
+
+    def hex_str
+      red, green, blue = rgb.map {|num| num.to_s(16).rjust(2, '0')}
+      "##{red}#{green}#{blue}"
+    end
+
+    def piecewise(other, operation)
+      other_num = other.is_a? Number
+      if other_num && !other.unitless?
+        raise Sass::SyntaxError.new(
+          "Cannot add a number with units (#{other}) to a color (#{self}).")
+      end
+
+      result = []
+      (0...3).each do |i|
+        res = rgb[i].send(operation, other_num ? other.value : other.rgb[i])
+        result[i] = [[res, 255].min, 0].max
+      end
+
+      if !other_num && other.alpha != alpha
+        raise Sass::SyntaxError.new("Alpha channels must be equal: #{self} #{operation} #{other}")
+      end
+
+      with(:red => result[0], :green => result[1], :blue => result[2])
+    end
+
+    def hsl_to_rgb!
+      return if @attrs[:red] && @attrs[:blue] && @attrs[:green]
+
+      h = @attrs[:hue] / 360.0
+      s = @attrs[:saturation] / 100.0
+      l = @attrs[:lightness] / 100.0
+
+      # Algorithm from the CSS3 spec: http://www.w3.org/TR/css3-color/#hsl-color.
+      m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s
+      m1 = l * 2 - m2
+      @attrs[:red], @attrs[:green], @attrs[:blue] = [
+        hue_to_rgb(m1, m2, h + 1.0 / 3),
+        hue_to_rgb(m1, m2, h),
+        hue_to_rgb(m1, m2, h - 1.0 / 3)
+      ].map {|c| (c * 0xff).round}
+    end
+
+    def hue_to_rgb(m1, m2, h)
+      h += 1 if h < 0
+      h -= 1 if h > 1
+      return m1 + (m2 - m1) * h * 6 if h * 6 < 1
+      return m2 if h * 2 < 1
+      return m1 + (m2 - m1) * (2.0 / 3 - h) * 6 if h * 3 < 2
+      m1
+    end
+
+    def rgb_to_hsl!
+      return if @attrs[:hue] && @attrs[:saturation] && @attrs[:lightness]
+      r, g, b = [:red, :green, :blue].map {|k| @attrs[k] / 255.0}
+
+      # Algorithm from http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV
+      max = [r, g, b].max
+      min = [r, g, b].min
+      d = max - min
+
+      h =
+        case max
+        when min; 0
+        when r; 60 * (g - b) / d
+        when g; 60 * (b - r) / d + 120
+        when b; 60 * (r - g) / d + 240
+        end
+
+      l = (max + min) / 2.0
+
+      s =
+        if max == min
+          0
+        elsif l < 0.5
+          d / (2 * l)
+        else
+          d / (2 - 2 * l)
+        end
+
+      @attrs[:hue] = h % 360
+      @attrs[:saturation] = s * 100
+      @attrs[:lightness] = l * 100
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/value/helpers.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/value/helpers.rb
new file mode 100644
index 0000000..d1a6376
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/value/helpers.rb
@@ -0,0 +1,262 @@
+module Sass::Script::Value
+  # Provides helper functions for creating sass values from within ruby methods.
+  # @since `3.3.0`
+  module Helpers
+    # Construct a Sass Boolean.
+    #
+    # @param value [Object] A ruby object that will be tested for truthiness.
+    # @return [Sass::Script::Value::Bool] whether the ruby value is truthy.
+    def bool(value)
+      Bool.new(value)
+    end
+
+    # Construct a Sass Color from a hex color string.
+    #
+    # @param value [::String] A string representing a hex color.
+    #   The leading hash ("#") is optional.
+    # @param alpha [::Number] The alpha channel. A number between 0 and 1.
+    # @return [Sass::Script::Value::Color] the color object
+    def hex_color(value, alpha = nil)
+      Color.from_hex(value, alpha)
+    end
+
+    # Construct a Sass Color from hsl values.
+    #
+    # @param hue [::Number] The hue of the color in degrees.
+    #   A non-negative number, usually less than 360.
+    # @param saturation [::Number] The saturation of the color.
+    #   Must be between 0 and 100 inclusive.
+    # @param lightness [::Number] The lightness of the color.
+    #   Must be between 0 and 100 inclusive.
+    # @param alpha [::Number] The alpha channel. A number between 0 and 1.
+    #
+    # @return [Sass::Script::Value::Color] the color object
+    def hsl_color(hue, saturation, lightness, alpha = nil)
+      attrs = {:hue => hue, :saturation => saturation, :lightness => lightness}
+      attrs[:alpha] = alpha if alpha
+      Color.new(attrs)
+    end
+
+    # Construct a Sass Color from rgb values.
+    #
+    # @param red [::Number] The red component. Must be between 0 and 255 inclusive.
+    # @param green [::Number] The green component. Must be between 0 and 255 inclusive.
+    # @param blue [::Number] The blue component. Must be between 0 and 255 inclusive.
+    # @param alpha [::Number] The alpha channel. A number between 0 and 1.
+    #
+    # @return [Sass::Script::Value::Color] the color object
+    def rgb_color(red, green, blue, alpha = nil)
+      attrs = {:red => red, :green => green, :blue => blue}
+      attrs[:alpha] = alpha if alpha
+      Color.new(attrs)
+    end
+
+    # Construct a Sass Number from a ruby number.
+    #
+    # @param number [::Number] A numeric value.
+    # @param unit_string [::String] A unit string of the form
+    #   `numeral_unit1 * numeral_unit2 ... / denominator_unit1 * denominator_unit2 ...`
+    #   this is the same format that is returned by
+    #   {Sass::Script::Value::Number#unit_str the `unit_str` method}
+    #
+    # @see Sass::Script::Value::Number#unit_str
+    #
+    # @return [Sass::Script::Value::Number] The sass number representing the given ruby number.
+    def number(number, unit_string = nil)
+      Number.new(number, *parse_unit_string(unit_string))
+    end
+
+    # @overload list(*elements, separator)
+    #   Create a space-separated list from the arguments given.
+    #   @param elements [Array<Sass::Script::Value::Base>] Each argument will be a list element.
+    #   @param separator [Symbol] Either :space or :comma.
+    #   @return [Sass::Script::Value::List] The space separated list.
+    #
+    # @overload list(array, separator)
+    #   Create a space-separated list from the array given.
+    #   @param array [Array<Sass::Script::Value::Base>] A ruby array of Sass values
+    #     to make into a list.
+    #   @return [Sass::Script::Value::List] The space separated list.
+    def list(*elements)
+      unless elements.last.is_a?(Symbol)
+        raise ArgumentError.new("A list type of :space or :comma must be specified.")
+      end
+      separator = elements.pop
+      if elements.size == 1 && elements.first.is_a?(Array)
+        elements = elements.first
+      end
+      Sass::Script::Value::List.new(elements, separator)
+    end
+
+    # Construct a Sass map.
+    #
+    # @param hash [Hash<Sass::Script::Value::Base,
+    #   Sass::Script::Value::Base>] A Ruby map to convert to a Sass map.
+    # @return [Sass::Script::Value::Map] The map.
+    def map(hash)
+      Map.new(hash)
+    end
+
+    # Create a sass null value.
+    #
+    # @return [Sass::Script::Value::Null]
+    def null
+      Sass::Script::Value::Null.new
+    end
+
+    # Create a quoted string.
+    #
+    # @param str [::String] A ruby string.
+    # @return [Sass::Script::Value::String] A quoted string.
+    def quoted_string(str)
+      Sass::Script::String.new(str, :string)
+    end
+
+    # Create an unquoted string.
+    #
+    # @param str [::String] A ruby string.
+    # @return [Sass::Script::Value::String] An unquoted string.
+    def unquoted_string(str)
+      Sass::Script::String.new(str, :identifier)
+    end
+    alias_method :identifier, :unquoted_string
+
+    # Parses a user-provided selector.
+    #
+    # @param value [Sass::Script::Value::String, Sass::Script::Value::List]
+    #   The selector to parse. This can be either a string, a list of
+    #   strings, or a list of lists of strings as returned by `&`.
+    # @param name [Symbol, nil]
+    #   If provided, the name of the selector argument. This is used
+    #   for error reporting.
+    # @param allow_parent_ref [Boolean]
+    #   Whether the parsed selector should allow parent references.
+    # @return [Sass::Selector::CommaSequence] The parsed selector.
+    # @throw [ArgumentError] if the parse failed for any reason.
+    def parse_selector(value, name = nil, allow_parent_ref = false)
+      str = normalize_selector(value, name)
+      begin
+        Sass::SCSS::StaticParser.new(str, nil, nil, 1, 1, allow_parent_ref).parse_selector
+      rescue Sass::SyntaxError => e
+        err = "#{value.inspect} is not a valid selector: #{e}"
+        err = "$#{name.to_s.gsub('_', '-')}: #{err}" if name
+        raise ArgumentError.new(err)
+      end
+    end
+
+    # Parses a user-provided complex selector.
+    #
+    # A complex selector can contain combinators but cannot contain commas.
+    #
+    # @param value [Sass::Script::Value::String, Sass::Script::Value::List]
+    #   The selector to parse. This can be either a string or a list of
+    #   strings.
+    # @param name [Symbol, nil]
+    #   If provided, the name of the selector argument. This is used
+    #   for error reporting.
+    # @param allow_parent_ref [Boolean]
+    #   Whether the parsed selector should allow parent references.
+    # @return [Sass::Selector::Sequence] The parsed selector.
+    # @throw [ArgumentError] if the parse failed for any reason.
+    def parse_complex_selector(value, name = nil, allow_parent_ref = false)
+      selector = parse_selector(value, name, allow_parent_ref)
+      return seq if selector.members.length == 1
+
+      err = "#{value.inspect} is not a complex selector"
+      err = "$#{name.to_s.gsub('_', '-')}: #{err}" if name
+      raise ArgumentError.new(err)
+    end
+
+    # Parses a user-provided compound selector.
+    #
+    # A compound selector cannot contain combinators or commas.
+    #
+    # @param value [Sass::Script::Value::String] The selector to parse.
+    # @param name [Symbol, nil]
+    #   If provided, the name of the selector argument. This is used
+    #   for error reporting.
+    # @param allow_parent_ref [Boolean]
+    #   Whether the parsed selector should allow parent references.
+    # @return [Sass::Selector::SimpleSequence] The parsed selector.
+    # @throw [ArgumentError] if the parse failed for any reason.
+    def parse_compound_selector(value, name = nil, allow_parent_ref = false)
+      assert_type value, :String, name
+      selector = parse_selector(value, name, allow_parent_ref)
+      seq = selector.members.first
+      sseq = seq.members.first
+      if selector.members.length == 1 && seq.members.length == 1 &&
+          sseq.is_a?(Sass::Selector::SimpleSequence)
+        return sseq
+      end
+
+      err = "#{value.inspect} is not a compound selector"
+      err = "$#{name.to_s.gsub('_', '-')}: #{err}" if name
+      raise ArgumentError.new(err)
+    end
+
+    private
+
+    # Converts a user-provided selector into string form or throws an
+    # ArgumentError if it's in an invalid format.
+    def normalize_selector(value, name)
+      if (str = selector_to_str(value))
+        return str
+      end
+
+      err = "#{value.inspect} is not a valid selector: it must be a string,\n" +
+        "a list of strings, or a list of lists of strings"
+      err = "$#{name.to_s.gsub('_', '-')}: #{err}" if name
+      raise ArgumentError.new(err)
+    end
+
+    # Converts a user-provided selector into string form or returns
+    # `nil` if it's in an invalid format.
+    def selector_to_str(value)
+      return value.value if value.is_a?(Sass::Script::String)
+      return unless value.is_a?(Sass::Script::List)
+
+      if value.separator == :comma
+        return value.to_a.map do |complex|
+          next complex.value if complex.is_a?(Sass::Script::String)
+          return unless complex.is_a?(Sass::Script::List) && complex.separator == :space
+          return unless (str = selector_to_str(complex))
+          str
+        end.join(', ')
+      end
+
+      value.to_a.map do |compound|
+        return unless compound.is_a?(Sass::Script::String)
+        compound.value
+      end.join(' ')
+    end
+
+    # @private
+    VALID_UNIT = /#{Sass::SCSS::RX::NMSTART}#{Sass::SCSS::RX::NMCHAR}|%*/
+
+    # @example
+    #   parse_unit_string("em*px/in*%") # => [["em", "px], ["in", "%"]]
+    #
+    # @param unit_string [String] A string adhering to the output of a number with complex
+    #   units. E.g. "em*px/in*%"
+    # @return [Array<Array<String>>] A list of numerator units and a list of denominator units.
+    def parse_unit_string(unit_string)
+      denominator_units = numerator_units = Sass::Script::Value::Number::NO_UNITS
+      return numerator_units, denominator_units unless unit_string && unit_string.length > 0
+      num_over_denominator = unit_string.split(/ *\/ */)
+      unless (1..2).include?(num_over_denominator.size)
+        raise ArgumentError.new("Malformed unit string: #{unit_string}")
+      end
+      numerator_units = num_over_denominator[0].split(/ *\* */)
+      denominator_units = (num_over_denominator[1] || "").split(/ *\* */)
+      [[numerator_units, "numerator"], [denominator_units, "denominator"]].each do |units, name|
+        if unit_string =~ /\// && units.size == 0
+          raise ArgumentError.new("Malformed unit string: #{unit_string}")
+        end
+        if units.any? {|unit| unit !~ VALID_UNIT}
+          raise ArgumentError.new("Malformed #{name} in unit string: #{unit_string}")
+        end
+      end
+      [numerator_units, denominator_units]
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/value/list.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/value/list.rb
new file mode 100644
index 0000000..648b830
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/value/list.rb
@@ -0,0 +1,113 @@
+module Sass::Script::Value
+  # A SassScript object representing a CSS list.
+  # This includes both comma-separated lists and space-separated lists.
+  class List < Base
+    # The Ruby array containing the contents of the list.
+    #
+    # @return [Array<Value>]
+    attr_reader :value
+    alias_method :to_a, :value
+
+    # The operator separating the values of the list.
+    # Either `:comma` or `:space`.
+    #
+    # @return [Symbol]
+    attr_reader :separator
+
+    # Creates a new list.
+    #
+    # @param value [Array<Value>] See \{#value}
+    # @param separator [Symbol] See \{#separator}
+    def initialize(value, separator)
+      super(value)
+      @separator = separator
+    end
+
+    # @see Value#options=
+    def options=(options)
+      super
+      value.each {|v| v.options = options}
+    end
+
+    # @see Value#eq
+    def eq(other)
+      Sass::Script::Value::Bool.new(
+        other.is_a?(List) && value == other.value &&
+        separator == other.separator)
+    end
+
+    def hash
+      @hash ||= [value, separator].hash
+    end
+
+    # @see Value#to_s
+    def to_s(opts = {})
+      raise Sass::SyntaxError.new("() isn't a valid CSS value.") if value.empty?
+      value.
+        reject {|e| e.is_a?(Null) || e.is_a?(List) && e.value.empty?}.
+        map {|e| e.to_s(opts)}.join(sep_str)
+    end
+
+    # @see Value#to_sass
+    def to_sass(opts = {})
+      return "()" if value.empty?
+      members = value.map do |v|
+        if element_needs_parens?(v)
+          "(#{v.to_sass(opts)})"
+        else
+          v.to_sass(opts)
+        end
+      end
+      return "(#{members.first},)" if members.length == 1 && separator == :comma
+      members.join(sep_str(nil))
+    end
+
+    # @see Value#to_h
+    def to_h
+      return Sass::Util.ordered_hash if value.empty?
+      super
+    end
+
+    # @see Value#inspect
+    def inspect
+      "(#{value.map {|e| e.inspect}.join(sep_str(nil))})"
+    end
+
+    # Asserts an index is within the list.
+    #
+    # @private
+    #
+    # @param list [Sass::Script::Value::List] The list for which the index should be checked.
+    # @param n [Sass::Script::Value::Number] The index being checked.
+    def self.assert_valid_index(list, n)
+      if !n.int? || n.to_i == 0
+        raise ArgumentError.new("List index #{n} must be a non-zero integer")
+      elsif list.to_a.size == 0
+        raise ArgumentError.new("List index is #{n} but list has no items")
+      elsif n.to_i.abs > (size = list.to_a.size)
+        raise ArgumentError.new(
+          "List index is #{n} but list is only #{size} item#{'s' if size != 1} long")
+      end
+    end
+
+    private
+
+    def element_needs_parens?(element)
+      if element.is_a?(List)
+        return false if element.value.empty?
+        precedence = Sass::Script::Parser.precedence_of(separator)
+        return Sass::Script::Parser.precedence_of(element.separator) <= precedence
+      end
+
+      return false unless separator == :space
+      return false unless element.is_a?(Sass::Script::Tree::UnaryOperation)
+      element.operator == :minus || element.operator == :plus
+    end
+
+    def sep_str(opts = options)
+      return ' ' if separator == :space
+      return ',' if opts && opts[:style] == :compressed
+      ', '
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/value/map.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/value/map.rb
new file mode 100644
index 0000000..9946fea
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/value/map.rb
@@ -0,0 +1,70 @@
+module Sass::Script::Value
+  # A SassScript object representing a map from keys to values. Both keys and
+  # values can be any SassScript object.
+  class Map < Base
+    # The Ruby hash containing the contents of this map.
+    #
+    # @return [Hash<Node, Node>]
+    attr_reader :value
+    alias_method :to_h, :value
+
+    # Creates a new map.
+    #
+    # @param hash [Hash<Node, Node>]
+    def initialize(hash)
+      super(Sass::Util.ordered_hash(hash))
+    end
+
+    # @see Value#options=
+    def options=(options)
+      super
+      value.each do |k, v|
+        k.options = options
+        v.options = options
+      end
+    end
+
+    # @see Value#separator
+    def separator
+      :comma unless value.empty?
+    end
+
+    # @see Value#to_a
+    def to_a
+      value.map do |k, v|
+        list = List.new([k, v], :space)
+        list.options = options
+        list
+      end
+    end
+
+    # @see Value#eq
+    def eq(other)
+      Bool.new(other.is_a?(Map) && value == other.value)
+    end
+
+    def hash
+      @hash ||= value.hash
+    end
+
+    # @see Value#to_s
+    def to_s(opts = {})
+      raise Sass::SyntaxError.new("#{inspect} isn't a valid CSS value.")
+    end
+
+    def to_sass(opts = {})
+      return "()" if value.empty?
+
+      to_sass = lambda do |value|
+        if value.is_a?(Map) || (value.is_a?(List) && value.separator == :comma)
+          "(#{value.to_sass(opts)})"
+        else
+          value.to_sass(opts)
+        end
+      end
+
+      "(#{value.map {|(k, v)| "#{to_sass[k]}: #{to_sass[v]}"}.join(', ')})"
+    end
+    alias_method :inspect, :to_sass
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/value/null.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/value/null.rb
new file mode 100644
index 0000000..f6d573b
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/value/null.rb
@@ -0,0 +1,44 @@
+module Sass::Script::Value
+  # A SassScript object representing a null value.
+  class Null < Base
+    # The null value in SassScript.
+    #
+    # This is assigned before new is overridden below so that we use the default implementation.
+    NULL = new(nil)
+
+    # We override object creation so that users of the core API
+    # will not need to know that null is a specific constant.
+    #
+    # @private
+    # @return [Null] the {NULL} constant.
+    def self.new
+      NULL
+    end
+
+    # @return [Boolean] `false` (the Ruby boolean value)
+    def to_bool
+      false
+    end
+
+    # @return [Boolean] `true`
+    def null?
+      true
+    end
+
+    # @return [String] '' (An empty string)
+    def to_s(opts = {})
+      ''
+    end
+
+    def to_sass(opts = {})
+      'null'
+    end
+
+    # Returns a string representing a null value.
+    #
+    # @return [String]
+    def inspect
+      'null'
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/value/number.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/value/number.rb
new file mode 100644
index 0000000..031a6e7
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/value/number.rb
@@ -0,0 +1,530 @@
+module Sass::Script::Value
+  # A SassScript object representing a number.
+  # SassScript numbers can have decimal values,
+  # and can also have units.
+  # For example, `12`, `1px`, and `10.45em`
+  # are all valid values.
+  #
+  # Numbers can also have more complex units, such as `1px*em/in`.
+  # These cannot be inputted directly in Sass code at the moment.
+  class Number < Base
+    # The Ruby value of the number.
+    #
+    # @return [Numeric]
+    attr_reader :value
+
+    # A list of units in the numerator of the number.
+    # For example, `1px*em/in*cm` would return `["px", "em"]`
+    # @return [Array<String>]
+    attr_reader :numerator_units
+
+    # A list of units in the denominator of the number.
+    # For example, `1px*em/in*cm` would return `["in", "cm"]`
+    # @return [Array<String>]
+    attr_reader :denominator_units
+
+    # The original representation of this number.
+    # For example, although the result of `1px/2px` is `0.5`,
+    # the value of `#original` is `"1px/2px"`.
+    #
+    # This is only non-nil when the original value should be used as the CSS value,
+    # as in `font: 1px/2px`.
+    #
+    # @return [Boolean, nil]
+    attr_accessor :original
+
+    def self.precision
+      @precision ||= 5
+    end
+
+    # Sets the number of digits of precision
+    # For example, if this is `3`,
+    # `3.1415926` will be printed as `3.142`.
+    def self.precision=(digits)
+      @precision = digits.round
+      @precision_factor = 10 0** precision
+    end
+
+    # the precision factor used in numeric output
+    # it is derived from the `precision` method.
+    def self.precision_factor
+      @precision_factor ||= 10.0**precision
+    end
+
+    # Used so we don't allocate two new arrays for each new number.
+    NO_UNITS  = []
+
+    # @param value [Numeric] The value of the number
+    # @param numerator_units [::String, Array<::String>] See \{#numerator\_units}
+    # @param denominator_units [::String, Array<::String>] See \{#denominator\_units}
+    def initialize(value, numerator_units = NO_UNITS, denominator_units = NO_UNITS)
+      numerator_units = [numerator_units] if numerator_units.is_a?(::String)
+      denominator_units = [denominator_units] if denominator_units.is_a?(::String)
+      super(value)
+      @numerator_units = numerator_units
+      @denominator_units = denominator_units
+      normalize!
+    end
+
+    # The SassScript `+` operation.
+    # Its functionality depends on the type of its argument:
+    #
+    # {Number}
+    # : Adds the two numbers together, converting units if possible.
+    #
+    # {Color}
+    # : Adds this number to each of the RGB color channels.
+    #
+    # {Value}
+    # : See {Value::Base#plus}.
+    #
+    # @param other [Value] The right-hand side of the operator
+    # @return [Value] The result of the operation
+    # @raise [Sass::UnitConversionError] if `other` is a number with incompatible units
+    def plus(other)
+      if other.is_a? Number
+        operate(other, :+)
+      elsif other.is_a?(Color)
+        other.plus(self)
+      else
+        super
+      end
+    end
+
+    # The SassScript binary `-` operation (e.g. `$a - $b`).
+    # Its functionality depends on the type of its argument:
+    #
+    # {Number}
+    # : Subtracts this number from the other, converting units if possible.
+    #
+    # {Value}
+    # : See {Value::Base#minus}.
+    #
+    # @param other [Value] The right-hand side of the operator
+    # @return [Value] The result of the operation
+    # @raise [Sass::UnitConversionError] if `other` is a number with incompatible units
+    def minus(other)
+      if other.is_a? Number
+        operate(other, :-)
+      else
+        super
+      end
+    end
+
+    # The SassScript unary `+` operation (e.g. `+$a`).
+    #
+    # @return [Number] The value of this number
+    def unary_plus
+      self
+    end
+
+    # The SassScript unary `-` operation (e.g. `-$a`).
+    #
+    # @return [Number] The negative value of this number
+    def unary_minus
+      Number.new(-value, @numerator_units, @denominator_units)
+    end
+
+    # The SassScript `*` operation.
+    # Its functionality depends on the type of its argument:
+    #
+    # {Number}
+    # : Multiplies the two numbers together, converting units appropriately.
+    #
+    # {Color}
+    # : Multiplies each of the RGB color channels by this number.
+    #
+    # @param other [Number, Color] The right-hand side of the operator
+    # @return [Number, Color] The result of the operation
+    # @raise [NoMethodError] if `other` is an invalid type
+    def times(other)
+      if other.is_a? Number
+        operate(other, :*)
+      elsif other.is_a? Color
+        other.times(self)
+      else
+        raise NoMethodError.new(nil, :times)
+      end
+    end
+
+    # The SassScript `/` operation.
+    # Its functionality depends on the type of its argument:
+    #
+    # {Number}
+    # : Divides this number by the other, converting units appropriately.
+    #
+    # {Value}
+    # : See {Value::Base#div}.
+    #
+    # @param other [Value] The right-hand side of the operator
+    # @return [Value] The result of the operation
+    def div(other)
+      if other.is_a? Number
+        res = operate(other, :/)
+        if original && other.original
+          res.original = "#{original}/#{other.original}"
+        end
+        res
+      else
+        super
+      end
+    end
+
+    # The SassScript `%` operation.
+    #
+    # @param other [Number] The right-hand side of the operator
+    # @return [Number] This number modulo the other
+    # @raise [NoMethodError] if `other` is an invalid type
+    # @raise [Sass::UnitConversionError] if `other` has incompatible units
+    def mod(other)
+      if other.is_a?(Number)
+        operate(other, :%)
+      else
+        raise NoMethodError.new(nil, :mod)
+      end
+    end
+
+    # The SassScript `==` operation.
+    #
+    # @param other [Value] The right-hand side of the operator
+    # @return [Boolean] Whether this number is equal to the other object
+    def eq(other)
+      return Bool::FALSE unless other.is_a?(Sass::Script::Value::Number)
+      this = self
+      begin
+        if unitless?
+          this = this.coerce(other.numerator_units, other.denominator_units)
+        else
+          other = other.coerce(@numerator_units, @denominator_units)
+        end
+      rescue Sass::UnitConversionError
+        return Bool::FALSE
+      end
+      Bool.new(this.value == other.value)
+    end
+
+    def hash
+      [value, numerator_units, denominator_units].hash
+    end
+
+    # Hash-equality works differently than `==` equality for numbers.
+    # Hash-equality must be transitive, so it just compares the exact value,
+    # numerator units, and denominator units.
+    def eql?(other)
+      value == other.value && numerator_units == other.numerator_units &&
+        denominator_units == other.denominator_units
+    end
+
+    # The SassScript `>` operation.
+    #
+    # @param other [Number] The right-hand side of the operator
+    # @return [Boolean] Whether this number is greater than the other
+    # @raise [NoMethodError] if `other` is an invalid type
+    def gt(other)
+      raise NoMethodError.new(nil, :gt) unless other.is_a?(Number)
+      operate(other, :>)
+    end
+
+    # The SassScript `>=` operation.
+    #
+    # @param other [Number] The right-hand side of the operator
+    # @return [Boolean] Whether this number is greater than or equal to the other
+    # @raise [NoMethodError] if `other` is an invalid type
+    def gte(other)
+      raise NoMethodError.new(nil, :gte) unless other.is_a?(Number)
+      operate(other, :>=)
+    end
+
+    # The SassScript `<` operation.
+    #
+    # @param other [Number] The right-hand side of the operator
+    # @return [Boolean] Whether this number is less than the other
+    # @raise [NoMethodError] if `other` is an invalid type
+    def lt(other)
+      raise NoMethodError.new(nil, :lt) unless other.is_a?(Number)
+      operate(other, :<)
+    end
+
+    # The SassScript `<=` operation.
+    #
+    # @param other [Number] The right-hand side of the operator
+    # @return [Boolean] Whether this number is less than or equal to the other
+    # @raise [NoMethodError] if `other` is an invalid type
+    def lte(other)
+      raise NoMethodError.new(nil, :lte) unless other.is_a?(Number)
+      operate(other, :<=)
+    end
+
+    # @return [String] The CSS representation of this number
+    # @raise [Sass::SyntaxError] if this number has units that can't be used in CSS
+    #   (e.g. `px*in`)
+    def to_s(opts = {})
+      return original if original
+      raise Sass::SyntaxError.new("#{inspect} isn't a valid CSS value.") unless legal_units?
+      inspect
+    end
+
+    # Returns a readable representation of this number.
+    #
+    # This representation is valid CSS (and valid SassScript)
+    # as long as there is only one unit.
+    #
+    # @return [String] The representation
+    def inspect(opts = {})
+      return original if original
+
+      value = self.class.round(self.value)
+      str = value.to_s
+
+      # Ruby will occasionally print in scientific notation if the number is
+      # small enough. That's technically valid CSS, but it's not well-supported
+      # and confusing.
+      str = ("%0.#{self.class.precision}f" % value).gsub(/0*$/, '') if str.include?('e')
+
+      unitless? ? str : "#{str}#{unit_str}"
+    end
+    alias_method :to_sass, :inspect
+
+    # @return [Fixnum] The integer value of the number
+    # @raise [Sass::SyntaxError] if the number isn't an integer
+    def to_i
+      super unless int?
+      value.to_i
+    end
+
+    # @return [Boolean] Whether or not this number is an integer.
+    def int?
+      value % 1 == 0.0
+    end
+
+    # @return [Boolean] Whether or not this number has no units.
+    def unitless?
+      @numerator_units.empty? && @denominator_units.empty?
+    end
+
+    # Checks whether the number has the numerator unit specified.
+    #
+    # @example
+    #   number = Sass::Script::Value::Number.new(10, "px")
+    #   number.is_unit?("px") => true
+    #   number.is_unit?(nil) => false
+    #
+    # @param unit [::String, nil] The unit the number should have or nil if the number
+    #   should be unitless.
+    # @see Number#unitless? The unitless? method may be more readable.
+    def is_unit?(unit)
+      if unit
+        denominator_units.size == 0 && numerator_units.size == 1 && numerator_units.first == unit
+      else
+        unitless?
+      end
+    end
+
+    # @return [Boolean] Whether or not this number has units that can be represented in CSS
+    #   (that is, zero or one \{#numerator\_units}).
+    def legal_units?
+      (@numerator_units.empty? || @numerator_units.size == 1) && @denominator_units.empty?
+    end
+
+    # Returns this number converted to other units.
+    # The conversion takes into account the relationship between e.g. mm and cm,
+    # as well as between e.g. in and cm.
+    #
+    # If this number has no units, it will simply return itself
+    # with the given units.
+    #
+    # An incompatible coercion, e.g. between px and cm, will raise an error.
+    #
+    # @param num_units [Array<String>] The numerator units to coerce this number into.
+    #   See {\#numerator\_units}
+    # @param den_units [Array<String>] The denominator units to coerce this number into.
+    #   See {\#denominator\_units}
+    # @return [Number] The number with the new units
+    # @raise [Sass::UnitConversionError] if the given units are incompatible with the number's
+    #   current units
+    def coerce(num_units, den_units)
+      Number.new(if unitless?
+                   value
+                 else
+                   value * coercion_factor(@numerator_units, num_units) /
+                     coercion_factor(@denominator_units, den_units)
+                 end, num_units, den_units)
+    end
+
+    # @param other [Number] A number to decide if it can be compared with this number.
+    # @return [Boolean] Whether or not this number can be compared with the other.
+    def comparable_to?(other)
+      operate(other, :+)
+      true
+    rescue Sass::UnitConversionError
+      false
+    end
+
+    # Returns a human readable representation of the units in this number.
+    # For complex units this takes the form of:
+    # numerator_unit1 * numerator_unit2 / denominator_unit1 * denominator_unit2
+    # @return [String] a string that represents the units in this number
+    def unit_str
+      rv = @numerator_units.sort.join("*")
+      if @denominator_units.any?
+        rv << "/"
+        rv << @denominator_units.sort.join("*")
+      end
+      rv
+    end
+
+    private
+
+    # @private
+    def self.round(num)
+      if num.is_a?(Float) && (num.infinite? || num.nan?)
+        num
+      elsif num % 1 == 0.0
+        num.to_i
+      else
+        ((num * precision_factor).round / precision_factor).to_f
+      end
+    end
+
+    OPERATIONS = [:+, :-, :<=, :<, :>, :>=, :%]
+
+    def operate(other, operation)
+      this = self
+      if OPERATIONS.include?(operation)
+        if unitless?
+          this = this.coerce(other.numerator_units, other.denominator_units)
+        else
+          other = other.coerce(@numerator_units, @denominator_units)
+        end
+      end
+      # avoid integer division
+      value = :/ == operation ? this.value.to_f : this.value
+      result = value.send(operation, other.value)
+
+      if result.is_a?(Numeric)
+        Number.new(result, *compute_units(this, other, operation))
+      else # Boolean op
+        Bool.new(result)
+      end
+    end
+
+    def coercion_factor(from_units, to_units)
+      # get a list of unmatched units
+      from_units, to_units = sans_common_units(from_units, to_units)
+
+      if from_units.size != to_units.size || !convertable?(from_units | to_units)
+        raise Sass::UnitConversionError.new(
+          "Incompatible units: '#{from_units.join('*')}' and '#{to_units.join('*')}'.")
+      end
+
+      from_units.zip(to_units).inject(1) {|m, p| m * conversion_factor(p[0], p[1])}
+    end
+
+    def compute_units(this, other, operation)
+      case operation
+      when :*
+        [this.numerator_units + other.numerator_units,
+         this.denominator_units + other.denominator_units]
+      when :/
+        [this.numerator_units + other.denominator_units,
+         this.denominator_units + other.numerator_units]
+      else
+        [this.numerator_units, this.denominator_units]
+      end
+    end
+
+    def normalize!
+      return if unitless?
+      @numerator_units, @denominator_units =
+        sans_common_units(@numerator_units, @denominator_units)
+
+      @denominator_units.each_with_index do |d, i|
+        if convertable?(d) && (u = @numerator_units.find(&method(:convertable?)))
+          @value /= conversion_factor(d, u)
+          @denominator_units.delete_at(i)
+          @numerator_units.delete_at(@numerator_units.index(u))
+        end
+      end
+    end
+
+    # This is the source data for all the unit logic. It's pre-processed to make
+    # it efficient to figure out whether a set of units is mutually compatible
+    # and what the conversion ratio is between two units.
+    #
+    # These come from http://www.w3.org/TR/2012/WD-css3-values-20120308/.
+    relative_sizes = [
+      {
+        'in' => Rational(1),
+        'cm' => Rational(1, 2.54),
+        'pc' => Rational(1, 6),
+        'mm' => Rational(1, 25.4),
+        'pt' => Rational(1, 72),
+        'px' => Rational(1, 96)
+      },
+      {
+        'deg'  => Rational(1, 360),
+        'grad' => Rational(1, 400),
+        'rad'  => Rational(1, 2 * Math::PI),
+        'turn' => Rational(1)
+      },
+      {
+        's'  => Rational(1),
+        'ms' => Rational(1, 1000)
+      },
+      {
+        'Hz'  => Rational(1),
+        'kHz' => Rational(1000)
+      },
+      {
+        'dpi'  => Rational(1),
+        'dpcm' => Rational(1, 2.54),
+        'dppx' => Rational(1, 96)
+      }
+    ]
+
+    # A hash from each known unit to the set of units that it's mutually
+    # convertible with.
+    MUTUALLY_CONVERTIBLE = {}
+    relative_sizes.map do |values|
+      set = values.keys.to_set
+      values.keys.each {|name| MUTUALLY_CONVERTIBLE[name] = set}
+    end
+
+    # A two-dimensional hash from two units to the conversion ratio between
+    # them. Multiply `X` by `CONVERSION_TABLE[X][Y]` to convert it to `Y`.
+    CONVERSION_TABLE = {}
+    relative_sizes.each do |values|
+      values.each do |(name1, value1)|
+        CONVERSION_TABLE[name1] ||= {}
+        values.each do |(name2, value2)|
+          value = value1 / value2
+          CONVERSION_TABLE[name1][name2] = value.denominator == 1 ? value.to_i : value.to_f
+        end
+      end
+    end
+
+    def conversion_factor(from_unit, to_unit)
+      CONVERSION_TABLE[from_unit][to_unit]
+    end
+
+    def convertable?(units)
+      units = Array(units).to_set
+      return true if units.empty?
+      return false unless (mutually_convertible = MUTUALLY_CONVERTIBLE[units.first])
+      units.subset?(mutually_convertible)
+    end
+
+    def sans_common_units(units1, units2)
+      units2 = units2.dup
+      # Can't just use -, because we want px*px to coerce properly to px*mm
+      units1 = units1.map do |u|
+        j = units2.index(u)
+        next u unless j
+        units2.delete_at(j)
+        nil
+      end
+      units1.compact!
+      return units1, units2
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/script/value/string.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/script/value/string.rb
new file mode 100644
index 0000000..1d47980
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/script/value/string.rb
@@ -0,0 +1,97 @@
+# -*- coding: utf-8 -*-
+module Sass::Script::Value
+  # A SassScript object representing a CSS string *or* a CSS identifier.
+  class String < Base
+    # The Ruby value of the string.
+    #
+    # @return [String]
+    attr_reader :value
+
+    # Whether this is a CSS string or a CSS identifier.
+    # The difference is that strings are written with double-quotes,
+    # while identifiers aren't.
+    #
+    # @return [Symbol] `:string` or `:identifier`
+    attr_reader :type
+
+    def self.value(contents)
+      contents.gsub("\\\n", "").gsub(/\\(?:([0-9a-fA-F]{1,6})\s?|(.))/) do
+        next $2 if $2
+        # Handle unicode escapes as per CSS Syntax Level 3 section 4.3.8.
+        code_point = $1.to_i(16)
+        if code_point == 0 || code_point > 0x10FFFF ||
+            (code_point >= 0xD800 && code_point <= 0xDFFF)
+          '�'
+        else
+          [code_point].pack("U")
+        end
+      end
+    end
+
+    def self.quote(contents, quote = nil)
+      # Short-circuit if there are no characters that need quoting.
+      unless contents =~ /[\n\\"']/
+        quote ||= '"'
+        return "#{quote}#{contents}#{quote}"
+      end
+
+      if quote.nil?
+        if contents.include?('"')
+          if contents.include?("'")
+            quote = '"'
+          else
+            quote = "'"
+          end
+        else
+          quote = '"'
+        end
+      end
+
+      # Replace single backslashes with multiples.
+      contents = contents.gsub("\\", "\\\\\\\\")
+
+      if quote == '"'
+        contents = contents.gsub('"', "\\\"")
+      else
+        contents = contents.gsub("'", "\\'")
+      end
+
+      contents = contents.gsub(/\n(?![a-fA-F0-9\s])/, "\\a").gsub("\n", "\\a ")
+      "#{quote}#{contents}#{quote}"
+    end
+
+    # Creates a new string.
+    #
+    # @param value [String] See \{#value}
+    # @param type [Symbol] See \{#type}
+    def initialize(value, type = :identifier)
+      super(value)
+      @type = type
+    end
+
+    # @see Value#plus
+    def plus(other)
+      other_value = if other.is_a?(Sass::Script::Value::String)
+                      other.value
+                    else
+                      other.to_s(:quote => :none)
+                    end
+      Sass::Script::Value::String.new(value + other_value, type)
+    end
+
+    # @see Value#to_s
+    def to_s(opts = {})
+      return @value.gsub(/\n\s*/, ' ') if opts[:quote] == :none || @type == :identifier
+      Sass::Script::Value::String.quote(value, opts[:quote])
+    end
+
+    # @see Value#to_sass
+    def to_sass(opts = {})
+      to_s
+    end
+
+    def inspect
+      String.quote(value)
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.2.12/lib/sass/scss.rb b/backends/css/gems/sass-3.4.9/lib/sass/scss.rb
similarity index 100%
rename from backends/css/gems/sass-3.2.12/lib/sass/scss.rb
rename to backends/css/gems/sass-3.4.9/lib/sass/scss.rb
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/scss/css_parser.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/scss/css_parser.rb
new file mode 100644
index 0000000..d655816
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/scss/css_parser.rb
@@ -0,0 +1,42 @@
+require 'sass/script/css_parser'
+
+module Sass
+  module SCSS
+    # This is a subclass of {Parser} which only parses plain CSS.
+    # It doesn't support any Sass extensions, such as interpolation,
+    # parent references, nested selectors, and so forth.
+    # It does support all the same CSS hacks as the SCSS parser, though.
+    class CssParser < StaticParser
+      private
+
+      def placeholder_selector; nil; end
+      def parent_selector; nil; end
+      def interpolation(warn_for_color = false); nil; end
+      def use_css_import?; true; end
+
+      def block_child(context)
+        case context
+        when :ruleset
+          declaration
+        when :stylesheet
+          directive || ruleset
+        when :directive
+          directive || declaration_or_ruleset
+        end
+      end
+
+      def nested_properties!(node)
+        expected('expression (e.g. 1px, bold)')
+      end
+
+      def ruleset
+        start_pos = source_position
+        return unless (selector = selector_comma_sequence)
+        block(node(Sass::Tree::RuleNode.new(selector, range(start_pos)), start_pos), :ruleset)
+      end
+
+      @sass_script_parser = Class.new(Sass::Script::CssParser)
+      @sass_script_parser.send(:include, ScriptParser)
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/scss/parser.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/scss/parser.rb
new file mode 100644
index 0000000..65378ea
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/scss/parser.rb
@@ -0,0 +1,1211 @@
+# -*- coding: utf-8 -*-
+require 'set'
+
+module Sass
+  module SCSS
+    # The parser for SCSS.
+    # It parses a string of code into a tree of {Sass::Tree::Node}s.
+    class Parser
+      # Expose for the SASS parser.
+      attr_accessor :offset
+
+      # @param str [String, StringScanner] The source document to parse.
+      #   Note that `Parser` *won't* raise a nice error message if this isn't properly parsed;
+      #   for that, you should use the higher-level {Sass::Engine} or {Sass::CSS}.
+      # @param filename [String] The name of the file being parsed. Used for
+      #   warnings and source maps.
+      # @param importer [Sass::Importers::Base] The importer used to import the
+      #   file being parsed. Used for source maps.
+      # @param line [Fixnum] The 1-based line on which the source string appeared,
+      #   if it's part of another document.
+      # @param offset [Fixnum] The 1-based character (not byte) offset in the line on
+      #   which the source string starts. Used for error reporting and sourcemap
+      #   building.
+      # @comment
+      #   rubocop:disable ParameterLists
+      def initialize(str, filename, importer, line = 1, offset = 1)
+        # rubocop:enable ParameterLists
+        @template = str
+        @filename = filename
+        @importer = importer
+        @line = line
+        @offset = offset
+        @strs = []
+      end
+
+      # Parses an SCSS document.
+      #
+      # @return [Sass::Tree::RootNode] The root node of the document tree
+      # @raise [Sass::SyntaxError] if there's a syntax error in the document
+      def parse
+        init_scanner!
+        root = stylesheet
+        expected("selector or at-rule") unless root && @scanner.eos?
+        root
+      end
+
+      # Parses an identifier with interpolation.
+      # Note that this won't assert that the identifier takes up the entire input string;
+      # it's meant to be used with `StringScanner`s as part of other parsers.
+      #
+      # @return [Array<String, Sass::Script::Tree::Node>, nil]
+      #   The interpolated identifier, or nil if none could be parsed
+      def parse_interp_ident
+        init_scanner!
+        interp_ident
+      end
+
+      # Parses a media query list.
+      #
+      # @return [Sass::Media::QueryList] The parsed query list
+      # @raise [Sass::SyntaxError] if there's a syntax error in the query list,
+      #   or if it doesn't take up the entire input string.
+      def parse_media_query_list
+        init_scanner!
+        ql = media_query_list
+        expected("media query list") unless ql && @scanner.eos?
+        ql
+      end
+
+      # Parses an at-root query.
+      #
+      # @return [Array<String, Sass::Script;:Tree::Node>] The interpolated query.
+      # @raise [Sass::SyntaxError] if there's a syntax error in the query,
+      #   or if it doesn't take up the entire input string.
+      def parse_at_root_query
+        init_scanner!
+        query = at_root_query
+        expected("@at-root query list") unless query && @scanner.eos?
+        query
+      end
+
+      # Parses a supports query condition.
+      #
+      # @return [Sass::Supports::Condition] The parsed condition
+      # @raise [Sass::SyntaxError] if there's a syntax error in the condition,
+      #   or if it doesn't take up the entire input string.
+      def parse_supports_condition
+        init_scanner!
+        condition = supports_condition
+        expected("supports condition") unless condition && @scanner.eos?
+        condition
+      end
+
+      private
+
+      include Sass::SCSS::RX
+
+      def source_position
+        Sass::Source::Position.new(@line, @offset)
+      end
+
+      def range(start_pos, end_pos = source_position)
+        Sass::Source::Range.new(start_pos, end_pos, @filename, @importer)
+      end
+
+      def init_scanner!
+        @scanner =
+          if @template.is_a?(StringScanner)
+            @template
+          else
+            Sass::Util::MultibyteStringScanner.new(@template.gsub("\r", ""))
+          end
+      end
+
+      def stylesheet
+        node = node(Sass::Tree::RootNode.new(@scanner.string), source_position)
+        block_contents(node, :stylesheet) {s(node)}
+      end
+
+      def s(node)
+        while tok(S) || tok(CDC) || tok(CDO) || (c = tok(SINGLE_LINE_COMMENT)) || (c = tok(COMMENT))
+          next unless c
+          process_comment c, node
+          c = nil
+        end
+        true
+      end
+
+      def ss
+        nil while tok(S) || tok(SINGLE_LINE_COMMENT) || tok(COMMENT)
+        true
+      end
+
+      def ss_comments(node)
+        while tok(S) || (c = tok(SINGLE_LINE_COMMENT)) || (c = tok(COMMENT))
+          next unless c
+          process_comment c, node
+          c = nil
+        end
+
+        true
+      end
+
+      def whitespace
+        return unless tok(S) || tok(SINGLE_LINE_COMMENT) || tok(COMMENT)
+        ss
+      end
+
+      def process_comment(text, node)
+        silent = text =~ %r{\A//}
+        loud = !silent && text =~ %r{\A/[/*]!}
+        line = @line - text.count("\n")
+
+        if silent
+          value = [text.sub(%r{\A\s*//}, '/*').gsub(%r{^\s*//}, ' *') + ' */']
+        else
+          value = Sass::Engine.parse_interp(
+            text, line, @scanner.pos - text.size, :filename => @filename)
+          string_before_comment = @scanner string[0    scanner pos - text.length]
+          newline_before_comment = string_before_comment.rindex("\n")
+          last_line_before_comment =
+            if newline_before_comment
+              string_before_comment[newline_before_comment + 1..-1]
+            else
+              string_before_comment
+            end
+          value.unshift(last_line_before_comment.gsub(/[^\s]/, ' '))
+        end
+
+        type = if silent
+                 :silent
+               elsif loud
+                 :loud
+               else
+                 :normal
+               end
+        comment = Sass::Tree::CommentNode.new(value, type)
+        comment.line = line
+        node << comment
+      end
+
+      DIRECTIVES = Set[:mixin, :include, :function, :return, :debug, :warn, :for,
+        :each, :while, :if, :else, :extend, :import, :media, :charset, :content,
+        :_moz_document, :at_root, :error]
+
+      PREFIXED_DIRECTIVES = Set[:supports]
+
+      def directive
+        start_pos = source_position
+        return unless tok(/@/)
+        name = tok!(IDENT)
+        ss
+
+        if (dir = special_directive(name, start_pos))
+          return dir
+        elsif (dir = prefixed_directive(name, start_pos))
+          return dir
+        end
+
+        val = almost_any_value
+        val = val ? ["@#{name} "] + Sass::Util.strip_string_array(val) : ["@#{name}"]
+        directive_body(val, start_pos)
+      end
+
+      def directive_body(value, start_pos)
+        node = Sass::Tree::DirectiveNode.new(value)
+
+        if tok(/\{/)
+          node.has_children = true
+          block_contents(node, :directive)
+          tok!(/\}/)
+        end
+
+        node(node, start_pos)
+      end
+
+      def special_directive(name, start_pos)
+        sym = name.gsub('-', '_').to_sym
+        DIRECTIVES.include?(sym) && send("#{sym}_directive", start_pos)
+      end
+
+      def prefixed_directive(name, start_pos)
+        sym = deprefix(name).gsub('-', '_').to_sym
+        PREFIXED_DIRECTIVES.include?(sym) && send("#{sym}_directive", name, start_pos)
+      end
+
+      def mixin_directive(start_pos)
+        name = tok! IDENT
+        args, splat = sass_script(:parse_mixin_definition_arglist)
+        ss
+        block(node(Sass::Tree::MixinDefNode.new(name, args, splat), start_pos), :directive)
+      end
+
+      def include_directive(start_pos)
+        name = tok! IDENT
+        args, keywords, splat, kwarg_splat = sass_script(:parse_mixin_include_arglist)
+        ss
+        include_node = node(
+          Sass::Tree::MixinNode.new(name, args, keywords, splat, kwarg_splat), start_pos)
+        if tok?(/\{/)
+          include_node.has_children = true
+          block(include_node, :directive)
+        else
+          include_node
+        end
+      end
+
+      def content_directive(start_pos)
+        ss
+        node(Sass::Tree::ContentNode.new, start_pos)
+      end
+
+      def function_directive(start_pos)
+        name = tok! IDENT
+        args, splat = sass_script(:parse_function_definition_arglist)
+        ss
+        block(node(Sass::Tree::FunctionNode.new(name, args, splat), start_pos), :function)
+      end
+
+      def return_directive(start_pos)
+        node(Sass::Tree::ReturnNode.new(sass_script(:parse)), start_pos)
+      end
+
+      def debug_directive(start_pos)
+        node(Sass::Tree::DebugNode.new(sass_script(:parse)), start_pos)
+      end
+
+      def warn_directive(start_pos)
+        node(Sass::Tree::WarnNode.new(sass_script(:parse)), start_pos)
+      end
+
+      def for_directive(start_pos)
+        tok!(/\$/)
+        var = tok! IDENT
+        ss
+
+        tok!(/from/)
+        from = sass_script(:parse_until, Set["to", "through"])
+        ss
+
+        @expected = '"to" or "through"'
+        exclusive = (tok(/to/) || tok!(/through/)) == 'to'
+        to = sass_script(:parse)
+        ss
+
+        block(node(Sass::Tree::ForNode.new(var, from, to, exclusive), start_pos), :directive)
+      end
+
+      def each_directive(start_pos)
+        tok!(/\$/)
+        vars = [tok!(IDENT)]
+        ss
+        while tok(/,/)
+          ss
+          tok!(/\$/)
+          vars << tok!(IDENT)
+          ss
+        end
+
+        tok!(/in/)
+        list = sass_script(:parse)
+        ss
+
+        block(node(Sass::Tree::EachNode.new(vars, list), start_pos), :directive)
+      end
+
+      def while_directive(start_pos)
+        expr = sass_script(:parse)
+        ss
+        block(node(Sass::Tree::WhileNode.new(expr), start_pos), :directive)
+      end
+
+      def if_directive(start_pos)
+        expr = sass_script(:parse)
+        ss
+        node = block(node(Sass::Tree::IfNode.new(expr), start_pos), :directive)
+        pos = @scanner.pos
+        line = @line
+        ss
+
+        else_block(node) ||
+          begin
+            # Backtrack in case there are any comments we want to parse
+            @scanner.pos = pos
+            @line = line
+            node
+          end
+      end
+
+      def else_block(node)
+        start_pos = source_position
+        return unless tok(/@else/)
+        ss
+        else_node = block(
+          node(Sass::Tree::IfNode.new((sass_script(:parse) if tok(/if/))), start_pos),
+          :directive)
+        node.add_else(else_node)
+        pos = @scanner.pos
+        line = @line
+        ss
+
+        else_block(node) ||
+          begin
+            # Backtrack in case there are any comments we want to parse
+            @scanner.pos = pos
+            @line = line
+            node
+          end
+      end
+
+      def else_directive(start_pos)
+        err("Invalid CSS: @else must come after @if")
+      end
+
+      def extend_directive(start_pos)
+        selector_start_pos = source_position
+        @expected = "selector"
+        selector = Sass::Util.strip_string_array(expr!(:almost_any_value))
+        optional = tok(OPTIONAL)
+        ss
+        node(Sass::Tree::ExtendNode.new(selector, !!optional, range(selector_start_pos)), start_pos)
+      end
+
+      def import_directive(start_pos)
+        values = []
+
+        loop do
+          values << expr!(:import_arg)
+          break if use_css_import?
+          break unless tok(/,/)
+          ss
+        end
+
+        values
+      end
+
+      def import_arg
+        start_pos = source_position
+        return unless (str = string) || (uri = tok?(/url\(/i))
+        if uri
+          str = sass_script(:parse_string)
+          ss
+          media = media_query_list
+          ss
+          return node(Tree::CssImportNode.new(str, media.to_a), start_pos)
+        end
+        ss
+
+        media = media_query_list
+        if str =~ %r{^(https?:)?//} || media || use_css_import?
+          return node(Sass::Tree::CssImportNode.new(
+              Sass::Script::Value::String.quote(str), media.to_a), start_pos)
+        end
+
+        node(Sass::Tree::ImportNode.new(str.strip), start_pos)
+      end
+
+      def use_css_import?; false; end
+
+      def media_directive(start_pos)
+        block(node(Sass::Tree::MediaNode.new(expr!(:media_query_list).to_a), start_pos), :directive)
+      end
+
+      # http://www.w3.org/TR/css3-mediaqueries/#syntax
+      def media_query_list
+        query = media_query
+        return unless query
+        queries = [query]
+
+        ss
+        while tok(/,/)
+          ss; queries << expr!(:media_query)
+        end
+        ss
+
+        Sass::Media::QueryList.new(queries)
+      end
+
+      def media_query
+        if (ident1 = interp_ident)
+          ss
+          ident2 = interp_ident
+          ss
+          if ident2 && ident2.length == 1 && ident2[0].is_a?(String) && ident2[0].downcase == 'and'
+            query = Sass::Media::Query.new([], ident1, [])
+          else
+            if ident2
+              query = Sass::Media::Query.new(ident1, ident2, [])
+            else
+              query = Sass::Media::Query.new([], ident1, [])
+            end
+            return query unless tok(/and/i)
+            ss
+          end
+        end
+
+        if query
+          expr = expr!(:media_expr)
+        else
+          expr = media_expr
+          return unless expr
+        end
+        query ||= Sass::Media::Query.new([], [], [])
+        query.expressions << expr
+
+        ss
+        while tok(/and/i)
+          ss; query.expressions << expr!(:media_expr)
+        end
+
+        query
+      end
+
+      def query_expr
+        interp = interpolation
+        return interp if interp
+        return unless tok(/\(/)
+        res = ['(']
+        ss
+        res << sass_script(:parse)
+
+        if tok(/:/)
+          res << ': '
+          ss
+          res << sass_script(:parse)
+        end
+        res << tok!(/\)/)
+        ss
+        res
+      end
+
+      # Aliases allow us to use different descriptions if the same
+      # expression fails in different contexts.
+      alias_method :media_expr, :query_expr
+      alias_method :at_root_query, :query_expr
+
+      def charset_directive(start_pos)
+        name = expr!(:string)
+        ss
+        node(Sass::Tree::CharsetNode.new(name), start_pos)
+      end
+
+      # The document directive is specified in
+      # http://www.w3.org/TR/css3-conditional/, but Gecko allows the
+      # `url-prefix` and `domain` functions to omit quotation marks, contrary to
+      # the standard.
+      #
+      # We could parse all document directives according to Mozilla's syntax,
+      # but if someone's using e.g. @-webkit-document we don't want them to
+      # think WebKit works sans quotes.
+      def _moz_document_directive(start_pos)
+        res = ["@-moz-document "]
+        loop do
+          res << str {ss} << expr!(:moz_document_function)
+          if (c = tok(/,/))
+            res << c
+          else
+            break
+          end
+        end
+        directive_body(res.flatten, start_pos)
+      end
+
+      def moz_document_function
+        val = interp_uri || _interp_string(:url_prefix) ||
+          _interp_string(:domain) || function(!:allow_var) || interpolation
+        return unless val
+        ss
+        val
+      end
+
+      def at_root_directive(start_pos)
+        if tok?(/\(/) && (expr = at_root_query)
+          return block(node(Sass::Tree::AtRootNode.new(expr), start_pos), :directive)
+        end
+
+        at_root_node = node(Sass::Tree::AtRootNode.new, start_pos)
+        rule_node = ruleset
+        return block(at_root_node, :stylesheet) unless rule_node
+        at_root_node << rule_node
+        at_root_node
+      end
+
+      def at_root_directive_list
+        return unless (first = tok(IDENT))
+        arr = [first]
+        ss
+        while (e = tok(IDENT))
+          arr << e
+          ss
+        end
+        arr
+      end
+
+      def error_directive(start_pos)
+        node(Sass::Tree::ErrorNode.new(sass_script(:parse)), start_pos)
+      end
+
+      # http://www.w3.org/TR/css3-conditional/
+      def supports_directive(name, start_pos)
+        condition = expr!(:supports_condition)
+        node = Sass::Tree::SupportsNode.new(name, condition)
+
+        tok!(/\{/)
+        node.has_children = true
+        block_contents(node, :directive)
+        tok!(/\}/)
+
+        node(node, start_pos)
+      end
+
+      def supports_condition
+        supports_negation || supports_operator || supports_interpolation
+      end
+
+      def supports_negation
+        return unless tok(/not/i)
+        ss
+        Sass::Supports::Negation.new(expr!(:supports_condition_in_parens))
+      end
+
+      def supports_operator
+        cond = supports_condition_in_parens
+        return unless cond
+        while (op = tok(/and|or/i))
+          ss
+          cond = Sass::Supports::Operator.new(
+            cond, expr!(:supports_condition_in_parens), op)
+        end
+        cond
+      end
+
+      def supports_condition_in_parens
+        interp = supports_interpolation
+        return interp if interp
+        return unless tok(/\(/); ss
+        if (cond = supports_condition)
+          tok!(/\)/); ss
+          cond
+        else
+          name = sass_script(:parse)
+          tok!(/:/); ss
+          value = sass_script(:parse)
+          tok!(/\)/); ss
+          Sass::Supports::Declaration.new(name, value)
+        end
+      end
+
+      def supports_declaration_condition
+        return unless tok(/\(/); ss
+        supports_declaration_body
+      end
+
+      def supports_interpolation
+        interp = interpolation
+        return unless interp
+        ss
+        Sass::Supports::Interpolation.new(interp)
+      end
+
+      def variable
+        return unless tok(/\$/)
+        start_pos = source_position
+        name = tok!(IDENT)
+        ss; tok!(/:/); ss
+
+        expr = sass_script(:parse)
+        while tok(/!/)
+          flag_name = tok!(IDENT)
+          if flag_name == 'default'
+            guarded ||= true
+          elsif flag_name == 'global'
+            global ||= true
+          else
+            raise Sass::SyntaxError.new("Invalid flag \"!#{flag_name}\".", :line => @line)
+          end
+          ss
+        end
+
+        result = Sass::Tree::VariableNode.new(name, expr, guarded, global)
+        node(result, start_pos)
+      end
+
+      def operator
+        # Many of these operators (all except / and ,)
+        # are disallowed by the CSS spec,
+        # but they're included here for compatibility
+        # with some proprietary MS properties
+        str {ss if tok(/[\/,:.=]/)}
+      end
+
+      def ruleset
+        start_pos = source_position
+        return unless (rules = almost_any_value)
+        block(node(
+          Sass::Tree::RuleNode.new(rules, range(start_pos)), start_pos), :ruleset)
+      end
+
+      def block(node, context)
+        node.has_children = true
+        tok!(/\{/)
+        block_contents(node, context)
+        tok!(/\}/)
+        node
+      end
+
+      # A block may contain declarations and/or rulesets
+      def block_contents(node, context)
+        block_given? ? yield : ss_comments(node)
+        node << (child = block_child(context))
+        while tok(/;/) || has_children?(child)
+          block_given? ? yield : ss_comments(node)
+          node << (child = block_child(context))
+        end
+        node
+      end
+
+      def block_child(context)
+        return variable || directive if context == :function
+        return variable || directive || ruleset if context == :stylesheet
+        variable || directive || declaration_or_ruleset
+      end
+
+      def has_children?(child_or_array)
+        return false unless child_or_array
+        return child_or_array.last.has_children if child_or_array.is_a?(Array)
+        child_or_array.has_children
+      end
+
+      # When parsing the contents of a ruleset, it can be difficult to tell
+      # declarations apart from nested rulesets. Since we don't thoroughly parse
+      # selectors until after resolving interpolation, we can share a bunch of
+      # the parsing of the two, but we need to disambiguate them first. We use
+      # the following criteria:
+      #
+      # * If the entity doesn't start with an identifier followed by a colon,
+      #   it's a selector. There are some additional mostly-unimportant cases
+      #   here to support various declaration hacks.
+      #
+      # * If the colon is followed by another colon, it's a selector.
+      #
+      # * Otherwise, if the colon is followed by anything other than
+      #   interpolation or a character that's valid as the beginning of an
+      #   identifier, it's a declaration.
+      #
+      # * If the colon is followed by interpolation or a valid identifier, try
+      #   parsing it as a declaration value. If this fails, backtrack and parse
+      #   it as a selector.
+      #
+      # * If the declaration value value valid but is followed by "{", backtrack
+      #   and parse it as a selector anyway. This ensures that ".foo:bar {" is
+      #   always parsed as a selector and never as a property with nested
+      #   properties beneath it.
+      def declaration_or_ruleset
+        start_pos = source_position
+        declaration = try_declaration
+
+        if declaration.nil?
+          return unless (selector = almost_any_value)
+        elsif declaration.is_a?(Array)
+          selector = declaration
+        else
+          # Declaration should be a PropNode.
+          return declaration
+        end
+
+        if (additional_selector = almost_any_value)
+          selector << additional_selector
+        end
+
+        block(node(
+          Sass::Tree::RuleNode.new(merge(selector), range(start_pos)), start_pos), :ruleset)
+      end
+
+      # Tries to parse a declaration, and returns the value parsed so far if it
+      # fails.
+      #
+      # This has three possible return types. It can return `nil`, indicating
+      # that parsing failed completely and the scanner hasn't moved forward at
+      # all. It can return an Array, indicating that parsing failed after
+      # consuming some text (possibly containing interpolation), which is
+      # returned. Or it can return a PropNode, indicating that parsing
+      # succeeded.
+      def try_declaration
+        # This allows the "*prop: val", ":prop: val", "#prop: val", and ".prop:
+        # val" hacks.
+        name_start_pos = source_position
+        if (s = tok(/[:\*\.]|\#(?!\{)/))
+          name = [s, str {ss}]
+          return name unless (ident = interp_ident)
+          name << ident
+        else
+          return unless (name = interp_ident)
+          name = Array(name)
+        end
+
+        if (comment = tok(COMMENT))
+          name << comment
+        end
+        name_end_pos = source_position
+
+        mid = [str {ss}]
+        return name + mid unless tok(/:/)
+        mid << ':'
+        return name + mid + [':'] if tok(/:/)
+        mid << str {ss}
+        post_colon_whitespace = !mid.last.empty?
+        could_be_selector = !post_colon_whitespace && (tok?(IDENT_START) || tok?(INTERP_START))
+
+        value_start_pos = source_position
+        value = nil
+        error = catch_error do
+          value = value!
+          if tok?(/\{/)
+            # Properties that are ambiguous with selectors can't have additional
+            # properties nested beneath them.
+            tok!(/;/) if could_be_selector
+          elsif !tok?(/[;{}]/)
+            # We want an exception if there's no valid end-of-property character
+            # exists, but we don't want to consume it if it does.
+            tok!(/[;{}]/)
+          end
+        end
+
+        if error
+          rethrow error unless could_be_selector
+
+          # If the value would be followed by a semicolon, it's definitely
+          # supposed to be a property, not a selector.
+          additional_selector = almost_any_value
+          rethrow error if tok?(/;/)
+
+          return name + mid + (additional_selector || [])
+        end
+
+        value_end_pos = source_position
+        ss
+        require_block = tok?(/\{/)
+
+        node = node(Sass::Tree::PropNode.new(name.flatten.compact, value, :new),
+                    name_start_pos, value_end_pos)
+        node.name_source_range = range(name_start_pos, name_end_pos)
+        node.value_source_range = range(value_start_pos, value_end_pos)
+
+        return node unless require_block
+        nested_properties! node
+      end
+
+      # This production is similar to the CSS [`<any-value>`][any-value]
+      # production, but as the name implies, not quite the same. It's meant to
+      # consume values that could be a selector, an expression, or a combination
+      # of both. It respects strings and comments and supports interpolation. It
+      # will consume up to "{", "}", ";", or "!".
+      #
+      # [any-value]: http://dev.w3.org/csswg/css-variables/#typedef-any-value
+      #
+      # Values consumed by this production will usually be parsed more
+      # thoroughly once interpolation has been resolved.
+      def almost_any_value
+        return unless (tok = almost_any_value_token)
+        sel = [tok]
+        while (tok = almost_any_value_token)
+          sel << tok
+        end
+        merge(sel)
+      end
+
+      def almost_any_value_token
+        tok(%r{
+          (
+            \\.
+          |
+            (?!url\()
+            [^"'/\#!;\{\}] # "
+          |
+            /(?![/*])
+          |
+            \#(?!\{)
+          |
+            !(?![a-z]) # TODO: never consume "!" when issue 1126 is fixed.
+          )+
+        }xi) || tok(COMMENT) || tok(SINGLE_LINE_COMMENT) || interp_string || interp_uri ||
+                interpolation(:warn_for_color)
+      end
+
+      def declaration
+        # This allows the "*prop: val", ":prop: val", "#prop: val", and ".prop:
+        # val" hacks.
+        name_start_pos = source_position
+        if (s = tok(/[:\*\.]|\#(?!\{)/))
+          name = [s, str {ss}, *expr!(:interp_ident)]
+        else
+          return unless (name = interp_ident)
+          name = Array(name)
+        end
+
+        if (comment = tok(COMMENT))
+          name << comment
+        end
+        name_end_pos = source_position
+        ss
+
+        tok!(/:/)
+        ss
+        value_start_pos = source_position
+        value = value!
+        value_end_pos = source_position
+        ss
+        require_block = tok?(/\{/)
+
+        node = node(Sass::Tree::PropNode.new(name.flatten.compact, value, :new),
+                    name_start_pos, value_end_pos)
+        node.name_source_range = range(name_start_pos, name_end_pos)
+        node.value_source_range = range(value_start_pos, value_end_pos)
+
+        return node unless require_block
+        nested_properties! node
+      end
+
+      def value!
+        if tok?(/\{/)
+          str = Sass::Script::Tree::Literal.new(Sass::Script::Value::String.new(""))
+          str.line = source_position.line
+          str.source_range = range(source_position)
+          return str
+        end
+
+        start_pos = source_position
+        # This is a bit of a dirty trick:
+        # if the value is completely static,
+        # we don't parse it at all, and instead return a plain old string
+        # containing the value.
+        # This results in a dramatic speed increase.
+        if (val = tok(STATIC_VALUE, true))
+          str = Sass::Script::Tree::Literal.new(Sass::Script::Value::String.new(val.strip))
+          str.line = start_pos.line
+          str.source_range = range(start_pos)
+          return str
+        end
+        sass_script(:parse)
+      end
+
+      def nested_properties!(node)
+        @expected = 'expression (e.g. 1px, bold) or "{"'
+        block(node, :property)
+      end
+
+      def expr(allow_var = true)
+        t = term(allow_var)
+        return unless t
+        res = [t, str {ss}]
+
+        while (o = operator) && (t = term(allow_var))
+          res << o << t << str {ss}
+        end
+
+        res.flatten
+      end
+
+      def term(allow_var)
+        e = tok(NUMBER) ||
+            interp_uri ||
+            function(allow_var) ||
+            interp_string ||
+            tok(UNICODERANGE) ||
+            interp_ident ||
+            tok(HEXCOLOR) ||
+            (allow_var && var_expr)
+        return e if e
+
+        op = tok(/[+-]/)
+        return unless op
+        @expected = "number or function"
+        [op,
+         tok(NUMBER) || function(allow_var) || (allow_var && var_expr) || expr!(:interpolation)]
+      end
+
+      def function(allow_var)
+        name = tok(FUNCTION)
+        return unless name
+        if name == "expression(" || name == "calc("
+          str, _ = Sass::Shared.balance(@scanner, ?(, ?), 1)
+          [name, str]
+        else
+          [name, str {ss}, expr(allow_var), tok!(/\)/)]
+        end
+      end
+
+      def var_expr
+        return unless tok(/\$/)
+        line = @line
+        var = Sass::Script::Tree::Variable.new(tok!(IDENT))
+        var.line = line
+        var
+      end
+
+      def interpolation(warn_for_color = false)
+        return unless tok(INTERP_START)
+        sass_script(:parse_interpolated, warn_for_color)
+      end
+
+      def string
+        return unless tok(STRING)
+        Sass::Script::Value::String.value(@scanner[1] || @scanner[2])
+      end
+
+      def interp_string
+        _interp_string(:double) || _interp_string(:single)
+      end
+
+      def interp_uri
+        _interp_string(:uri)
+      end
+
+      def _interp_string(type)
+        start = tok(Sass::Script::Lexer::STRING_REGULAR_EXPRESSIONS[type][false])
+        return unless start
+        res = [start]
+
+        mid_re = Sass::Script::Lexer::STRING_REGULAR_EXPRESSIONS[type][true]
+        # @scanner[2].empty? means we've started an interpolated section
+        while @scanner[2] == '#{'
+          @scanner.pos -= 2 # Don't consume the #{
+          res.last.slice!(-2..-1)
+          res << expr!(:interpolation) << tok(mid_re)
+        end
+        res
+      end
+
+      def interp_ident(start = IDENT)
+        val = tok(start) || interpolation(:warn_for_color) || tok(IDENT_HYPHEN_INTERP, true)
+        return unless val
+        res = [val]
+        while (val = tok(NAME) || interpolation(:warn_for_color))
+          res << val
+        end
+        res
+      end
+
+      def interp_ident_or_var
+        id = interp_ident
+        return id if id
+        var = var_expr
+        return [var] if var
+      end
+
+      def str
+        @strs.push ""
+        yield
+        @strs.last
+      ensure
+        @strs.pop
+      end
+
+      def str?
+        pos = @scanner.pos
+        line = @line
+        offset = @offset
+        @strs.push ""
+        throw_error {yield} && @strs.last
+      rescue Sass::SyntaxError
+        @scanner.pos = pos
+        @line = line
+        @offset = offset
+        nil
+      ensure
+        @strs.pop
+      end
+
+      def node(node, start_pos, end_pos = source_position)
+        node.line = start_pos.line
+        node.source_range = range(start_pos, end_pos)
+        node
+      end
+
+      @sass_script_parser = Class.new(Sass::Script::Parser)
+      @sass_script_parser.send(:include, ScriptParser)
+
+      class << self
+        # @private
+        attr_accessor :sass_script_parser
+      end
+
+      def sass_script(*args)
+        parser = self.class.sass_script_parser.new(@scanner, @line, @offset,
+                                                   :filename => @filename, :importer => @importer)
+        result = parser.send(*args)
+        unless @strs.empty?
+          # Convert to CSS manually so that comments are ignored.
+          src = result.to_sass
+          @strs.each {|s| s << src}
+        end
+        @line = parser.line
+        @offset = parser.offset
+        result
+      rescue Sass::SyntaxError => e
+        throw(:_sass_parser_error, true) if @throw_error
+        raise e
+      end
+
+      def merge(arr)
+        arr && Sass::Util.merge_adjacent_strings([arr].flatten)
+      end
+
+      EXPR_NAMES = {
+        :media_query => "media query (e.g. print, screen, print and screen)",
+        :media_query_list => "media query (e.g. print, screen, print and screen)",
+        :media_expr => "media expression (e.g. (min-device-width: 800px))",
+        :at_root_query => "@at-root query (e.g. (without: media))",
+        :at_root_directive_list => '* or identifier',
+        :pseudo_args => "expression (e.g. fr, 2n+1)",
+        :interp_ident => "identifier",
+        :qualified_name => "identifier",
+        :expr => "expression (e.g. 1px, bold)",
+        :selector_comma_sequence => "selector",
+        :string => "string",
+        :import_arg => "file to import (string or url())",
+        :moz_document_function => "matching function (e.g. url-prefix(), domain())",
+        :supports_condition => "@supports condition (e.g. (display: flexbox))",
+        :supports_condition_in_parens => "@supports condition (e.g. (display: flexbox))",
+        :a_n_plus_b => "An+B expression",
+        :keyframes_selector_component => "from, to, or a percentage",
+        :keyframes_selector => "keyframes selector (e.g. 10%)"
+      }
+
+      TOK_NAMES = Sass::Util.to_hash(Sass::SCSS::RX.constants.map do |c|
+        [Sass::SCSS::RX.const_get(c), c.downcase]
+      end).merge(
+        IDENT => "identifier",
+        /[;{}]/ => '";"',
+        /\b(without|with)\b/ => '"with" or "without"'
+      )
+
+      def tok?(rx)
+        @scanner.match?(rx)
+      end
+
+      def expr!(name)
+        e = send(name)
+        return e if e
+        expected(EXPR_NAMES[name] || name.to_s)
+      end
+
+      def tok!(rx)
+        t = tok(rx)
+        return t if t
+        name = TOK_NAMES[rx]
+
+        unless name
+          # Display basic regexps as plain old strings
+          source = rx.source.gsub(/\\\//, '/')
+          string = rx.source.gsub(/\\(.)/, '\1')
+          name = source == Regexp.escape(string) ? string.inspect : rx.inspect
+        end
+
+        expected(name)
+      end
+
+      def expected(name)
+        throw(:_sass_parser_error, true) if @throw_error
+        self.class.expected(@scanner, @expected || name, @line)
+      end
+
+      def err(msg)
+        throw(:_sass_parser_error, true) if @throw_error
+        raise Sass::SyntaxError.new(msg, :line => @line)
+      end
+
+      def throw_error
+        old_throw_error, @throw_error = @throw_error, false
+        yield
+      ensure
+        @throw_error = old_throw_error
+      end
+
+      def catch_error(&block)
+        old_throw_error, @throw_error = @throw_error, true
+        pos = @scanner.pos
+        line = @line
+        offset = @offset
+        expected = @expected
+        if catch(:_sass_parser_error) {yield; false}
+          @scanner.pos = pos
+          @line = line
+          @offset = offset
+          @expected = expected
+          {:pos => pos, :line => line, :expected => @expected, :block => block}
+        end
+      ensure
+        @throw_error = old_throw_error
+      end
+
+      def rethrow(err)
+        if @throw_error
+          throw :_sass_parser_error, err
+        else
+          @scanner = Sass::Util::MultibyteStringScanner.new(@scanner.string)
+          @scanner.pos = err[:pos]
+          @line = err[:line]
+          @expected = err[:expected]
+          err[:block].call
+        end
+      end
+
+      # @private
+      def self.expected(scanner, expected, line)
+        pos = scanner.pos
+
+        after = scanner.string[0...pos]
+        # Get rid of whitespace between pos and the last token,
+        # but only if there's a newline in there
+        after.gsub!(/\s*\n\s*$/, '')
+        # Also get rid of stuff before the last newline
+        after.gsub!(/.*\n/, '')
+        after = "..." + after[-15..-1] if after.size > 18
+
+        was = scanner.rest.dup
+        # Get rid of whitespace between pos and the next token,
+        # but only if there's a newline in there
+        was.gsub!(/^\s*\n\s*/, '')
+        # Also get rid of stuff after the next newline
+        was.gsub!(/\n.*/, '')
+        was = was[0...15] + "..." if was.size > 18
+
+        raise Sass::SyntaxError.new(
+          "Invalid CSS after \"#{after}\": expected #{expected}, was \"#{was}\"",
+          :line => line)
+      end
+
+      # Avoid allocating lots of new strings for `#tok`.
+      # This is important because `#tok` is called all the time.
+      NEWLINE = "\n"
+
+      def tok(rx, last_group_lookahead = false)
+        res = @scanner.scan(rx)
+        if res
+          # This fixes https://github.com/nex3/sass/issues/104, which affects
+          # Ruby 1.8.7 and REE. This fix is to replace the ?= zero-width
+          # positive lookahead operator in the Regexp (which matches without
+          # consuming the matched group), with a match that does consume the
+          # group, but then rewinds the scanner and removes the group from the
+          # end of the matched string. This fix makes the assumption that the
+          # matched group will always occur at the end of the match.
+          if last_group_lookahead && @scanner[-1]
+            @scanner.pos -= @scanner[-1].length
+            res.slice!(- scanner[-1] length  -1)
+          end
+
+          newline_count = res.count(NEWLINE)
+          if newline_count > 0
+            @line += newline_count
+            @offset = res[res.rindex(NEWLINE)..-1].size
+          else
+            @offset += res.size
+          end
+
+          @expected = nil
+          if ! strs empty? && rx != COMMENT && rx != SINGLE_LINE_COMMENT
+            @strs.each {|s| s << res}
+          end
+          res
+        end
+      end
+
+      # Remove a vendor prefix from `str`.
+      def deprefix(str)
+        str.gsub(/^-[a-zA-Z0-9]+-/, '')
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/scss/rx.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/scss/rx.rb
new file mode 100644
index 0000000..2226157
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/scss/rx.rb
@@ -0,0 +1,141 @@
+# -*- coding: utf-8 -*-
+module Sass
+  module SCSS
+    # A module containing regular expressions used
+    # for lexing tokens in an SCSS document.
+    # Most of these are taken from [the CSS3 spec](http://www.w3.org/TR/css3-syntax/#lexical),
+    # although some have been modified for various reasons.
+    module RX
+      # Takes a string and returns a CSS identifier
+      # that will have the value of the given string.
+      #
+      # @param str [String] The string to escape
+      # @return [String] The escaped string
+      def self.escape_ident(str)
+        return "" if str.empty?
+        return "\\#{str}" if str == '-' || str == '_'
+        out = ""
+        value = str.dup
+        out << value.slice!(0...1) if value =~ /^[-_]/
+        if value[0...1] =~ NMSTART
+          out << value.slice!(0...1)
+        else
+          out << escape_char(value.slice!(0...1))
+        end
+        out << value.gsub(/[^a-zA-Z0-9_-]/) {|c| escape_char c}
+        out
+      end
+
+      # Escapes a single character for a CSS identifier.
+      #
+      # @param c [String] The character to escape. Should have length 1
+      # @return [String] The escaped character
+      # @private
+      def self.escape_char(c)
+        return "\\%06x" % Sass::Util.ord(c) unless c =~ /[ -\/:-~]/
+        "\\#{c}"
+      end
+
+      # Creates a Regexp from a plain text string,
+      # escaping all significant characters.
+      #
+      # @param str [String] The text of the regexp
+      # @param flags [Fixnum] Flags for the created regular expression
+      # @return [Regexp]
+      # @private
+      def self.quote(str, flags = 0)
+        Regexp.new(Regexp.quote(str), flags)
+      end
+
+      H        = /[0-9a-fA-F]/
+      NL       = /\n|\r\n|\r|\f/
+      UNICODE  = /\\#{H}{1,6}[ \t\r\n\f]?/
+      s = if Sass::Util.ruby1_8?
+            '\200-\377'
+          elsif Sass::Util.macruby?
+            '\u0080-\uD7FF\uE000-\uFFFD\U00010000-\U0010FFFF'
+          else
+            '\u{80}-\u{D7FF}\u{E000}-\u{FFFD}\u{10000}-\u{10FFFF}'
+          end
+      NONASCII = /[#{s}]/
+      ESCAPE   = /#{UNICODE}|\\[ -~#{s}]/
+      NMSTART  = /[_a-zA-Z]|#{NONASCII}|#{ESCAPE}/
+      NMCHAR   = /[a-zA-Z0-9_-]|#{NONASCII}|#{ESCAPE}/
+      STRING1  = /\"((?:[^\n\r\f\\"]|\\#{NL}|#{ESCAPE})*)\"/
+      STRING2  = /\'((?:[^\n\r\f\\']|\\#{NL}|#{ESCAPE})*)\'/
+
+      IDENT    = /-*#{NMSTART}#{NMCHAR}*/
+      NAME     = /#{NMCHAR}+/
+      NUM      = //
+      STRING   = /#{STRING1}|#{STRING2}/
+      URLCHAR  = /[#%&*-~]|#{NONASCII}|#{ESCAPE}/
+      URL      = /(#{URLCHAR}*)/
+      W        = /[ \t\r\n\f]*/
+      VARIABLE = /(\$)(#{Sass::SCSS::RX::IDENT})/
+
+      # This is more liberal than the spec's definition,
+      # but that definition didn't work well with the greediness rules
+      RANGE    = /(?:#{H}|\?){1,6}/
+
+      ##
+
+      S = /[ \t\r\n\f]+/
+
+      COMMENT = %r{/\*([^*]|\*+[^/*])*\**\*/}
+      SINGLE_LINE_COMMENT = %r{//.*(\n[ \t]*//.*)*}
+
+      CDO            = quote("<!--")
+      CDC            = quote("-->")
+      INCLUDES       = quote("~=")
+      DASHMATCH      = quote("|=")
+      PREFIXMATCH    = quote("^=")
+      SUFFIXMATCH    = quote("$=")
+      SUBSTRINGMATCH = quote("*=")
+
+      HASH = /##{NAME}/
+
+      IMPORTANT = /!#{W}important/i
+
+      UNITLESS_NUMBER = /(?:[0-9]+|[0-9]*\.[0-9]+)(?:[eE][+-]?\d+)?/
+      NUMBER = /#{UNITLESS_NUMBER}(?:#{IDENT}|%)?/
+      PERCENTAGE = /#{UNITLESS_NUMBER}%/
+
+      URI = /url\(#{W}(?:#{STRING}|#{URL})#{W}\)/i
+      FUNCTION = /#{IDENT}\(/
+
+      UNICODERANGE = /u\+(?:#{H}{1,6}-#{H}{1,6}|#{RANGE})/i
+
+      # Defined in http://www.w3.org/TR/css3-selectors/#lex
+      PLUS = /#{W}\+/
+      GREATER = /#{W}>/
+      TILDE = /#{W}~/
+      NOT = quote(":not(", Regexp::IGNORECASE)
+
+      # Defined in https://developer.mozilla.org/en/CSS/@-moz-document as a
+      # non-standard version of http://www.w3.org/TR/css3-conditional/
+      URL_PREFIX = /url-prefix\(#{W}(?:#{STRING}|#{URL})#{W}\)/i
+      DOMAIN = /domain\(#{W}(?:#{STRING}|#{URL})#{W}\)/i
+
+      # Custom
+      HEXCOLOR = /\#[0-9a-fA-F]+/
+      INTERP_START = /#\{/
+      ANY = /:(-[-\w]+-)?any\(/i
+      OPTIONAL = /!#{W}optional/i
+      IDENT_START = /-|#{NMSTART}/
+
+      # A unit is like an IDENT, but disallows a hyphen followed by a digit.
+      # This allows "1px-2px" to be interpreted as subtraction rather than "1"
+      # with the unit "px-2px". It also allows "%".
+      UNIT = /-?#{NMSTART}(?:[a-zA-Z0-9_]|#{NONASCII}|#{ESCAPE}|-(?!\d))*|%/
+
+      IDENT_HYPHEN_INTERP = /-(#\{)/
+      STRING1_NOINTERP = /\"((?:[^\n\r\f\\"#]|#(?!\{)|#{ESCAPE})*)\"/
+      STRING2_NOINTERP = /\'((?:[^\n\r\f\\'#]|#(?!\{)|#{ESCAPE})*)\'/
+      STRING_NOINTERP = /#{STRING1_NOINTERP}|#{STRING2_NOINTERP}/
+
+      STATIC_COMPONENT = /#{IDENT}|#{STRING_NOINTERP}|#{HEXCOLOR}|[+-]?#{NUMBER}|\!important/i
+      STATIC_VALUE = /#{STATIC_COMPONENT}(\s*[\s,\/]\s*#{STATIC_COMPONENT})*([;}])/i
+      STATIC_SELECTOR = /(#{NMCHAR}|[ \t]|[,>+*]|[:#.]#{NMSTART}){1,50}([{])/i
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.2.12/lib/sass/scss/script_lexer.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/scss/script_lexer.rb
similarity index 100%
rename from backends/css/gems/sass-3.2.12/lib/sass/scss/script_lexer.rb
rename to backends/css/gems/sass-3.4.9/lib/sass/scss/script_lexer.rb
diff --git a/backends/css/gems/sass-3.2.12/lib/sass/scss/script_parser.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/scss/script_parser.rb
similarity index 100%
rename from backends/css/gems/sass-3.2.12/lib/sass/scss/script_parser.rb
rename to backends/css/gems/sass-3.4.9/lib/sass/scss/script_parser.rb
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/scss/static_parser.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/scss/static_parser.rb
new file mode 100644
index 0000000..013fcab
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/scss/static_parser.rb
@@ -0,0 +1,368 @@
+require 'sass/script/css_parser'
+
+module Sass
+  module SCSS
+    # A parser for a static SCSS tree.
+    # Parses with SCSS extensions, like nested rules and parent selectors,
+    # but without dynamic SassScript.
+    # This is useful for e.g. \{#parse\_selector parsing selectors}
+    # after resolving the interpolation.
+    class StaticParser < Parser
+      # Parses the text as a selector.
+      #
+      # @param filename [String, nil] The file in which the selector appears,
+      #   or nil if there is no such file.
+      #   Used for error reporting.
+      # @return [Selector::CommaSequence] The parsed selector
+      # @raise [Sass::SyntaxError] if there's a syntax error in the selector
+      def parse_selector
+        init_scanner!
+        seq = expr!(:selector_comma_sequence)
+        expected("selector") unless @scanner.eos?
+        seq.line = @line
+        seq.filename = @filename
+        seq
+      end
+
+      # Parses a static at-root query.
+      #
+      # @return [(Symbol, Array<String>)] The type of the query
+      #   (`:with` or `:without`) and the values that are being filtered.
+      # @raise [Sass::SyntaxError] if there's a syntax error in the query,
+      #   or if it doesn't take up the entire input string.
+      def parse_static_at_root_query
+        init_scanner!
+        tok!(/\(/); ss
+        type = tok!(/\b(without|with)\b/).to_sym; ss
+        tok!(/:/); ss
+        directives = expr!(:at_root_directive_list); ss
+        tok!(/\)/)
+        expected("@at-root query list") unless @scanner.eos?
+        return type, directives
+      end
+
+      def parse_keyframes_selector
+        init_scanner!
+        sel = expr!(:keyframes_selector)
+        expected("keyframes selector") unless @scanner.eos?
+        sel
+      end
+
+      # @see Parser#initialize
+      # @param allow_parent_ref [Boolean] Whether to allow the
+      #   parent-reference selector, `&`, when parsing the document.
+      # @comment
+      #   rubocop:disable ParameterLists
+      def initialize(str, filename, importer, line = 1, offset = 1, allow_parent_ref = true)
+        # rubocop:enable ParameterLists
+        super(str, filename, importer, line, offset)
+        @allow_parent_ref = allow_parent_ref
+      end
+
+      private
+
+      def moz_document_function
+        val = tok(URI) || tok(URL_PREFIX) || tok(DOMAIN) || function(!:allow_var)
+        return unless val
+        ss
+        [val]
+      end
+
+      def variable; nil; end
+      def script_value; nil; end
+      def interpolation(warn_for_color = false); nil; end
+      def var_expr; nil; end
+      def interp_string; (s = tok(STRING)) && [s]; end
+      def interp_uri; (s = tok(URI)) && [s]; end
+      def interp_ident(ident = IDENT); (s = tok(ident)) && [s]; end
+      def use_css_import?; true; end
+
+      def special_directive(name, start_pos)
+        return unless %w[media import charset -moz-document].include?(name)
+        super
+      end
+
+      def selector_comma_sequence
+        sel = selector
+        return unless sel
+        selectors = [sel]
+        ws = ''
+        while tok(/,/)
+          ws << str {ss}
+          if (sel = selector)
+            selectors << sel
+            if ws.include?("\n")
+              selectors[-1] = Selector::Sequence.new(["\n"] + selectors.last.members)
+            end
+            ws = ''
+          end
+        end
+        Selector::CommaSequence.new(selectors)
+      end
+
+      def selector_string
+        sel = selector
+        return unless sel
+        sel.to_s
+      end
+
+      def selector
+        start_pos = source_position
+        # The combinator here allows the "> E" hack
+        val = combinator || simple_selector_sequence
+        return unless val
+        nl = str {ss}.include?("\n")
+        res = []
+        res << val
+        res << "\n" if nl
+
+        while (val = combinator || simple_selector_sequence)
+          res << val
+          res << "\n" if str {ss}.include?("\n")
+        end
+        seq = Selector::Sequence.new(res.compact)
+
+        if seq.members.any? {|sseq| sseq.is_a?(Selector::SimpleSequence) && sseq.subject?}
+          location = " of #{ filename}" if @filename
+          Sass::Util.sass_warn <<MESSAGE
+DEPRECATION WARNING on line #{start_pos.line}, column #{start_pos.offset}#{location}:
+The subject selector operator "!" is deprecated and will be removed in a future release.
+This operator has been replaced by ":has()" in the CSS spec.
+For example: #{seq.subjectless}
+MESSAGE
+        end
+
+        seq
+      end
+
+      def combinator
+        tok(PLUS) || tok(GREATER) || tok(TILDE) || reference_combinator
+      end
+
+      def reference_combinator
+        return unless tok(/\//)
+        res = '/'
+        ns, name = expr!(:qualified_name)
+        res << ns << '|' if ns
+        res << name << tok!(/\//)
+        res
+      end
+
+      def simple_selector_sequence
+        start_pos = source_position
+        e = element_name || id_selector || class_selector || placeholder_selector || attrib ||
+            pseudo || parent_selector
+        return unless e
+        res = [e]
+
+        # The tok(/\*/) allows the "E*" hack
+        while (v = id_selector || class_selector || placeholder_selector ||
+                   attrib || pseudo || (tok(/\*/) && Selector::Universal.new(nil)))
+          res << v
+        end
+
+        pos = @scanner.pos
+        line = @line
+        if (sel = str? {simple_selector_sequence})
+          @scanner.pos = pos
+          @line = line
+          begin
+            # If we see "*E", don't force a throw because this could be the
+            # "*prop: val" hack.
+            expected('"{"') if res.length == 1 && res[0].is_a?(Selector::Universal)
+            throw_error {expected('"{"')}
+          rescue Sass::SyntaxError => e
+            e.message << "\n\n\"#{sel}\" may only be used at the beginning of a compound selector."
+            raise e
+          end
+        end
+
+        Selector::SimpleSequence.new(res, tok(/!/), range(start_pos))
+      end
+
+      def parent_selector
+        return unless @allow_parent_ref && tok(/&/)
+        Selector::Parent.new(tok(NAME))
+      end
+
+      def class_selector
+        return unless tok(/\./)
+        @expected = "class name"
+        Selector::Class.new(tok!(IDENT))
+      end
+
+      def id_selector
+        return unless tok(/#(?!\{)/)
+        @expected = "id name"
+        Selector::Id.new(tok!(NAME))
+      end
+
+      def placeholder_selector
+        return unless tok(/%/)
+        @expected = "placeholder name"
+        Selector::Placeholder.new(tok!(IDENT))
+      end
+
+      def element_name
+        ns, name = Sass::Util.destructure(qualified_name(:allow_star_name))
+        return unless ns || name
+
+        if name == '*'
+          Selector::Universal.new(ns)
+        else
+          Selector::Element.new(name, ns)
+        end
+      end
+
+      def qualified_name(allow_star_name = false)
+        name = tok(IDENT) || tok(/\*/) || (tok?(/\|/) && "")
+        return unless name
+        return nil, name unless tok(/\|/)
+
+        return name, tok!(IDENT) unless allow_star_name
+        @expected = "identifier or *"
+        return name, tok(IDENT) || tok!(/\*/)
+      end
+
+      def attrib
+        return unless tok(/\[/)
+        ss
+        ns, name = attrib_name!
+        ss
+
+        op = tok(/=/) ||
+             tok(INCLUDES) ||
+             tok(DASHMATCH) ||
+             tok(PREFIXMATCH) ||
+             tok(SUFFIXMATCH) ||
+             tok(SUBSTRINGMATCH)
+        if op
+          @expected = "identifier or string"
+          ss
+          val = tok(IDENT) || tok!(STRING)
+          ss
+        end
+        flags = tok(IDENT) || tok(STRING)
+        tok!(/\]/)
+
+        Selector::Attribute.new(name, ns, op, val, flags)
+      end
+
+      def attrib_name!
+        if (name_or_ns = tok(IDENT))
+          # E, E|E
+          if tok(/\|(?!=)/)
+            ns = name_or_ns
+            name = tok(IDENT)
+          else
+            name = name_or_ns
+          end
+        else
+          # *|E or |E
+          ns = tok(/\*/) || ""
+          tok!(/\|/)
+          name = tok!(IDENT)
+        end
+        return ns, name
+      end
+
+      SELECTOR_PSEUDO_CLASSES = %w[not matches current any has host host-context].to_set
+
+      PREFIXED_SELECTOR_PSEUDO_CLASSES = %w[nth-child nth-last-child].to_set
+
+      def pseudo
+        s = tok(/::?/)
+        return unless s
+        @expected = "pseudoclass or pseudoelement"
+        name = tok!(IDENT)
+        if tok(/\(/)
+          ss
+          deprefixed = deprefix(name)
+          if s == ':' && SELECTOR_PSEUDO_CLASSES.include?(deprefixed)
+            sel = selector_comma_sequence
+          elsif s == ':' && PREFIXED_SELECTOR_PSEUDO_CLASSES.include?(deprefixed)
+            arg, sel = prefixed_selector_pseudo
+          else
+            arg = expr!(:pseudo_args)
+          end
+
+          tok!(/\)/)
+        end
+        Selector::Pseudo.new(s == ':' ? :class : :element, name, arg, sel)
+      end
+
+      def pseudo_args
+        arg = expr!(:pseudo_expr)
+        while tok(/,/)
+          arg << ',' << str {ss}
+          arg.concat expr!(:pseudo_expr)
+        end
+        arg
+      end
+
+      def pseudo_expr
+        res = pseudo_expr_token
+        return unless res
+        res << str {ss}
+        while (e = pseudo_expr_token)
+          res << e << str {ss}
+        end
+        res
+      end
+
+      def pseudo_expr_token
+        tok(PLUS) || tok(/[-*]/) || tok(NUMBER) || tok(STRING) || tok(IDENT)
+      end
+
+      def prefixed_selector_pseudo
+        prefix = str do
+          expr = str {expr!(:a_n_plus_b)}
+          ss
+          return expr, nil unless tok(/of/)
+          ss
+        end
+        return prefix, expr!(:selector_comma_sequence)
+      end
+
+      def a_n_plus_b
+        if (parity = tok(/even|odd/i))
+          return parity
+        end
+
+        if tok(/[+-]?[0-9]+/)
+          ss
+          return true unless tok(/n/)
+        else
+          return unless tok(/[+-]?n/i)
+        end
+        ss
+
+        return true unless tok(/[+-]/)
+        ss
+        @expected = "number"
+        tok!(/[0-9]+/)
+        true
+      end
+
+      def keyframes_selector
+        ss
+        str do
+          return unless keyframes_selector_component
+          ss
+          while tok(/,/)
+            ss
+            expr!(:keyframes_selector_component)
+            ss
+          end
+        end
+      end
+
+      def keyframes_selector_component
+        tok(IDENT) || tok(PERCENTAGE)
+      end
+
+      @sass_script_parser = Class.new(Sass::Script::CssParser)
+      @sass_script_parser.send(:include, ScriptParser)
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/selector.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/selector.rb
new file mode 100644
index 0000000..752491b
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/selector.rb
@@ -0,0 +1,326 @@
+require 'sass/selector/simple'
+require 'sass/selector/abstract_sequence'
+require 'sass/selector/comma_sequence'
+require 'sass/selector/pseudo'
+require 'sass/selector/sequence'
+require 'sass/selector/simple_sequence'
+
+module Sass
+  # A namespace for nodes in the parse tree for selectors.
+  #
+  # {CommaSequence} is the toplevel selector,
+  # representing a comma-separated sequence of {Sequence}s,
+  # such as `foo bar, baz bang`.
+  # {Sequence} is the next level,
+  # representing {SimpleSequence}s separated by combinators (e.g. descendant or child),
+  # such as `foo bar` or `foo > bar baz`.
+  # {SimpleSequence} is a sequence of selectors that all apply to a single element,
+  # such as `foo.bar[attr=val]`.
+  # Finally, {Simple} is the superclass of the simplest selectors,
+  # such as `.foo` or `#bar`.
+  module Selector
+    # The base used for calculating selector specificity. The spec says this
+    # should be "sufficiently high"; it's extremely unlikely that any single
+    # selector sequence will contain 1,000 simple selectors.
+    SPECIFICITY_BASE = 1_000
+
+    # A parent-referencing selector (`&` in Sass).
+    # The function of this is to be replaced by the parent selector
+    # in the nested hierarchy.
+    class Parent < Simple
+      # The identifier following the `&`. `nil` indicates no suffix.
+      #
+      # @return [String, nil]
+      attr_reader :suffix
+
+      # @param name [String, nil] See \{#suffix}
+      def initialize(suffix = nil)
+        @suffix = suffix
+      end
+
+      # @see Selector#to_s
+      def to_s
+        "&" + (@suffix || '')
+      end
+
+      # Always raises an exception.
+      #
+      # @raise [Sass::SyntaxError] Parent selectors should be resolved before unification
+      # @see Selector#unify
+      def unify(sels)
+        raise Sass::SyntaxError.new("[BUG] Cannot unify parent selectors.")
+      end
+    end
+
+    # A class selector (e.g. `.foo`).
+    class Class < Simple
+      # The class name.
+      #
+      # @return [String]
+      attr_reader :name
+
+      # @param name [String] The class name
+      def initialize(name)
+        @name = name
+      end
+
+      # @see Selector#to_s
+      def to_s
+        "." + @name
+      end
+
+      # @see AbstractSequence#specificity
+      def specificity
+        SPECIFICITY_BASE
+      end
+    end
+
+    # An id selector (e.g. `#foo`).
+    class Id < Simple
+      # The id name.
+      #
+      # @return [String]
+      attr_reader :name
+
+      # @param name [String] The id name
+      def initialize(name)
+        @name = name
+      end
+
+      # @see Selector#to_s
+      def to_s
+        "#" + @name
+      end
+
+      # Returns `nil` if `sels` contains an {Id} selector
+      # with a different name than this one.
+      #
+      # @see Selector#unify
+      def unify(sels)
+        return if sels.any? {|sel2| sel2.is_a?(Id) && name != sel2.name}
+        super
+      end
+
+      # @see AbstractSequence#specificity
+      def specificity
+        SPECIFICITY_BASE**2
+      end
+    end
+
+    # A placeholder selector (e.g. `%foo`).
+    # This exists to be replaced via ` extend` 
+    # Rulesets using this selector will not be printed, but can be extended.
+    # Otherwise, this acts just like a class selector.
+    class Placeholder < Simple
+      # The placeholder name.
+      #
+      # @return [String]
+      attr_reader :name
+
+      # @param name [String] The placeholder name
+      def initialize(name)
+        @name = name
+      end
+
+      # @see Selector#to_s
+      def to_s
+        "%" + @name
+      end
+
+      # @see AbstractSequence#specificity
+      def specificity
+        SPECIFICITY_BASE
+      end
+    end
+
+    # A universal selector (`*` in CSS).
+    class Universal < Simple
+      # The selector namespace. `nil` means the default namespace, `""` means no
+      # namespace, `"*"` means any namespace.
+      #
+      # @return [String, nil]
+      attr_reader :namespace
+
+      # @param namespace [String, nil] See \{#namespace}
+      def initialize(namespace)
+        @namespace = namespace
+      end
+
+      # @see Selector#to_s
+      def to_s
+        @namespace ? "#{ namespace}|*" : "*"
+      end
+
+      # Unification of a universal selector is somewhat complicated,
+      # especially when a namespace is specified.
+      # If there is no namespace specified
+      # or any namespace is specified (namespace `"*"`),
+      # then `sel` is returned without change
+      # (unless it's empty, in which case `"*"` is required).
+      #
+      # If a namespace is specified
+      # but `sel` does not specify a namespace,
+      # then the given namespace is applied to `sel`,
+      # either by adding this {Universal} selector
+      # or applying this namespace to an existing {Element} selector.
+      #
+      # If both this selector *and* `sel` specify namespaces,
+      # those namespaces are unified via {Simple#unify_namespaces}
+      # and the unified namespace is used, if possible.
+      #
+      # @todo There are lots of cases that this documentation specifies;
+      #   make sure we thoroughly test **all of them**.
+      # @todo Keep track of whether a default namespace has been declared
+      #   and handle namespace-unspecified selectors accordingly.
+      # @todo If any branch of a CommaSequence ends up being just `"*"`,
+      #   then all other branches should be eliminated
+      #
+      # @see Selector#unify
+      def unify(sels)
+        name =
+          case sels.first
+          when Universal; :universal
+          when Element; sels.first.name
+          else
+            return [self] + sels unless namespace.nil? || namespace == '*'
+            return sels unless sels.empty?
+            return [self]
+          end
+
+        ns, accept = unify_namespaces(namespace, sels.first.namespace)
+        return unless accept
+        [name == :universal ? Universal.new(ns) : Element.new(name, ns)] + sels[1..-1]
+      end
+
+      # @see AbstractSequence#specificity
+      def specificity
+        0
+      end
+    end
+
+    # An element selector (e.g. `h1`).
+    class Element < Simple
+      # The element name.
+      #
+      # @return [String]
+      attr_reader :name
+
+      # The selector namespace. `nil` means the default namespace, `""` means no
+      # namespace, `"*"` means any namespace.
+      #
+      # @return [String, nil]
+      attr_reader :namespace
+
+      # @param name [String] The element name
+      # @param namespace [String, nil] See \{#namespace}
+      def initialize(name, namespace)
+        @name = name
+        @namespace = namespace
+      end
+
+      # @see Selector#to_s
+      def to_s
+        @namespace ? "#{ namespace}|#{ name}" : @name
+      end
+
+      # Unification of an element selector is somewhat complicated,
+      # especially when a namespace is specified.
+      # First, if `sel` contains another {Element} with a different \{#name},
+      # then the selectors can't be unified and `nil` is returned.
+      #
+      # Otherwise, if `sel` doesn't specify a namespace,
+      # or it specifies any namespace (via `"*"`),
+      # then it's returned with this element selector
+      # (e.g. `.foo` becomes `a.foo` or `svg|a.foo`).
+      # Similarly, if this selector doesn't specify a namespace,
+      # the namespace from `sel` is used.
+      #
+      # If both this selector *and* `sel` specify namespaces,
+      # those namespaces are unified via {Simple#unify_namespaces}
+      # and the unified namespace is used, if possible.
+      #
+      # @todo There are lots of cases that this documentation specifies;
+      #   make sure we thoroughly test **all of them**.
+      # @todo Keep track of whether a default namespace has been declared
+      #   and handle namespace-unspecified selectors accordingly.
+      #
+      # @see Selector#unify
+      def unify(sels)
+        case sels.first
+        when Universal;
+        when Element; return unless name == sels.first.name
+        else return [self] + sels
+        end
+
+        ns, accept = unify_namespaces(namespace, sels.first.namespace)
+        return unless accept
+        [Element.new(name, ns)] + sels[1..-1]
+      end
+
+      # @see AbstractSequence#specificity
+      def specificity
+        1
+      end
+    end
+
+    # An attribute selector (e.g. `[href^="http://"]`).
+    class Attribute < Simple
+      # The attribute name.
+      #
+      # @return [Array<String, Sass::Script::Tree::Node>]
+      attr_reader :name
+
+      # The attribute namespace. `nil` means the default namespace, `""` means
+      # no namespace, `"*"` means any namespace.
+      #
+      # @return [String, nil]
+      attr_reader :namespace
+
+      # The matching operator, e.g. `"="` or `"^="`.
+      #
+      # @return [String]
+      attr_reader :operator
+
+      # The right-hand side of the operator.
+      #
+      # @return [String]
+      attr_reader :value
+
+      # Flags for the attribute selector (e.g. `i`).
+      #
+      # @return [String]
+      attr_reader :flags
+
+      # @param name [String] The attribute name
+      # @param namespace [String, nil] See \{#namespace}
+      # @param operator [String] The matching operator, e.g. `"="` or `"^="`
+      # @param value [String] See \{#value}
+      # @param flags [String] See \{#flags}
+      # @comment
+      #   rubocop:disable ParameterLists
+      def initialize(name, namespace, operator, value, flags)
+        # rubocop:enable ParameterLists
+        @name = name
+        @namespace = namespace
+        @operator = operator
+        @value = value
+        @flags = flags
+      end
+
+      # @see Selector#to_s
+      def to_s
+        res = "["
+        res << @namespace << "|" if @namespace
+        res << @name
+        res << @operator << @value if @value
+        res << " " << @flags if @flags
+        res << "]"
+      end
+
+      # @see AbstractSequence#specificity
+      def specificity
+        SPECIFICITY_BASE
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/selector/abstract_sequence.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/selector/abstract_sequence.rb
new file mode 100644
index 0000000..2761715
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/selector/abstract_sequence.rb
@@ -0,0 +1,109 @@
+module Sass
+  module Selector
+    # The abstract parent class of the various selector sequence classes.
+    #
+    # All subclasses should implement a `members` method that returns an array
+    # of object that respond to `#line=` and `#filename=`, as well as a `to_s`
+    # method that returns the string representation of the selector.
+    class AbstractSequence
+      # The line of the Sass template on which this selector was declared.
+      #
+      # @return [Fixnum]
+      attr_reader :line
+
+      # The name of the file in which this selector was declared.
+      #
+      # @return [String, nil]
+      attr_reader :filename
+
+      # Sets the line of the Sass template on which this selector was declared.
+      # This also sets the line for all child selectors.
+      #
+      # @param line [Fixnum]
+      # @return [Fixnum]
+      def line=(line)
+        members.each {|m| m.line = line}
+        @line = line
+      end
+
+      # Sets the name of the file in which this selector was declared,
+      # or `nil` if it was not declared in a file (e.g. on stdin).
+      # This also sets the filename for all child selectors.
+      #
+      # @param filename [String, nil]
+      # @return [String, nil]
+      def filename=(filename)
+        members.each {|m| m.filename = filename}
+        @filename = filename
+      end
+
+      # Returns a hash code for this sequence.
+      #
+      # Subclasses should define `#_hash` rather than overriding this method,
+      # which automatically handles memoizing the result.
+      #
+      # @return [Fixnum]
+      def hash
+        @_hash ||= _hash
+      end
+
+      # Checks equality between this and another object.
+      #
+      # Subclasses should define `#_eql?` rather than overriding this method,
+      # which handles checking class equality and hash equality.
+      #
+      # @param other [Object] The object to test equality against
+      # @return [Boolean] Whether or not this is equal to `other`
+      def eql?(other)
+        other.class == self.class && other.hash == hash && _eql?(other)
+      end
+      alias_method :==, :eql?
+
+      # Whether or not this selector sequence contains a placeholder selector.
+      # Checks recursively.
+      def has_placeholder?
+        @has_placeholder ||= members.any? do |m|
+          next m.has_placeholder? if m.is_a?(AbstractSequence)
+          next m.selector && m.selector.has_placeholder? if m.is_a?(Pseudo)
+          m.is_a?(Placeholder)
+        end
+      end
+
+      # Returns the selector string.
+      #
+      # @return [String]
+      def to_s
+        Sass::Util.abstract(self)
+      end
+
+      # Returns the specificity of the selector.
+      #
+      # The base is given by {Sass::Selector::SPECIFICITY_BASE}. This can be a
+      # number or a range representing possible specificities.
+      #
+      # @return [Fixnum, Range]
+      def specificity
+        _specificity(members)
+      end
+
+      protected
+
+      def _specificity(arr)
+        min = 0
+        max = 0
+        arr.each do |m|
+          next if m.is_a?(String)
+          spec = m.specificity
+          if spec.is_a?(Range)
+            min += spec.begin
+            max += spec.end
+          else
+            min += spec
+            max += spec
+          end
+        end
+        min == max ? min : (min..max)
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/selector/comma_sequence.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/selector/comma_sequence.rb
new file mode 100644
index 0000000..506af86
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/selector/comma_sequence.rb
@@ -0,0 +1,177 @@
+module Sass
+  module Selector
+    # A comma-separated sequence of selectors.
+    class CommaSequence < AbstractSequence
+      # The comma-separated selector sequences
+      # represented by this class.
+      #
+      # @return [Array<Sequence>]
+      attr_reader :members
+
+      # @param seqs [Array<Sequence>] See \{#members}
+      def initialize(seqs)
+        @members = seqs
+      end
+
+      # Resolves the {Parent} selectors within this selector
+      # by replacing them with the given parent selector,
+      # handling commas appropriately.
+      #
+      # @param super_cseq [CommaSequence] The parent selector
+      # @param implicit_parent [Boolean] Whether the the parent
+      #   selector should automatically be prepended to the resolved
+      #   selector if it contains no parent refs.
+      # @return [CommaSequence] This selector, with parent references resolved
+      # @raise [Sass::SyntaxError] If a parent selector is invalid
+      def resolve_parent_refs(super_cseq, implicit_parent = true)
+        if super_cseq.nil?
+          if contains_parent_ref?
+            raise Sass::SyntaxError.new(
+              "Base-level rules cannot contain the parent-selector-referencing character '&'.")
+          end
+          return self
+        end
+
+        CommaSequence.new(Sass::Util.flatten_vertically(@members.map do |seq|
+          seq.resolve_parent_refs(super_cseq, implicit_parent).members
+        end))
+      end
+
+      # Returns whether there's a {Parent} selector anywhere in this sequence.
+      #
+      # @return [Boolean]
+      def contains_parent_ref?
+        @members.any? {|sel| sel.contains_parent_ref?}
+      end
+
+      # Non-destrucively extends this selector with the extensions specified in a hash
+      # (which should come from {Sass::Tree::Visitors::Cssize}).
+      #
+      # @todo Link this to the reference documentation on ` extend`
+      #   when such a thing exists.
+      #
+      # @param extends [Sass::Util::SubsetMap{Selector::Simple =>
+      #                                       Sass::Tree::Visitors::Cssize::Extend}]
+      #   The extensions to perform on this selector
+      # @param parent_directives [Array<Sass::Tree::DirectiveNode>]
+      #   The directives containing this selector.
+      # @param replace [Boolean]
+      #   Whether to replace the original selector entirely or include
+      #   it in the result.
+      # @param seen [Set<Array<Selector::Simple>>]
+      #   The set of simple sequences that are currently being replaced.
+      # @param original [Boolean]
+      #   Whether this is the original selector being extended, as opposed to
+      #   the result of a previous extension that's being re-extended.
+      # @return [CommaSequence] A copy of this selector,
+      #   with extensions made according to `extends`
+      def do_extend(extends, parent_directives = [], replace = false, seen = Set.new,
+          original = true)
+        CommaSequence.new(members.map do |seq|
+          seq.do_extend(extends, parent_directives, replace, seen, original)
+        end.flatten)
+      end
+
+      # Returns whether or not this selector matches all elements
+      # that the given selector matches (as well as possibly more).
+      #
+      # @example
+      #   (.foo).superselector?(.foo.bar) #=> true
+      #   (.foo).superselector?(.bar) #=> false
+      # @param cseq [CommaSequence]
+      # @return [Boolean]
+      def superselector?(cseq)
+        cseq.members.all? {|seq1| members.any? {|seq2| seq2.superselector?(seq1)}}
+      end
+
+      # Populates a subset map that can then be used to extend
+      # selectors. This registers an extension with this selector as
+      # the extender and `extendee` as the extendee.
+      #
+      # @param extends [Sass::Util::SubsetMap{Selector::Simple =>
+      #                                       Sass::Tree::Visitors::Cssize::Extend}]
+      #   The subset map representing the extensions to perform.
+      # @param extendee [CommaSequence] The selector being extended.
+      # @param extend_node [Sass::Tree::ExtendNode]
+      #   The node that caused this extension.
+      # @param parent_directives [Array<Sass::Tree::DirectiveNode>]
+      #   The parent directives containing `extend_node`.
+      # @raise [Sass::SyntaxError] if this extension is invalid.
+      def populate_extends(extends, extendee, extend_node = nil, parent_directives = [])
+        extendee.members.each do |seq|
+          if seq.members.size > 1
+            raise Sass::SyntaxError.new("Can't extend #{seq}: can't extend nested selectors")
+          end
+
+          sseq = seq.members.first
+          if !sseq.is_a?(Sass::Selector::SimpleSequence)
+            raise Sass::SyntaxError.new("Can't extend #{seq}: invalid selector")
+          elsif sseq.members.any? {|ss| ss.is_a?(Sass::Selector::Parent)}
+            raise Sass::SyntaxError.new("Can't extend #{seq}: can't extend parent selectors")
+          end
+
+          sel = sseq.members
+          members.each do |member|
+            unless member.members.last.is_a?(Sass::Selector::SimpleSequence)
+              raise Sass::SyntaxError.new("#{member} can't extend: invalid selector")
+            end
+
+            extends[sel] = Sass::Tree::Visitors::Cssize::Extend.new(
+              member, sel, extend_node, parent_directives, :not_found)
+          end
+        end
+      end
+
+      # Unifies this with another comma selector to produce a selector
+      # that matches (a subset of) the intersection of the two inputs.
+      #
+      # @param other [CommaSequence]
+      # @return [CommaSequence, nil] The unified selector, or nil if unification failed.
+      # @raise [Sass::SyntaxError] If this selector cannot be unified.
+      #   This will only ever occur when a dynamic selector,
+      #   such as {Parent} or {Interpolation}, is used in unification.
+      #   Since these selectors should be resolved
+      #   by the time extension and unification happen,
+      #   this exception will only ever be raised as a result of programmer error
+      def unify(other)
+        results = members.map {|seq1| other.members.map {|seq2| seq1.unify(seq2)}}.flatten.compact
+        results.empty? ? nil : CommaSequence.new(results.map {|cseq| cseq.members}.flatten)
+      end
+
+      # Returns a SassScript representation of this selector.
+      #
+      # @return [Sass::Script::Value::List]
+      def to_sass_script
+        Sass::Script::Value::List.new(members.map do |seq|
+          Sass::Script::Value::List.new(seq.members.map do |component|
+            next if component == "\n"
+            Sass::Script::Value::String.new(component.to_s)
+          end.compact, :space)
+        end, :comma)
+      end
+
+      # Returns a string representation of the sequence.
+      # This is basically the selector string.
+      #
+      # @return [String]
+      def inspect
+        members.map {|m| m.inspect}.join(", ")
+      end
+
+      # @see AbstractSequence#to_s
+      def to_s
+        @members.join(", ").gsub(", \n", ",\n")
+      end
+
+      private
+
+      def _hash
+        members.hash
+      end
+
+      def _eql?(other)
+        other.class == self.class && other.members.eql?(members)
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/selector/pseudo.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/selector/pseudo.rb
new file mode 100644
index 0000000..047fa4b
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/selector/pseudo.rb
@@ -0,0 +1,266 @@
+module Sass
+  module Selector
+    # A pseudoclass (e.g. `:visited`) or pseudoelement (e.g. `::first-line`)
+    # selector. It can have arguments (e.g. `:nth-child(2n+1)`) which can
+    # contain selectors (e.g. `:nth-child(2n+1 of .foo)`).
+    class Pseudo < Simple
+      # Some pseudo-class-syntax selectors are actually considered
+      # pseudo-elements and must be treated differently. This is a list of such
+      # selectors.
+      #
+      # @return [Set<String>]
+      ACTUALLY_ELEMENTS = %w[after before first-line first-letter].to_set
+
+      # Like \{#type}, but returns the type of selector this looks like, rather
+      # than the type it is semantically. This only differs from type for
+      # selectors in \{ACTUALLY\_ELEMENTS}.
+      #
+      # @return [Symbol]
+      attr_reader :syntactic_type
+
+      # The name of the selector.
+      #
+      # @return [String]
+      attr_reader :name
+
+      # The argument to the selector,
+      # or `nil` if no argument was given.
+      #
+      # @return [String, nil]
+      attr_reader :arg
+
+      # The selector argument, or `nil` if no selector exists.
+      #
+      # If this and \{#arg\} are both set, \{#arg\} is considered a non-selector
+      # prefix.
+      #
+      # @return [CommaSequence]
+      attr_reader :selector
+
+      # @param syntactic_type [Symbol] See \{#syntactic_type}
+      # @param name [String] See \{#name}
+      # @param arg [nil, String] See \{#arg}
+      # @param selector [nil, CommaSequence] See \{#selector}
+      def initialize(syntactic_type, name, arg, selector)
+        @syntactic_type = syntactic_type
+        @name = name
+        @arg = arg
+        @selector = selector
+      end
+
+      # Returns a copy of this with \{#selector} set to \{#new\_selector}.
+      #
+      # @param new_selector [CommaSequence]
+      # @return [Array<Simple>]
+      def with_selector(new_selector)
+        result = Pseudo.new(syntactic_type, name, arg,
+          CommaSequence.new(new_selector.members.map do |seq|
+            next seq unless seq.members.length == 1
+            sseq = seq.members.first
+            next seq unless sseq.is_a?(SimpleSequence) && sseq.members.length == 1
+            sel = sseq.members.first
+            next seq unless sel.is_a?(Pseudo) && sel.selector
+
+            case normalized_name
+            when 'not'
+              # In theory, if there's a nested :not its contents should be
+              # unified with the return value. For example, if :not(.foo)
+              # extends .bar, :not(.bar) should become .foo:not(.bar). However,
+              # this is a narrow edge case and supporting it properly would make
+              # this code and the code calling it a lot more complicated, so
+              # it's not supported for now.
+              next [] unless sel.normalized_name == 'matches'
+              sel.selector.members
+            when 'matches', 'any', 'current', 'nth-child', 'nth-last-child'
+              # As above, we could theoretically support :not within :matches, but
+              # doing so would require this method and its callers to handle much
+              # more complex cases that likely aren't worth the pain.
+              next [] unless sel.name == name && sel.arg == arg
+              sel.selector.members
+            when 'has', 'host', 'host-context'
+              # We can't expand nested selectors here, because each layer adds an
+              # additional layer of semantics. For example, `:has(:has(img))`
+              # doesn't match `<div><img></div>` but `:has(img)` does.
+              sel
+            else
+              []
+            end
+          end.flatten))
+
+        # Older browsers support :not but only with a single complex selector.
+        # In order to support those browsers, we break up the contents of a :not
+        # unless it originally contained a selector list.
+        return [result] unless normalized_name == 'not'
+        return [result] if selector.members.length > 1
+        result.selector.members.map do |seq|
+          Pseudo.new(syntactic_type, name, arg, CommaSequence.new([seq]))
+        end
+      end
+
+      # The type of the selector. `:class` if this is a pseudoclass selector,
+      # `:element` if it's a pseudoelement.
+      #
+      # @return [Symbol]
+      def type
+        ACTUALLY_ELEMENTS.include?(normalized_name) ? :element : syntactic_type
+      end
+
+      # Like \{#name\}, but without any vendor prefix.
+      #
+      # @return [String]
+      def normalized_name
+        @normalized_name ||= name.gsub(/^-[a-zA-Z0-9]+-/, '')
+      end
+
+      # @see Selector#to_s
+      def to_s
+        res = (syntactic_type == :class ? ":" : "::") + @name
+        if @arg || @selector
+          res << "("
+          res << @arg.strip if @arg
+          res << " " if @arg && @selector
+          res << @selector.to_s if @selector
+          res << ")"
+        end
+        res
+      end
+
+      # Returns `nil` if this is a pseudoelement selector
+      # and `sels` contains a pseudoelement selector different than this one.
+      #
+      # @see SimpleSequence#unify
+      def unify(sels)
+        return if type == :element && sels.any? do |sel|
+          sel.is_a?(Pseudo) && sel.type == :element &&
+            (sel.name != name || sel.arg != arg || sel.selector != selector)
+        end
+        super
+      end
+
+      # Returns whether or not this selector matches all elements
+      # that the given selector matches (as well as possibly more).
+      #
+      # @example
+      #   (.foo).superselector?(.foo.bar) #=> true
+      #   (.foo).superselector?(.bar) #=> false
+      # @param their_sseq [SimpleSequence]
+      # @param parents [Array<SimpleSequence, String>] The parent selectors of `their_sseq`, if any.
+      # @return [Boolean]
+      def superselector?(their_sseq, parents = [])
+        case normalized_name
+        when 'matches', 'any'
+          # :matches can be a superselector of another selector in one of two
+          # ways. Either its constituent selectors can be a superset of those of
+          # another :matches in the other selector, or any of its constituent
+          # selectors can individually be a superselector of the other selector.
+          (their_sseq.selector_pseudo_classes[normalized_name] || []).any? do |their_sel|
+            next false unless their_sel.is_a?(Pseudo)
+            next false unless their_sel.name == name
+            selector.superselector?(their_sel.selector)
+          end || selector.members.any? do |our_seq|
+            their_seq = Sequence.new(parents + [their_sseq])
+            our_seq.superselector?(their_seq)
+          end
+        when 'has', 'host', 'host-context'
+          # Like :matches, :has (et al) can be a superselector of another
+          # selector if its constituent selectors are a superset of those of
+          # another :has in the other selector. However, the :matches other case
+          # doesn't work, because :has refers to nested elements.
+          (their_sseq.selector_pseudo_classes[normalized_name] || []).any? do |their_sel|
+            next false unless their_sel.is_a?(Pseudo)
+            next false unless their_sel.name == name
+            selector.superselector?(their_sel.selector)
+          end
+        when 'not'
+          selector.members.all? do |our_seq|
+            their_sseq.members.any? do |their_sel|
+              if their_sel.is_a?(Element) || their_sel.is_a?(Id)
+                # `:not(a)` is a superselector of `h1` and `:not(#foo)` is a
+                # superselector of `#bar`.
+                our_sseq = our_seq.members.last
+                next false unless our_sseq.is_a?(SimpleSequence)
+                our_sseq.members.any? do |our_sel|
+                  our_sel.class == their_sel.class && our_sel != their_sel
+                end
+              else
+                next false unless their_sel.is_a?(Pseudo)
+                next false unless their_sel.name == name
+                # :not(X) is a superselector of :not(Y) exactly when Y is a
+                # superselector of X.
+                their_sel.selector.superselector?(CommaSequence.new([our_seq]))
+              end
+            end
+          end
+        when 'current'
+          (their_sseq.selector_pseudo_classes['current'] || []).any? do |their_current|
+            next false if their_current.name != name
+            # Explicitly don't check for nested superselector relationships
+            # here. :current(.foo) isn't always a superselector of
+            # :current(.foo.bar), since it matches the *innermost* ancestor of
+            # the current element that matches the selector. For example:
+            #
+            #     <div class="foo bar">
+            #       <p class="foo">
+            #         <span>current element</span>
+            #       </p>
+            #     </div>
+            #
+            # Here :current(.foo) would match the p element and *not* the div
+            # element, whereas :current(.foo.bar) would match the div and not
+            # the p.
+            selector == their_current.selector
+          end
+        when 'nth-child', 'nth-last-child'
+          their_sseq.members.any? do |their_sel|
+            # This misses a few edge cases. For example, `:nth-child(n of X)`
+            # is a superselector of `X`, and `:nth-child(2n of X)` is a
+            # superselector of `:nth-child(4n of X)`. These seem rare enough
+            # not to be worth worrying about, though.
+            next false unless their_sel.is_a?(Pseudo)
+            next false unless their_sel.name == name
+            next false unless their_sel.arg == arg
+            selector.superselector?(their_sel.selector)
+          end
+        else
+          throw "[BUG] Unknown selector pseudo class #{name}"
+        end
+      end
+
+      # @see AbstractSequence#specificity
+      def specificity
+        return 1 if type == :element
+        return SPECIFICITY_BASE unless selector
+        @specificity ||=
+          if normalized_name == 'not'
+            min = 0
+            max = 0
+            selector.members.each do |seq|
+              spec = seq.specificity
+              if spec.is_a?(Range)
+                min = Sass::Util.max(spec.begin, min)
+                max = Sass::Util.max(spec.end, max)
+              else
+                min = Sass::Util.max(spec, min)
+                max = Sass::Util.max(spec, max)
+              end
+            end
+            min == max ? max : (min..max)
+          else
+            min = 0
+            max = 0
+            selector.members.each do |seq|
+              spec = seq.specificity
+              if spec.is_a?(Range)
+                min = Sass::Util.min(spec.begin, min)
+                max = Sass::Util.max(spec.end, max)
+              else
+                min = Sass::Util.min(spec, min)
+                max = Sass::Util.max(spec, max)
+              end
+            end
+            min == max ? max : (min..max)
+          end
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/selector/sequence.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/selector/sequence.rb
new file mode 100644
index 0000000..a2de06c
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/selector/sequence.rb
@@ -0,0 +1,618 @@
+module Sass
+  module Selector
+    # An operator-separated sequence of
+    # {SimpleSequence simple selector sequences}.
+    class Sequence < AbstractSequence
+      # Sets the line of the Sass template on which this selector was declared.
+      # This also sets the line for all child selectors.
+      #
+      # @param line [Fixnum]
+      # @return [Fixnum]
+      def line=(line)
+        members.each {|m| m.line = line if m.is_a?(SimpleSequence)}
+        line
+      end
+
+      # Sets the name of the file in which this selector was declared,
+      # or `nil` if it was not declared in a file (e.g. on stdin).
+      # This also sets the filename for all child selectors.
+      #
+      # @param filename [String, nil]
+      # @return [String, nil]
+      def filename=(filename)
+        members.each {|m| m.filename = filename if m.is_a?(SimpleSequence)}
+        filename
+      end
+
+      # The array of {SimpleSequence simple selector sequences}, operators, and
+      # newlines. The operators are strings such as `"+"` and `">"` representing
+      # the corresponding CSS operators, or interpolated SassScript. Newlines
+      # are also newline strings; these aren't semantically relevant, but they
+      # do affect formatting.
+      #
+      # @return [Array<SimpleSequence, String|Array<Sass::Tree::Node, String>>]
+      attr_reader :members
+
+      # @param seqs_and_ops [Array<SimpleSequence, String|Array<Sass::Tree::Node, String>>]
+      #   See \{#members}
+      def initialize(seqs_and_ops)
+        @members = seqs_and_ops
+      end
+
+      # Resolves the {Parent} selectors within this selector
+      # by replacing them with the given parent selector,
+      # handling commas appropriately.
+      #
+      # @param super_cseq [CommaSequence] The parent selector
+      # @param implicit_parent [Boolean] Whether the the parent
+      #   selector should automatically be prepended to the resolved
+      #   selector if it contains no parent refs.
+      # @return [CommaSequence] This selector, with parent references resolved
+      # @raise [Sass::SyntaxError] If a parent selector is invalid
+      def resolve_parent_refs(super_cseq, implicit_parent)
+        members = @members.dup
+        nl = (members.first == "\n" && members.shift)
+        contains_parent_ref = contains_parent_ref?
+        return CommaSequence.new([self]) if !implicit_parent && !contains_parent_ref
+
+        unless contains_parent_ref
+          old_members, members = members, []
+          members << nl if nl
+          members << SimpleSequence.new([Parent.new], false)
+          members += old_members
+        end
+
+        CommaSequence.new(Sass::Util.paths(members.map do |sseq_or_op|
+          next [sseq_or_op] unless sseq_or_op.is_a?(SimpleSequence)
+          sseq_or_op.resolve_parent_refs(super_cseq).members
+        end).map do |path|
+          Sequence.new(path.map do |seq_or_op|
+            next seq_or_op unless seq_or_op.is_a?(Sequence)
+            seq_or_op.members
+          end.flatten)
+        end)
+      end
+
+      # Returns whether there's a {Parent} selector anywhere in this sequence.
+      #
+      # @return [Boolean]
+      def contains_parent_ref?
+        members.any? do |sseq_or_op|
+          next false unless sseq_or_op.is_a?(SimpleSequence)
+          next true if sseq_or_op.members.first.is_a?(Parent)
+          sseq_or_op.members.any? do |sel|
+            sel.is_a?(Pseudo) && sel.selector && sel.selector.contains_parent_ref?
+          end
+        end
+      end
+
+      # Non-destructively extends this selector with the extensions specified in a hash
+      # (which should come from {Sass::Tree::Visitors::Cssize}).
+      #
+      # @param extends [Sass::Util::SubsetMap{Selector::Simple =>
+      #                                       Sass::Tree::Visitors::Cssize::Extend}]
+      #   The extensions to perform on this selector
+      # @param parent_directives [Array<Sass::Tree::DirectiveNode>]
+      #   The directives containing this selector.
+      # @param replace [Boolean]
+      #   Whether to replace the original selector entirely or include
+      #   it in the result.
+      # @param seen [Set<Array<Selector::Simple>>]
+      #   The set of simple sequences that are currently being replaced.
+      # @param original [Boolean]
+      #   Whether this is the original selector being extended, as opposed to
+      #   the result of a previous extension that's being re-extended.
+      # @return [Array<Sequence>] A list of selectors generated
+      #   by extending this selector with `extends`.
+      #   These correspond to a {CommaSequence}'s {CommaSequence#members members array}.
+      # @see CommaSequence#do_extend
+      def do_extend(extends, parent_directives, replace, seen, original)
+        extended_not_expanded = members.map do |sseq_or_op|
+          next [[sseq_or_op]] unless sseq_or_op.is_a?(SimpleSequence)
+          extended = sseq_or_op.do_extend(extends, parent_directives, replace, seen)
+
+          # The First Law of Extend says that the generated selector should have
+          # specificity greater than or equal to that of the original selector.
+          # In order to ensure that, we record the original selector's
+          # (`extended.first`) original specificity.
+          extended.first.add_sources!([self]) if original && !has_placeholder?
+
+          extended.map {|seq| seq.members}
+        end
+        weaves = Sass::Util.paths(extended_not_expanded).map {|path| weave(path)}
+        trim(weaves).map {|p| Sequence.new(p)}
+      end
+
+      # Unifies this with another selector sequence to produce a selector
+      # that matches (a subset of) the intersection of the two inputs.
+      #
+      # @param other [Sequence]
+      # @return [CommaSequence, nil] The unified selector, or nil if unification failed.
+      # @raise [Sass::SyntaxError] If this selector cannot be unified.
+      #   This will only ever occur when a dynamic selector,
+      #   such as {Parent} or {Interpolation}, is used in unification.
+      #   Since these selectors should be resolved
+      #   by the time extension and unification happen,
+      #   this exception will only ever be raised as a result of programmer error
+      def unify(other)
+        base = members.last
+        other_base = other.members.last
+        return unless base.is_a?(SimpleSequence) && other_base.is_a?(SimpleSequence)
+        return unless (unified = other_base.unify(base))
+
+        woven = weave([members[0...-1], other.members[0...-1] + [unified]])
+        CommaSequence.new(woven.map {|w| Sequence.new(w)})
+      end
+
+      # Returns whether or not this selector matches all elements
+      # that the given selector matches (as well as possibly more).
+      #
+      # @example
+      #   (.foo).superselector?(.foo.bar) #=> true
+      #   (.foo).superselector?(.bar) #=> false
+      # @param cseq [Sequence]
+      # @return [Boolean]
+      def superselector?(seq)
+        _superselector?(members, seq.members)
+      end
+
+      # @see AbstractSequence#to_s
+      def to_s
+        @members.join(" ").gsub(/ ?\n ?/, "\n")
+      end
+
+      # Returns a string representation of the sequence.
+      # This is basically the selector string.
+      #
+      # @return [String]
+      def inspect
+        members.map {|m| m.inspect}.join(" ")
+      end
+
+      # Add to the {SimpleSequence#sources} sets of the child simple sequences.
+      # This destructively modifies this sequence's members array, but not the
+      # child simple sequences.
+      #
+      # @param sources [Set<Sequence>]
+      def add_sources!(sources)
+        members.map! {|m| m.is_a?(SimpleSequence) ? m.with_more_sources(sources) : m}
+      end
+
+      # Converts the subject operator "!", if it exists, into a ":has()"
+      # selector.
+      #
+      # @retur [Sequence]
+      def subjectless
+        pre_subject = []
+        has = []
+        subject = nil
+        members.each do |sseq_or_op|
+          if subject
+            has << sseq_or_op
+          elsif sseq_or_op.is_a?(String) || !sseq_or_op.subject?
+            pre_subject << sseq_or_op
+          else
+            subject = sseq_or_op.dup
+            subject.members = sseq_or_op.members.dup
+            subject.subject = false
+            has = []
+          end
+        end
+
+        return self unless subject
+
+        unless has.empty?
+          subject.members << Pseudo.new(:class, 'has', nil, CommaSequence.new([Sequence.new(has)]))
+        end
+        Sequence.new(pre_subject + [subject])
+      end
+
+      private
+
+      # Conceptually, this expands "parenthesized selectors". That is, if we
+      # have `.A .B { extend .C}` and `.D .C {...}`, this conceptually expands
+      # into `.D .C, .D (.A .B)`, and this function translates `.D (.A .B)` into
+      # `.D .A .B, .A .D .B`. For thoroughness, `.A.D .B` would also be
+      # required, but including merged selectors results in exponential output
+      # for very little gain.
+      #
+      # @param path [Array<Array<SimpleSequence or String>>]
+      #   A list of parenthesized selector groups.
+      # @return [Array<Array<SimpleSequence or String>>] A list of fully-expanded selectors.
+      def weave(path)
+        # This function works by moving through the selector path left-to-right,
+        # building all possible prefixes simultaneously.
+        prefixes = [[]]
+
+        path.each do |current|
+          next if current.empty?
+          current = current.dup
+          last_current = [current.pop]
+          prefixes = Sass::Util.flatten(prefixes.map do |prefix|
+            sub = subweave(prefix, current)
+            next [] unless sub
+            sub.map {|seqs| seqs + last_current}
+          end, 1)
+        end
+        prefixes
+      end
+
+      # This interweaves two lists of selectors,
+      # returning all possible orderings of them (including using unification)
+      # that maintain the relative ordering of the input arrays.
+      #
+      # For example, given `.foo .bar` and `.baz .bang`,
+      # this would return `.foo .bar .baz .bang`, `.foo .bar.baz .bang`,
+      # `.foo .baz .bar .bang`, `.foo .baz .bar.bang`, `.foo .baz .bang .bar`,
+      # and so on until `.baz .bang .foo .bar`.
+      #
+      # Semantically, for selectors A and B, this returns all selectors `AB_i`
+      # such that the union over all i of elements matched by `AB_i X` is
+      # identical to the intersection of all elements matched by `A X` and all
+      # elements matched by `B X`. Some `AB_i` are elided to reduce the size of
+      # the output.
+      #
+      # @param seq1 [Array<SimpleSequence or String>]
+      # @param seq2 [Array<SimpleSequence or String>]
+      # @return [Array<Array<SimpleSequence or String>>]
+      def subweave(seq1, seq2)
+        return [seq2] if seq1.empty?
+        return [seq1] if seq2.empty?
+
+        seq1, seq2 = seq1.dup, seq2.dup
+        init = merge_initial_ops(seq1, seq2)
+        return unless init
+        fin = merge_final_ops(seq1, seq2)
+        return unless fin
+        seq1 = group_selectors(seq1)
+        seq2 = group_selectors(seq2)
+        lcs = Sass::Util.lcs(seq2, seq1) do |s1, s2|
+          next s1 if s1 == s2
+          next unless s1.first.is_a?(SimpleSequence) && s2.first.is_a?(SimpleSequence)
+          next s2 if parent_superselector?(s1, s2)
+          next s1 if parent_superselector?(s2, s1)
+        end
+
+        diff = [[init]]
+        until lcs.empty?
+          diff << chunks(seq1, seq2) {|s| parent_superselector?(s.first, lcs.first)} << [lcs.shift]
+          seq1.shift
+          seq2.shift
+        end
+        diff << chunks(seq1, seq2) {|s| s.empty?}
+        diff += fin.map {|sel| sel.is_a?(Array) ? sel : [sel]}
+        diff.reject! {|c| c.empty?}
+
+        Sass::Util.paths(diff).map {|p| p.flatten}.reject {|p| path_has_two_subjects?(p)}
+      end
+
+      # Extracts initial selector combinators (`"+"`, `">"`, `"~"`, and `"\n"`)
+      # from two sequences and merges them together into a single array of
+      # selector combinators.
+      #
+      # @param seq1 [Array<SimpleSequence or String>]
+      # @param seq2 [Array<SimpleSequence or String>]
+      # @return [Array<String>, nil] If there are no operators in the merged
+      #   sequence, this will be the empty array. If the operators cannot be
+      #   merged, this will be nil.
+      def merge_initial_ops(seq1, seq2)
+        ops1, ops2 = [], []
+        ops1 << seq1.shift while seq1.first.is_a?(String)
+        ops2 << seq2.shift while seq2.first.is_a?(String)
+
+        newline = false
+        newline ||= !!ops1.shift if ops1.first == "\n"
+        newline ||= !!ops2.shift if ops2.first == "\n"
+
+        # If neither sequence is a subsequence of the other, they cannot be
+        # merged successfully
+        lcs = Sass::Util.lcs(ops1, ops2)
+        return unless lcs == ops1 || lcs == ops2
+        (newline ? ["\n"] : []) + (ops1.size > ops2.size ? ops1 : ops2)
+      end
+
+      # Extracts final selector combinators (`"+"`, `">"`, `"~"`) and the
+      # selectors to which they apply from two sequences and merges them
+      # together into a single array.
+      #
+      # @param seq1 [Array<SimpleSequence or String>]
+      # @param seq2 [Array<SimpleSequence or String>]
+      # @return [Array<SimpleSequence or String or
+      #     Array<Array<SimpleSequence or String>>]
+      #   If there are no trailing combinators to be merged, this will be the
+      #   empty array. If the trailing combinators cannot be merged, this will
+      #   be nil. Otherwise, this will contained the merged selector. Array
+      #   elements are [Sass::Util#paths]-style options; conceptually, an "or"
+      #   of multiple selectors.
+      # @comment
+      #   rubocop:disable MethodLength
+      def merge_final_ops(seq1, seq2, res = [])
+        ops1, ops2 = [], []
+        ops1 << seq1.pop while seq1.last.is_a?(String)
+        ops2 << seq2.pop while seq2.last.is_a?(String)
+
+        # Not worth the headache of trying to preserve newlines here. The most
+        # important use of newlines is at the beginning of the selector to wrap
+        # across lines anyway.
+        ops1.reject! {|o| o == "\n"}
+        ops2.reject! {|o| o == "\n"}
+
+        return res if ops1.empty? && ops2.empty?
+        if ops1.size > 1 || ops2.size > 1
+          # If there are multiple operators, something hacky's going on. If one
+          # is a supersequence of the other, use that, otherwise give up.
+          lcs = Sass::Util.lcs(ops1, ops2)
+          return unless lcs == ops1 || lcs == ops2
+          res.unshift(*(ops1.size > ops2.size ? ops1 : ops2).reverse)
+          return res
+        end
+
+        # This code looks complicated, but it's actually just a bunch of special
+        # cases for interactions between different combinators.
+        op1, op2 = ops1.first, ops2.first
+        if op1 && op2
+          sel1 = seq1.pop
+          sel2 = seq2.pop
+          if op1 == '~' && op2 == '~'
+            if sel1.superselector?(sel2)
+              res.unshift sel2, '~'
+            elsif sel2.superselector?(sel1)
+              res.unshift sel1, '~'
+            else
+              merged = sel1.unify(sel2)
+              res.unshift [
+                [sel1, '~', sel2, '~'],
+                [sel2, '~', sel1, '~'],
+                ([merged, '~'] if merged)
+              ].compact
+            end
+          elsif (op1 == '~' && op2 == '+') || (op1 == '+' && op2 == '~')
+            if op1 == '~'
+              tilde_sel, plus_sel = sel1, sel2
+            else
+              tilde_sel, plus_sel = sel2, sel1
+            end
+
+            if tilde_sel.superselector?(plus_sel)
+              res.unshift plus_sel, '+'
+            else
+              merged = plus_sel.unify(tilde_sel)
+              res.unshift [
+                [tilde_sel, '~', plus_sel, '+'],
+                ([merged, '+'] if merged)
+              ].compact
+            end
+          elsif op1 == '>' && %w[~ +].include?(op2)
+            res.unshift sel2, op2
+            seq1.push sel1, op1
+          elsif op2 == '>' && %w[~ +].include?(op1)
+            res.unshift sel1, op1
+            seq2.push sel2, op2
+          elsif op1 == op2
+            merged = sel1.unify(sel2)
+            return unless merged
+            res.unshift merged, op1
+          else
+            # Unknown selector combinators can't be unified
+            return
+          end
+          return merge_final_ops(seq1, seq2, res)
+        elsif op1
+          seq2.pop if op1 == '>' && seq2.last && seq2.last.superselector?(seq1.last)
+          res.unshift seq1.pop, op1
+          return merge_final_ops(seq1, seq2, res)
+        else # op2
+          seq1.pop if op2 == '>' && seq1.last && seq1.last.superselector?(seq2.last)
+          res.unshift seq2.pop, op2
+          return merge_final_ops(seq1, seq2, res)
+        end
+      end
+      # @comment
+      #   rubocop:enable MethodLength
+
+      # Takes initial subsequences of `seq1` and `seq2` and returns all
+      # orderings of those subsequences. The initial subsequences are determined
+      # by a block.
+      #
+      # Destructively removes the initial subsequences of `seq1` and `seq2`.
+      #
+      # For example, given `(A B C | D E)` and `(1 2 | 3 4 5)` (with `|`
+      # denoting the boundary of the initial subsequence), this would return
+      # `[(A B C 1 2), (1 2 A B C)]`. The sequences would then be `(D E)` and
+      # `(3 4 5)`.
+      #
+      # @param seq1 [Array]
+      # @param seq2 [Array]
+      # @yield [a] Used to determine when to cut off the initial subsequences.
+      #   Called repeatedly for each sequence until it returns true.
+      # @yieldparam a [Array] A final subsequence of one input sequence after
+      #   cutting off some initial subsequence.
+      # @yieldreturn [Boolean] Whether or not to cut off the initial subsequence
+      #   here.
+      # @return [Array<Array>] All possible orderings of the initial subsequences.
+      def chunks(seq1, seq2)
+        chunk1 = []
+        chunk1 << seq1.shift until yield seq1
+        chunk2 = []
+        chunk2 << seq2.shift until yield seq2
+        return [] if chunk1.empty? && chunk2.empty?
+        return [chunk2] if chunk1.empty?
+        return [chunk1] if chunk2.empty?
+        [chunk1 + chunk2, chunk2 + chunk1]
+      end
+
+      # Groups a sequence into subsequences. The subsequences are determined by
+      # strings; adjacent non-string elements will be put into separate groups,
+      # but any element adjacent to a string will be grouped with that string.
+      #
+      # For example, `(A B "C" D E "F" G "H" "I" J)` will become `[(A) (B "C" D)
+      # (E "F" G "H" "I" J)]`.
+      #
+      # @param seq [Array]
+      # @return [Array<Array>]
+      def group_selectors(seq)
+        newseq = []
+        tail = seq.dup
+        until tail.empty?
+          head = []
+          begin
+            head << tail.shift
+          end while !tail.empty? && head.last.is_a?(String) || tail.first.is_a?(String)
+          newseq << head
+        end
+        newseq
+      end
+
+      # Given two selector sequences, returns whether `seq1` is a
+      # superselector of `seq2`; that is, whether `seq1` matches every
+      # element `seq2` matches.
+      #
+      # @param seq1 [Array<SimpleSequence or String>]
+      # @param seq2 [Array<SimpleSequence or String>]
+      # @return [Boolean]
+      def _superselector?(seq1, seq2)
+        seq1 = seq1.reject {|e| e == "\n"}
+        seq2 = seq2.reject {|e| e == "\n"}
+        # Selectors with leading or trailing operators are neither
+        # superselectors nor subselectors.
+        return if seq1.last.is_a?(String) || seq2.last.is_a?(String) ||
+          seq1.first.is_a?(String) || seq2.first.is_a?(String)
+        # More complex selectors are never superselectors of less complex ones
+        return if seq1.size > seq2.size
+        return seq1.first.superselector?(seq2.last, seq2[0...-1]) if seq1.size == 1
+
+        _, si = Sass::Util.enum_with_index(seq2).find do |e, i|
+          return if i == seq2.size - 1
+          next if e.is_a?(String)
+          seq1.first.superselector?(e, seq2[0...i])
+        end
+        return unless si
+
+        if seq1[1].is_a?(String)
+          return unless seq2[si + 1].is_a?(String)
+
+          # .foo ~ .bar is a superselector of .foo + .bar
+          return unless seq1[1] == "~" ? seq2[si + 1] != ">" : seq1[1] == seq2[si + 1]
+
+          # .foo > .baz is not a superselector of .foo > .bar > .baz or .foo >
+          # .bar .baz, despite the fact that .baz is a superselector of .bar >
+          # .baz and .bar .baz. Same goes for + and ~.
+          return if seq1.length == 3 && seq2.length > 3
+
+          return _superselector?(seq1[2..-1], seq2[si + 2..-1])
+        elsif seq2[si + 1].is_a?(String)
+          return unless seq2[si + 1] == ">"
+          return _superselector?(seq1[1..-1], seq2[si + 2..-1])
+        else
+          return _superselector?(seq1[1..-1], seq2[si + 1..-1])
+        end
+      end
+
+      # Like \{#_superselector?}, but compares the selectors in the
+      # context of parent selectors, as though they shared an implicit
+      # base simple selector. For example, `B` is not normally a
+      # superselector of `B A`, since it doesn't match `A` elements.
+      # However, it is a parent superselector, since `B X` is a
+      # superselector of `B A X`.
+      #
+      # @param seq1 [Array<SimpleSequence or String>]
+      # @param seq2 [Array<SimpleSequence or String>]
+      # @return [Boolean]
+      def parent_superselector?(seq1, seq2)
+        base = Sass::Selector::SimpleSequence.new([Sass::Selector::Placeholder.new('<temp>')],
+                                                  false)
+        _superselector?(seq1 + [base], seq2 + [base])
+      end
+
+      # Removes redundant selectors from between multiple lists of
+      # selectors. This takes a list of lists of selector sequences;
+      # each individual list is assumed to have no redundancy within
+      # itself. A selector is only removed if it's redundant with a
+      # selector in another list.
+      #
+      # "Redundant" here means that one selector is a superselector of
+      # the other. The more specific selector is removed.
+      #
+      # @param seqses [Array<Array<Array<SimpleSequence or String>>>]
+      # @return [Array<Array<SimpleSequence or String>>]
+      def trim(seqses)
+        # Avoid truly horrific quadratic behavior. TODO: I think there
+        # may be a way to get perfect trimming without going quadratic.
+        return Sass::Util.flatten(seqses, 1) if seqses.size > 100
+
+        # Keep the results in a separate array so we can be sure we aren't
+        # comparing against an already-trimmed selector. This ensures that two
+        # identical selectors don't mutually trim one another.
+        result = seqses.dup
+
+        # This is n^2 on the sequences, but only comparing between
+        # separate sequences should limit the quadratic behavior.
+        seqses.each_with_index do |seqs1, i|
+          result[i] = seqs1.reject do |seq1|
+            # The maximum specificity of the sources that caused [seq1] to be
+            # generated. In order for [seq1] to be removed, there must be
+            # another selector that's a superselector of it *and* that has
+            # specificity greater or equal to this.
+            max_spec = _sources(seq1).map do |seq|
+              spec = seq.specificity
+              spec.is_a?(Range) ? spec.max : spec
+            end.max || 0
+
+            result.any? do |seqs2|
+              next if seqs1.equal?(seqs2)
+              # Second Law of Extend: the specificity of a generated selector
+              # should never be less than the specificity of the extending
+              # selector.
+              #
+              # See https://github.com/nex3/sass/issues/324.
+              seqs2.any? do |seq2|
+                spec2 = _specificity(seq2)
+                spec2 = spec2.begin if spec2.is_a?(Range)
+                spec2 >= max_spec && _superselector?(seq2, seq1)
+              end
+            end
+          end
+        end
+        Sass::Util.flatten(result, 1)
+      end
+
+      def _hash
+        members.reject {|m| m == "\n"}.hash
+      end
+
+      def _eql?(other)
+        other.members.reject {|m| m == "\n"}.eql?(members.reject {|m| m == "\n"})
+      end
+
+      private
+
+      def path_has_two_subjects?(path)
+        subject = false
+        path.each do |sseq_or_op|
+          next unless sseq_or_op.is_a?(SimpleSequence)
+          next unless sseq_or_op.subject?
+          return true if subject
+          subject = true
+        end
+        false
+      end
+
+      def _sources(seq)
+        s = Set.new
+        seq.map {|sseq_or_op| s.merge sseq_or_op.sources if sseq_or_op.is_a?(SimpleSequence)}
+        s
+      end
+
+      def extended_not_expanded_to_s(extended_not_expanded)
+        extended_not_expanded.map do |choices|
+          choices = choices.map do |sel|
+            next sel.first.to_s if sel.size == 1
+            "#{sel.join ' '}"
+          end
+          next choices.first if choices.size == 1 && !choices.include?(' ')
+          "(#{choices.join ', '})"
+        end.join ' '
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/selector/simple.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/selector/simple.rb
new file mode 100644
index 0000000..bb18e8d
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/selector/simple.rb
@@ -0,0 +1,117 @@
+module Sass
+  module Selector
+    # The abstract superclass for simple selectors
+    # (that is, those that don't compose multiple selectors).
+    class Simple
+      # The line of the Sass template on which this selector was declared.
+      #
+      # @return [Fixnum]
+      attr_accessor :line
+
+      # The name of the file in which this selector was declared,
+      # or `nil` if it was not declared in a file (e.g. on stdin).
+      #
+      # @return [String, nil]
+      attr_accessor :filename
+
+      # @see #to_s
+      #
+      # @return [String]
+      def inspect
+        to_s
+      end
+
+      # Returns the selector string.
+      #
+      # @return [String]
+      def to_s
+        Sass::Util.abstract(self)
+      end
+
+      # Returns a hash code for this selector object.
+      #
+      # By default, this is based on the value of \{#to\_a},
+      # so if that contains information irrelevant to the identity of the selector,
+      # this should be overridden.
+      #
+      # @return [Fixnum]
+      def hash
+        @_hash ||= equality_key.hash
+      end
+
+      # Checks equality between this and another object.
+      #
+      # By default, this is based on the value of \{#to\_a},
+      # so if that contains information irrelevant to the identity of the selector,
+      # this should be overridden.
+      #
+      # @param other [Object] The object to test equality against
+      # @return [Boolean] Whether or not this is equal to `other`
+      def eql?(other)
+        other.class == self.class && other.hash == hash && other.equality_key == equality_key
+      end
+      alias_method :==, :eql?
+
+      # Unifies this selector with a {SimpleSequence}'s {SimpleSequence#members members array},
+      # returning another `SimpleSequence` members array
+      # that matches both this selector and the input selector.
+      #
+      # By default, this just appends this selector to the end of the array
+      # (or returns the original array if this selector already exists in it).
+      #
+      # @param sels [Array<Simple>] A {SimpleSequence}'s {SimpleSequence#members members array}
+      # @return [Array<Simple>, nil] A {SimpleSequence} {SimpleSequence#members members array}
+      #   matching both `sels` and this selector,
+      #   or `nil` if this is impossible (e.g. unifying `#foo` and `#bar`)
+      # @raise [Sass::SyntaxError] If this selector cannot be unified.
+      #   This will only ever occur when a dynamic selector,
+      #   such as {Parent} or {Interpolation}, is used in unification.
+      #   Since these selectors should be resolved
+      #   by the time extension and unification happen,
+      #   this exception will only ever be raised as a result of programmer error
+      def unify(sels)
+        return sels if sels.any? {|sel2| eql?(sel2)}
+        sels_with_ix = Sass::Util.enum_with_index(sels)
+        _, i =
+          if is_a?(Pseudo)
+            sels_with_ix.find {|sel, _| sel.is_a?(Pseudo) && (sels.last.type == :element)}
+          else
+            sels_with_ix.find {|sel, _| sel.is_a?(Pseudo)}
+          end
+        return sels + [self] unless i
+        sels[0...i] + [self] + sels[i..-1]
+      end
+
+      protected
+
+      # Returns the key used for testing whether selectors are equal.
+      #
+      # This is a cached version of \{#to\_s}.
+      #
+      # @return [String]
+      def equality_key
+        @equality_key ||= to_s
+      end
+
+      # Unifies two namespaces,
+      # returning a namespace that works for both of them if possible.
+      #
+      # @param ns1 [String, nil] The first namespace.
+      #   `nil` means none specified, e.g. `foo`.
+      #   The empty string means no namespace specified, e.g. `|foo`.
+      #   `"*"` means any namespace is allowed, e.g. `*|foo`.
+      # @param ns2 [String, nil] The second namespace. See `ns1`.
+      # @return [Array(String or nil, Boolean)]
+      #   The first value is the unified namespace, or `nil` for no namespace.
+      #   The second value is whether or not a namespace that works for both inputs
+      #   could be found at all.
+      #   If the second value is `false`, the first should be ignored.
+      def unify_namespaces(ns1, ns2)
+        return nil, false unless ns1 == ns2 || ns1.nil? || ns1 == '*' || ns2.nil? || ns2 == '*'
+        return ns2, true if ns1 == '*'
+        return ns1, true if ns2 == '*'
+        [ns1 || ns2, true]
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/selector/simple_sequence.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/selector/simple_sequence.rb
new file mode 100644
index 0000000..bfcda10
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/selector/simple_sequence.rb
@@ -0,0 +1,344 @@
+module Sass
+  module Selector
+    # A unseparated sequence of selectors
+    # that all apply to a single element.
+    # For example, `.foo#bar[attr=baz]` is a simple sequence
+    # of the selectors `.foo`, `#bar`, and `[attr=baz]`.
+    class SimpleSequence < AbstractSequence
+      # The array of individual selectors.
+      #
+      # @return [Array<Simple>]
+      attr_accessor :members
+
+      # The extending selectors that caused this selector sequence to be
+      # generated. For example:
+      #
+      #     a.foo { ... }
+      #     b.bar { extend a}
+      #     c.baz { extend b}
+      #
+      # The generated selector `b.foo.bar` has `{b.bar}` as its `sources` set,
+      # and the generated selector `c.foo.bar.baz` has `{b.bar, c.baz}` as its
+      # `sources` set.
+      #
+      # This is populated during the {Sequence#do_extend} process.
+      #
+      # @return {Set<Sequence>}
+      attr_accessor :sources
+
+      # This sequence source range.
+      #
+      # @return [Sass::Source::Range]
+      attr_accessor :source_range
+
+      # @see \{#subject?}
+      attr_writer :subject
+
+      # Returns the element or universal selector in this sequence,
+      # if it exists.
+      #
+      # @return [Element, Universal, nil]
+      def base
+        @base ||= (members.first if members.first.is_a?(Element) || members.first.is_a?(Universal))
+      end
+
+      def pseudo_elements
+        @pseudo_elements ||= members.select {|sel| sel.is_a?(Pseudo) && sel.type == :element}
+      end
+
+      def selector_pseudo_classes
+        @selector_pseudo_classes ||= members.
+          select {|sel| sel.is_a?(Pseudo) && sel.type == :class && sel.selector}.
+          group_by {|sel| sel.normalized_name}
+      end
+
+      # Returns the non-base, non-pseudo-element selectors in this sequence.
+      #
+      # @return [Set<Simple>]
+      def rest
+        @rest ||= Set.new(members - [base] - pseudo_elements)
+      end
+
+      # Whether or not this compound selector is the subject of the parent
+      # selector; that is, whether it is prepended with `$` and represents the
+      # actual element that will be selected.
+      #
+      # @return [Boolean]
+      def subject?
+        @subject
+      end
+
+      # @param selectors [Array<Simple>] See \{#members}
+      # @param subject [Boolean] See \{#subject?}
+      # @param source_range [Sass::Source::Range]
+      def initialize(selectors, subject, source_range = nil)
+        @members = selectors
+        @subject = subject
+        @sources = Set.new
+        @source_range = source_range
+      end
+
+      # Resolves the {Parent} selectors within this selector
+      # by replacing them with the given parent selector,
+      # handling commas appropriately.
+      #
+      # @param super_cseq [CommaSequence] The parent selector
+      # @return [CommaSequence] This selector, with parent references resolved
+      # @raise [Sass::SyntaxError] If a parent selector is invalid
+      def resolve_parent_refs(super_cseq)
+        resolved_members = @members.map do |sel|
+          next sel unless sel.is_a?(Pseudo) && sel.selector
+          sel.with_selector(sel.selector.resolve_parent_refs(super_cseq, !:implicit_parent))
+        end.flatten
+
+        # Parent selector only appears as the first selector in the sequence
+        unless (parent = resolved_members.first).is_a?(Parent)
+          return CommaSequence.new([Sequence.new([SimpleSequence.new(resolved_members, subject?)])])
+        end
+
+        return super_cseq if @members.size == 1 && parent.suffix.nil?
+
+        CommaSequence.new(super_cseq.members.map do |super_seq|
+          members = super_seq.members.dup
+          newline = members.pop if members.last == "\n"
+          unless members.last.is_a?(SimpleSequence)
+            raise Sass::SyntaxError.new("Invalid parent selector for \"#{self}\": \"" +
+              super_seq.to_s + '"')
+          end
+
+          parent_sub = members.last.members
+          unless parent.suffix.nil?
+            parent_sub = parent_sub.dup
+            parent_sub[-1] = parent_sub.last.dup
+            case parent_sub.last
+            when Sass::Selector::Class, Sass::Selector::Id, Sass::Selector::Placeholder
+              parent_sub[-1] = parent_sub.last.class.new(parent_sub.last.name + parent.suffix)
+            when Sass::Selector::Element
+              parent_sub[-1] = parent_sub.last.class.new(
+                parent_sub.last.name + parent.suffix,
+                parent_sub.last.namespace)
+            when Sass::Selector::Pseudo
+              if parent_sub.last.arg || parent_sub.last.selector
+                raise Sass::SyntaxError.new("Invalid parent selector for \"#{self}\": \"" +
+                  super_seq.to_s + '"')
+              end
+              parent_sub[-1] = Sass::Selector::Pseudo.new(
+                parent_sub.last.type,
+                parent_sub.last.name + parent.suffix,
+                nil, nil)
+            else
+              raise Sass::SyntaxError.new("Invalid parent selector for \"#{self}\": \"" +
+                super_seq.to_s + '"')
+            end
+          end
+
+          Sequence.new(members[0...-1] +
+            [SimpleSequence.new(parent_sub + @members[1..-1], subject?)] +
+            [newline].compact)
+        end)
+      end
+
+      # Non-destructively extends this selector with the extensions specified in a hash
+      # (which should come from {Sass::Tree::Visitors::Cssize}).
+      #
+      # @param extends [{Selector::Simple =>
+      #                  Sass::Tree::Visitors::Cssize::Extend}]
+      #   The extensions to perform on this selector
+      # @param parent_directives [Array<Sass::Tree::DirectiveNode>]
+      #   The directives containing this selector.
+      # @param seen [Set<Array<Selector::Simple>>]
+      #   The set of simple sequences that are currently being replaced.
+      # @param original [Boolean]
+      #   Whether this is the original selector being extended, as opposed to
+      #   the result of a previous extension that's being re-extended.
+      # @return [Array<Sequence>] A list of selectors generated
+      #   by extending this selector with `extends`.
+      # @see CommaSequence#do_extend
+      def do_extend(extends, parent_directives, replace, seen)
+        seen_with_pseudo_selectors = seen.dup
+
+        modified_original = false
+        members = Sass::Util.enum_with_index(self.members).map do |sel, i|
+          next sel unless sel.is_a?(Pseudo) && sel.selector
+          next sel if seen.include?([sel])
+          extended = sel.selector.do_extend(extends, parent_directives, replace, seen, !:original)
+          next sel if extended == sel.selector
+          extended.members.reject! {|seq| seq.has_placeholder?}
+
+          # For `:not()`, we usually want to get rid of any complex
+          # selectors becuase that will cause the selector to fail to
+          # parse on all browsers at time of writing. We can keep them
+          # if either the original selector had a complex selector, or
+          # the result of extending has only complex selectors,
+          # because either way we aren't breaking anything that isn't
+          # already broken.
+          if sel.normalized_name == 'not' &&
+              (sel.selector.members.none? {|seq| seq.members.length > 1} &&
+               extended.members.any? {|seq| seq.members.length == 1})
+            extended.members.reject! {|seq| seq.members.length > 1}
+          end
+
+          modified_original = true
+          result = sel.with_selector(extended)
+          result.each {|new_sel| seen_with_pseudo_selectors << [new_sel]}
+          result
+        end.flatten
+
+        groups = Sass::Util.group_by_to_a(extends[members.to_set]) {|ex| ex.extender}
+        groups.map! do |seq, group|
+          sels = group.map {|e| e.target}.flatten
+          # If A { extend B} and C {...},
+          # seq is A, sels is B, and self is C
+
+          self_without_sel = Sass::Util.array_minus(members, sels)
+          group.each {|e| e.result = :failed_to_unify unless e.result == :succeeded}
+          unified = seq.members.last.unify(SimpleSequence.new(self_without_sel, subject?))
+          next unless unified
+          group.each {|e| e.result = :succeeded}
+          group.each {|e| check_directives_match!(e, parent_directives)}
+          new_seq = Sequence.new(seq.members[0...-1] + [unified])
+          new_seq.add_sources!(sources + [seq])
+          [sels, new_seq]
+        end
+        groups.compact!
+        groups.map! do |sels, seq|
+          next [] if seen.include?(sels)
+          seq.do_extend(
+            extends, parent_directives, !:replace, seen_with_pseudo_selectors + [sels], !:original)
+        end
+        groups.flatten!
+
+        if modified_original || !replace || groups.empty?
+          # First Law of Extend: the result of extending a selector should
+          # (almost) always contain the base selector.
+          #
+          # See https://github.com/nex3/sass/issues/324.
+          original = Sequence.new([SimpleSequence.new(members, @subject, source_range)])
+          original.add_sources! sources
+          groups.unshift original
+        end
+        groups.uniq!
+        groups
+      end
+
+      # Unifies this selector with another {SimpleSequence}, returning
+      # another `SimpleSequence` that is a subselector of both input
+      # selectors.
+      #
+      # @param other [SimpleSequence]
+      # @return [SimpleSequence, nil] A {SimpleSequence} matching both `sels` and this selector,
+      #   or `nil` if this is impossible (e.g. unifying `#foo` and `#bar`)
+      # @raise [Sass::SyntaxError] If this selector cannot be unified.
+      #   This will only ever occur when a dynamic selector,
+      #   such as {Parent} or {Interpolation}, is used in unification.
+      #   Since these selectors should be resolved
+      #   by the time extension and unification happen,
+      #   this exception will only ever be raised as a result of programmer error
+      def unify(other)
+        sseq = members.inject(other.members) do |member, sel|
+          return unless member
+          sel.unify(member)
+        end
+        return unless sseq
+        SimpleSequence.new(sseq, other.subject? || subject?)
+      end
+
+      # Returns whether or not this selector matches all elements
+      # that the given selector matches (as well as possibly more).
+      #
+      # @example
+      #   (.foo).superselector?(.foo.bar) #=> true
+      #   (.foo).superselector?(.bar) #=> false
+      # @param their_sseq [SimpleSequence]
+      # @param parents [Array<SimpleSequence, String>] The parent selectors of `their_sseq`, if any.
+      # @return [Boolean]
+      def superselector?(their_sseq, parents = [])
+        return false unless base.nil? || base.eql?(their_sseq.base)
+        return false unless pseudo_elements.eql?(their_sseq.pseudo_elements)
+        our_spcs = selector_pseudo_classes
+        their_spcs = their_sseq.selector_pseudo_classes
+
+        # Some psuedo-selectors can be subselectors of non-pseudo selectors.
+        # Pull those out here so we can efficiently check against them below.
+        their_subselector_pseudos = %w[matches any nth-child nth-last-child].
+          map {|name| their_spcs[name] || []}.flatten
+
+        # If `self`'s non-pseudo simple selectors aren't a subset of `their_sseq`'s,
+        # it's definitely not a superselector. This also considers being matched
+        # by `:matches` or `:any`.
+        return false unless rest.all? do |our_sel|
+          next true if our_sel.is_a?(Pseudo) && our_sel.selector
+          next true if their_sseq.rest.include?(our_sel)
+          their_subselector_pseudos.any? do |their_pseudo|
+            their_pseudo.selector.members.all? do |their_seq|
+              next false unless their_seq.members.length == 1
+              their_sseq = their_seq.members.first
+              next false unless their_sseq.is_a?(SimpleSequence)
+              their_sseq.rest.include?(our_sel)
+            end
+          end
+        end
+
+        our_spcs.all? do |name, pseudos|
+          pseudos.all? {|pseudo| pseudo.superselector?(their_sseq, parents)}
+        end
+      end
+
+      # @see Simple#to_s
+      def to_s
+        res = @members.join
+        res << '!' if subject?
+        res
+      end
+
+      # Returns a string representation of the sequence.
+      # This is basically the selector string.
+      #
+      # @return [String]
+      def inspect
+        res = members.map {|m| m.inspect}.join
+        res << '!' if subject?
+        res
+      end
+
+      # Return a copy of this simple sequence with `sources` merged into the
+      # {SimpleSequence#sources} set.
+      #
+      # @param sources [Set<Sequence>]
+      # @return [SimpleSequence]
+      def with_more_sources(sources)
+        sseq = dup
+        sseq.members = members.dup
+        sseq.sources = self.sources | sources
+        sseq
+      end
+
+      private
+
+      def check_directives_match!(extend, parent_directives)
+        dirs1 = extend.directives.map {|d| d.resolved_value}
+        dirs2 = parent_directives.map {|d| d.resolved_value}
+        return if Sass::Util.subsequence?(dirs1, dirs2)
+        line = extend.node.line
+        filename = extend.node.filename
+
+        # TODO(nweiz): this should use the Sass stack trace of the extend node,
+        # not the selector.
+        raise Sass::SyntaxError.new(<<MESSAGE)
+You may not @extend an outer selector from within #{extend.directives.last.name}.
+You may only @extend selectors within the same directive.
+From "@extend #{extend.target.join(', ')}" on line #{line}#{" of #{filename}" if filename}.
+MESSAGE
+      end
+
+      def _hash
+        [base, Sass::Util.set_hash(rest)].hash
+      end
+
+      def _eql?(other)
+        other.base.eql?(base) && other.pseudo_elements == pseudo_elements &&
+          Sass::Util.set_eql?(other.rest, rest) && other.subject? == subject?
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/shared.rb b/backends/css/gems/sass-3.4.9/lib/sass/shared.rb
new file mode 100644
index 0000000..9e9189c
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/shared.rb
@@ -0,0 +1,76 @@
+module Sass
+  # This module contains functionality that's shared between Haml and Sass.
+  module Shared
+    extend self
+
+    # Scans through a string looking for the interoplation-opening `#{`
+    # and, when it's found, yields the scanner to the calling code
+    # so it can handle it properly.
+    #
+    # The scanner will have any backslashes immediately in front of the `#{`
+    # as the second capture group (`scan[2]`),
+    # and the text prior to that as the first (`scan[1]`).
+    #
+    # @yieldparam scan [StringScanner] The scanner scanning through the string
+    # @return [String] The text remaining in the scanner after all `#{`s have been processed
+    def handle_interpolation(str)
+      scan = Sass::Util::MultibyteStringScanner.new(str)
+      yield scan while scan.scan(/(.*?)(\\*)\#\{/m)
+      scan.rest
+    end
+
+    # Moves a scanner through a balanced pair of characters.
+    # For example:
+    #
+    #     Foo (Bar (Baz bang) bop) (Bang (bop bip))
+    #     ^                       ^
+    #     from                    to
+    #
+    # @param scanner [StringScanner] The string scanner to move
+    # @param start [Character] The character opening the balanced pair.
+    #   A `Fixnum` in 1.8, a `String` in 1.9
+    # @param finish [Character] The character closing the balanced pair.
+    #   A `Fixnum` in 1.8, a `String` in 1.9
+    # @param count [Fixnum] The number of opening characters matched
+    #   before calling this method
+    # @return [(String, String)] The string matched within the balanced pair
+    #   and the rest of the string.
+    #   `["Foo (Bar (Baz bang) bop)", " (Bang (bop bip))"]` in the example above.
+    def balance(scanner, start, finish, count = 0)
+      str = ''
+      scanner = Sass::Util::MultibyteStringScanner.new(scanner) unless scanner.is_a? StringScanner
+      regexp = Regexp.new("(.*?)[\\#{start.chr}\\#{finish.chr}]", Regexp::MULTILINE)
+      while scanner.scan(regexp)
+        str << scanner.matched
+        count += 1 if scanner.matched[-1] == start
+        count -= 1 if scanner.matched[-1] == finish
+        return [str, scanner.rest] if count == 0
+      end
+    end
+
+    # Formats a string for use in error messages about indentation.
+    #
+    # @param indentation [String] The string used for indentation
+    # @param was [Boolean] Whether or not to add `"was"` or `"were"`
+    #   (depending on how many characters were in `indentation`)
+    # @return [String] The name of the indentation (e.g. `"12 spaces"`, `"1 tab"`)
+    def human_indentation(indentation, was = false)
+      if !indentation.include?(?\t)
+        noun = 'space'
+      elsif !indentation.include?(?\s)
+        noun = 'tab'
+      else
+        return indentation.inspect + (was ? ' was' : '')
+      end
+
+      singular = indentation.length == 1
+      if was
+        was = singular ? ' was' : ' were'
+      else
+        was = ''
+      end
+
+      "#{indentation.length} #{noun}#{'s' unless singular}#{was}"
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/source/map.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/source/map.rb
new file mode 100644
index 0000000..fdad539
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/source/map.rb
@@ -0,0 +1,211 @@
+module Sass::Source
+  class Map
+    # A mapping from one source range to another. Indicates that `input` was
+    # compiled to `output`.
+    #
+    # @!attribute input
+    #   @return [Sass::Source::Range] The source range in the input document.
+    #
+    # @!attribute output
+    #   @return [Sass::Source::Range] The source range in the output document.
+    class Mapping < Struct.new(:input, :output)
+      # @return [String] A string representation of the mapping.
+      def inspect
+        "#{input.inspect} => #{output.inspect}"
+      end
+    end
+
+    # The mapping data ordered by the location in the target.
+    #
+    # @return [Array<Mapping>]
+    attr_reader :data
+
+    def initialize
+      @data = []
+    end
+
+    # Adds a new mapping from one source range to another. Multiple invocations
+    # of this method should have each `output` range come after all previous ranges.
+    #
+    # @param input [Sass::Source::Range]
+    #   The source range in the input document.
+    # @param output [Sass::Source::Range]
+    #   The source range in the output document.
+    def add(input, output)
+      @data.push(Mapping.new(input, output))
+    end
+
+    # Shifts all output source ranges forward one or more lines.
+    #
+    # @param delta [Fixnum] The number of lines to shift the ranges forward.
+    def shift_output_lines(delta)
+      return if delta == 0
+      @data.each do |m|
+        m.output.start_pos.line += delta
+        m.output.end_pos.line += delta
+      end
+    end
+
+    # Shifts any output source ranges that lie on the first line forward one or
+    # more characters on that line.
+    #
+    # @param delta [Fixnum] The number of characters to shift the ranges
+    #   forward.
+    def shift_output_offsets(delta)
+      return if delta == 0
+      @data.each do |m|
+        break if m.output.start_pos.line > 1
+        m.output.start_pos.offset += delta
+        m.output.end_pos.offset += delta if m.output.end_pos.line > 1
+      end
+    end
+
+    # Returns the standard JSON representation of the source map.
+    #
+    # If the `:css_uri` option isn't specified, the `:css_path` and
+    # `:sourcemap_path` options must both be specified. Any options may also be
+    # specified alongside the `:css_uri` option. If `:css_uri` isn't specified,
+    # it will be inferred from `:css_path` and `:sourcemap_path` using the
+    # assumption that the local file system has the same layout as the server.
+    #
+    # Regardless of which options are passed to this method, source stylesheets
+    # that are imported using a non-default importer will only be linked to in
+    # the source map if their importers implement
+    # \{Sass::Importers::Base#public\_url\}.
+    #
+    # @option options :css_uri [String]
+    #   The publicly-visible URI of the CSS output file.
+    # @option options :css_path [String]
+    #   The local path of the CSS output file.
+    # @option options :sourcemap_path [String]
+    #   The (eventual) local path of the sourcemap file.
+    # @option options :type [Symbol]
+    #   `:auto` (default),  `:file`, or `:inline`.
+    # @return [String] The JSON string.
+    # @raise [ArgumentError] If neither `:css_uri` nor `:css_path` and
+    #   `:sourcemap_path` are specified.
+    # @comment
+    #   rubocop:disable MethodLength
+    def to_json(options)
+      css_uri, css_path, sourcemap_path =
+        options[:css_uri], options[:css_path], options[:sourcemap_path]
+      unless css_uri || (css_path && sourcemap_path)
+        raise ArgumentError.new("Sass::Source::Map#to_json requires either " \
+          "the :css_uri option or both the :css_path and :soucemap_path options.")
+      end
+      css_path &&= Sass::Util.pathname(Sass::Util.absolute_path(css_path))
+      sourcemap_path &&= Sass::Util.pathname(Sass::Util.absolute_path(sourcemap_path))
+      css_uri ||= Sass::Util.file_uri_from_path(
+        Sass::Util.relative_path_from(css_path, sourcemap_path.dirname))
+
+      result = "{\n"
+      write_json_field(result, "version", 3, true)
+
+      source_uri_to_id = {}
+      id_to_source_uri = {}
+      id_to_contents = {} if options[:type] == :inline
+      next_source_id = 0
+      line_data = []
+      segment_data_for_line = []
+
+      # These track data necessary for the delta coding.
+      previous_target_line = nil
+      previous_target_offset = 1
+      previous_source_line = 1
+      previous_source_offset = 1
+      previous_source_id = 0
+
+      @data.each do |m|
+        file, importer = m.input.file, m.input.importer
+
+        if options[:type] == :inline
+          source_uri = file
+        else
+          sourcemap_dir = sourcemap_path && sourcemap_path.dirname.to_s
+          sourcemap_dir = nil if options[:type] == :file
+          source_uri = importer && importer.public_url(file, sourcemap_dir)
+          next unless source_uri
+        end
+
+        current_source_id = source_uri_to_id[source_uri]
+        unless current_source_id
+          current_source_id = next_source_id
+          next_source_id += 1
+
+          source_uri_to_id[source_uri] = current_source_id
+          id_to_source_uri[current_source_id] = source_uri
+
+          if options[:type] == :inline
+            id_to_contents[current_source_id] =
+              importer.find(file, {}).instance_variable_get('@template')
+          end
+        end
+
+        [
+          [m.input.start_pos, m.output.start_pos],
+          [m.input.end_pos, m.output.end_pos]
+        ].each do |source_pos, target_pos|
+          if previous_target_line != target_pos.line
+            line_data.push(segment_data_for_line.join(",")) unless segment_data_for_line.empty?
+            (target_pos.line - 1 - (previous_target_line || 0)).times {line_data.push("")}
+            previous_target_line = target_pos.line
+            previous_target_offset = 1
+            segment_data_for_line = []
+          end
+
+          # `segment` is a data chunk for a single position mapping.
+          segment = ""
+
+          # Field 1: zero-based starting offset.
+          segment << Sass::Util.encode_vlq(target_pos.offset - previous_target_offset)
+          previous_target_offset = target_pos.offset
+
+          # Field 2: zero-based index into the "sources" list.
+          segment << Sass::Util.encode_vlq(current_source_id - previous_source_id)
+          previous_source_id = current_source_id
+
+          # Field 3: zero-based starting line in the original source.
+          segment << Sass::Util.encode_vlq(source_pos.line - previous_source_line)
+          previous_source_line = source_pos.line
+
+          # Field 4: zero-based starting offset in the original source.
+          segment << Sass::Util.encode_vlq(source_pos.offset - previous_source_offset)
+          previous_source_offset = source_pos.offset
+
+          segment_data_for_line.push(segment)
+
+          previous_target_line = target_pos.line
+        end
+      end
+      line_data.push(segment_data_for_line.join(","))
+      write_json_field(result, "mappings", line_data.join(";"))
+
+      source_names = []
+      (0...next_source_id).each {|id| source_names.push(id_to_source_uri[id].to_s)}
+      write_json_field(result, "sources", source_names)
+
+      if options[:type] == :inline
+        write_json_field(result, "sourcesContent",
+          (0...next_source_id).map {|id| id_to_contents[id]})
+      end
+
+      write_json_field(result, "names", [])
+      write_json_field(result, "file", css_uri)
+
+      result << "\n}"
+      result
+    end
+    # @comment
+    #   rubocop:enable MethodLength
+
+    private
+
+    def write_json_field(out, name, value, is_first = false)
+      out << (is_first ? "" : ",\n") <<
+        "\"" <<
+        Sass::Util.json_escape_string(name) <<
+        "\": " <<
+        Sass::Util.json_value_of(value)
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/source/position.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/source/position.rb
new file mode 100644
index 0000000..df39bd3
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/source/position.rb
@@ -0,0 +1,39 @@
+module Sass::Source
+  class Position
+    # The one-based line of the document associated with the position.
+    #
+    # @return [Fixnum]
+    attr_accessor :line
+
+    # The one-based offset in the line of the document associated with the
+    # position.
+    #
+    # @return [Fixnum]
+    attr_accessor :offset
+
+    # @param line [Fixnum] The source line
+    # @param offset [Fixnum] The source offset
+    def initialize(line, offset)
+      @line = line
+      @offset = offset
+    end
+
+    # @return [String] A string representation of the source position.
+    def inspect
+      "#{line.inspect}:#{offset.inspect}"
+    end
+
+    # @param str [String] The string to move through.
+    # @return [Position] The source position after proceeding forward through
+    #   `str`.
+    def after(str)
+      newlines = str.count("\n")
+      Position.new(line + newlines,
+        if newlines == 0
+          offset + str.length
+        else
+          str.length - str.rindex("\n") - 1
+        end)
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/source/range.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/source/range.rb
new file mode 100644
index 0000000..de687f9
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/source/range.rb
@@ -0,0 +1,41 @@
+module Sass::Source
+  class Range
+    # The starting position of the range in the document (inclusive).
+    #
+    # @return [Sass::Source::Position]
+    attr_accessor :start_pos
+
+    # The ending position of the range in the document (exclusive).
+    #
+    # @return [Sass::Source::Position]
+    attr_accessor :end_pos
+
+    # The file in which this source range appears. This can be nil if the file
+    # is unknown or not yet generated.
+    #
+    # @return [String]
+    attr_accessor :file
+
+    # The importer that imported the file in which this source range appears.
+    # This is nil for target ranges.
+    #
+    # @return [Sass::Importers::Base]
+    attr_accessor :importer
+
+    # @param start_pos [Sass::Source::Position] See \{#start_pos}
+    # @param end_pos [Sass::Source::Position] See \{#end_pos}
+    # @param file [String] See \{#file}
+    # @param importer [Sass::Importers::Base] See \{#importer}
+    def initialize(start_pos, end_pos, file, importer = nil)
+      @start_pos = start_pos
+      @end_pos = end_pos
+      @file = file
+      @importer = importer
+    end
+
+    # @return [String] A string representation of the source range.
+    def inspect
+      "(#{start_pos.inspect} to #{end_pos.inspect}#{" in #{ file}" if @file})"
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/stack.rb b/backends/css/gems/sass-3.4.9/lib/sass/stack.rb
new file mode 100644
index 0000000..3036d42
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/stack.rb
@@ -0,0 +1,120 @@
+module Sass
+  # A class representing the stack when compiling a Sass file.
+  class Stack
+    # TODO: use this to generate stack information for Sass::SyntaxErrors.
+
+    # A single stack frame.
+    class Frame
+      # The filename of the file in which this stack frame was created.
+      #
+      # @return [String]
+      attr_reader :filename
+
+      # The line number on which this stack frame was created.
+      #
+      # @return [String]
+      attr_reader :line
+
+      # The type of this stack frame. This can be `:import`, `:mixin`, or
+      # `:base`.
+      #
+      # `:base` indicates that this is the bottom-most frame, meaning that it
+      # represents a single line of code rather than a nested context. The stack
+      # will only ever have one base frame, and it will always be the most
+      # deeply-nested frame.
+      #
+      # @return [Symbol?]
+      attr_reader :type
+
+      # The name of the stack frame. For mixin frames, this is the mixin name;
+      # otherwise, it's `nil`.
+      #
+      # @return [String?]
+      attr_reader :name
+
+      def initialize(filename, line, type, name = nil)
+        @filename = filename
+        @line = line
+        @type = type
+        @name = name
+      end
+
+      # Whether this frame represents an import.
+      #
+      # @return [Boolean]
+      def is_import?
+        type == :import
+      end
+
+      # Whether this frame represents a mixin.
+      #
+      # @return [Boolean]
+      def is_mixin?
+        type == :mixin
+      end
+
+      # Whether this is the base frame.
+      #
+      # @return [Boolean]
+      def is_base?
+        type == :base
+      end
+    end
+
+    # The stack frames. The last frame is the most deeply-nested.
+    #
+    # @return [Array<Frame>]
+    attr_reader :frames
+
+    def initialize
+      @frames = []
+    end
+
+    # Pushes a base frame onto the stack.
+    #
+    # @param filename [String] See \{Frame#filename}.
+    # @param line [String] See \{Frame#line}.
+    # @yield [] A block in which the new frame is on the stack.
+    def with_base(filename, line)
+      with_frame(filename, line, :base) {yield}
+    end
+
+    # Pushes an import frame onto the stack.
+    #
+    # @param filename [String] See \{Frame#filename}.
+    # @param line [String] See \{Frame#line}.
+    # @yield [] A block in which the new frame is on the stack.
+    def with_import(filename, line)
+      with_frame(filename, line, :import) {yield}
+    end
+
+    # Pushes a mixin frame onto the stack.
+    #
+    # @param filename [String] See \{Frame#filename}.
+    # @param line [String] See \{Frame#line}.
+    # @param name [String] See \{Frame#name}.
+    # @yield [] A block in which the new frame is on the stack.
+    def with_mixin(filename, line, name)
+      with_frame(filename, line, :mixin, name) {yield}
+    end
+
+    def to_s
+      Sass::Util.enum_with_index(Sass::Util.enum_cons(frames.reverse + [nil], 2)).
+          map do |(frame, caller), i|
+        "#{i == 0 ? "on" : "from"} line #{frame.line}" +
+          " of #{frame.filename || "an unknown file"}" +
+          (caller && caller.name ? ", in `#{caller.name}'" : "")
+      end.join("\n")
+    end
+
+    private
+
+    def with_frame(filename, line, type, name = nil)
+      @frames.pop if @frames.last && @frames.last.type == :base
+      @frames.push(Frame.new(filename, line, type, name))
+      yield
+    ensure
+      @frames.pop unless type == :base && @frames.last && @frames.last.type != :base
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/supports.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/supports.rb
new file mode 100644
index 0000000..ee67254
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/supports.rb
@@ -0,0 +1,227 @@
+# A namespace for the ` supports` condition parse tree.
+module Sass::Supports
+  # The abstract superclass of all Supports conditions.
+  class Condition
+    # Runs the SassScript in the supports condition.
+    #
+    # @param environment [Sass::Environment] The environment in which to run the script.
+    def perform(environment); Sass::Util.abstract(self); end
+
+    # Returns the CSS for this condition.
+    #
+    # @return [String]
+    def to_css; Sass::Util.abstract(self); end
+
+    # Returns the Sass/CSS code for this condition.
+    #
+    # @param options [{Symbol => Object}] An options hash (see {Sass::CSS#initialize}).
+    # @return [String]
+    def to_src(options); Sass::Util.abstract(self); end
+
+    # Returns a deep copy of this condition and all its children.
+    #
+    # @return [Condition]
+    def deep_copy; Sass::Util.abstract(self); end
+
+    # Sets the options hash for the script nodes in the supports condition.
+    #
+    # @param options [{Symbol => Object}] The options has to set.
+    def options=(options); Sass::Util.abstract(self); end
+  end
+
+  # An operator condition (e.g. `CONDITION1 and CONDITION2`).
+  class Operator < Condition
+    # The left-hand condition.
+    #
+    # @return [Sass::Supports::Condition]
+    attr_accessor :left
+
+    # The right-hand condition.
+    #
+    # @return [Sass::Supports::Condition]
+    attr_accessor :right
+
+    # The operator ("and" or "or").
+    #
+    # @return [String]
+    attr_accessor :op
+
+    def initialize(left, right, op)
+      @left = left
+      @right = right
+      @op = op
+    end
+
+    def perform(env)
+      @left.perform(env)
+      @right.perform(env)
+    end
+
+    def to_css
+      "#{left_parens @left.to_css} #{op} #{right_parens @right.to_css}"
+    end
+
+    def to_src(options)
+      "#{left_parens @left.to_src(options)} #{op} #{right_parens @right.to_src(options)}"
+    end
+
+    def deep_copy
+      copy = dup
+      copy.left = @left.deep_copy
+      copy.right = @right.deep_copy
+      copy
+    end
+
+    def options=(options)
+      @left.options = options
+      @right.options = options
+    end
+
+    private
+
+    def left_parens(str)
+      return "(#{str})" if @left.is_a?(Negation)
+      str
+    end
+
+    def right_parens(str)
+      return "(#{str})" if @right.is_a?(Negation) || @right.is_a?(Operator)
+      str
+    end
+  end
+
+  # A negation condition (`not CONDITION`).
+  class Negation < Condition
+    # The condition being negated.
+    #
+    # @return [Sass::Supports::Condition]
+    attr_accessor :condition
+
+    def initialize(condition)
+      @condition = condition
+    end
+
+    def perform(env)
+      @condition.perform(env)
+    end
+
+    def to_css
+      "not #{parens @condition.to_css}"
+    end
+
+    def to_src(options)
+      "not #{parens @condition.to_src(options)}"
+    end
+
+    def deep_copy
+      copy = dup
+      copy.condition = condition.deep_copy
+      copy
+    end
+
+    def options=(options)
+      condition.options = options
+    end
+
+    private
+
+    def parens(str)
+      return "(#{str})" if @condition.is_a?(Negation) || @condition.is_a?(Operator)
+      str
+    end
+  end
+
+  # A declaration condition (e.g. `(feature: value)`).
+  class Declaration < Condition
+    # @return [Sass::Script::Tree::Node] The feature name.
+    attr_accessor :name
+
+    # @!attribute resolved_name
+    #   The name of the feature after any SassScript has been resolved.
+    #   Only set once \{Tree::Visitors::Perform} has been run.
+    #
+    #   @return [String]
+    attr_accessor :resolved_name
+
+    # The feature value.
+    #
+    # @return [Sass::Script::Tree::Node]
+    attr_accessor :value
+
+    # The value of the feature after any SassScript has been resolved.
+    # Only set once \{Tree::Visitors::Perform} has been run.
+    #
+    # @return [String]
+    attr_accessor :resolved_value
+
+    def initialize(name, value)
+      @name = name
+      @value = value
+    end
+
+    def perform(env)
+      @resolved_name = name.perform(env)
+      @resolved_value = value.perform(env)
+    end
+
+    def to_css
+      "(#{ resolved_name}: #{ resolved_value})"
+    end
+
+    def to_src(options)
+      "(#{ name to_sass(options)}: #{ value to_sass(options)})"
+    end
+
+    def deep_copy
+      copy = dup
+      copy.name = @name.deep_copy
+      copy.value = @value.deep_copy
+      copy
+    end
+
+    def options=(options)
+      @name.options = options
+      @value.options = options
+    end
+  end
+
+  # An interpolation condition (e.g. `#{$var}`).
+  class Interpolation < Condition
+    # The SassScript expression in the interpolation.
+    #
+    # @return [Sass::Script::Tree::Node]
+    attr_accessor :value
+
+    # The value of the expression after it's been resolved.
+    # Only set once \{Tree::Visitors::Perform} has been run.
+    #
+    # @return [String]
+    attr_accessor :resolved_value
+
+    def initialize(value)
+      @value = value
+    end
+
+    def perform(env)
+      @resolved_value = value.perform(env).to_s(:quote => :none)
+    end
+
+    def to_css
+      @resolved_value
+    end
+
+    def to_src(options)
+      @value.to_sass(options)
+    end
+
+    def deep_copy
+      copy = dup
+      copy.value = @value.deep_copy
+      copy
+    end
+
+    def options=(options)
+      @value.options = options
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/at_root_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/at_root_node.rb
new file mode 100644
index 0000000..e44d7aa
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/at_root_node.rb
@@ -0,0 +1,83 @@
+module Sass
+  module Tree
+    # A dynamic node representing an ` at-root` directive.
+    #
+    # An ` at-root` directive with a selector is converted to an \{AtRootNode}
+    # containing a \{RuleNode} at parse time.
+    #
+    # @see Sass::Tree
+    class AtRootNode < Node
+      # The query for this node (e.g. `(without: media)`),
+      # interspersed with {Sass::Script::Tree::Node}s representing
+      # `#{}`-interpolation. Any adjacent strings will be merged
+      # together.
+      #
+      # This will be nil if the directive didn't have a query. In this
+      # case, {#resolved\_type} will automatically be set to
+      # `:without` and {#resolved\_rule} will automatically be set to `["rule"]`.
+      #
+      # @return [Array<String, Sass::Script::Tree::Node>]
+      attr_accessor :query
+
+      # The resolved type of this directive. `:with` or `:without`.
+      #
+      # @return [Symbol]
+      attr_accessor :resolved_type
+
+      # The resolved value of this directive -- a list of directives
+      # to either include or exclude.
+      #
+      # @return [Array<String>]
+      attr_accessor :resolved_value
+
+      # The number of additional tabs that the contents of this node
+      # should be indented.
+      #
+      # @return [Number]
+      attr_accessor :tabs
+
+      # Whether the last child of this node should be considered the
+      # end of a group.
+      #
+      # @return [Boolean]
+      attr_accessor :group_end
+
+      def initialize(query = nil)
+        super()
+        @query = Sass::Util.strip_string_array(Sass::Util.merge_adjacent_strings(query)) if query
+        @tabs = 0
+      end
+
+      # Returns whether or not the given directive is excluded by this
+      # node. `directive` may be "rule", which indicates whether
+      # normal CSS rules should be excluded.
+      #
+      # @param directive [String]
+      # @return [Boolean]
+      def exclude?(directive)
+        if resolved_type == :with
+          return false if resolved_value.include?('all')
+          !resolved_value.include?(directive)
+        else # resolved_type == :without
+          return true if resolved_value.include?('all')
+          resolved_value.include?(directive)
+        end
+      end
+
+      # Returns whether the given node is excluded by this node.
+      #
+      # @param node [Sass::Tree::Node]
+      # @return [Boolean]
+      def exclude_node?(node)
+        return exclude?(node.name.gsub(/^@/, '')) if node.is_a?(Sass::Tree::DirectiveNode)
+        return exclude?('keyframes') if node.is_a?(Sass::Tree::KeyframeRuleNode)
+        exclude?('rule') && node.is_a?(Sass::Tree::RuleNode)
+      end
+
+      # @see Node#bubbles?
+      def bubbles?
+        true
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/charset_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/charset_node.rb
new file mode 100644
index 0000000..5e0eeba
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/charset_node.rb
@@ -0,0 +1,22 @@
+module Sass::Tree
+  # A static node representing an unprocessed Sass ` charset` directive.
+  #
+  # @see Sass::Tree
+  class CharsetNode < Node
+    # The name of the charset.
+    #
+    # @return [String]
+    attr_accessor :name
+
+    # @param name [String] see \{#name}
+    def initialize(name)
+      @name = name
+      super()
+    end
+
+    # @see Node#invisible?
+    def invisible?
+      !Sass::Util.ruby1_8?
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/comment_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/comment_node.rb
new file mode 100644
index 0000000..8b7cdf0
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/comment_node.rb
@@ -0,0 +1,82 @@
+require 'sass/tree/node'
+
+module Sass::Tree
+  # A static node representing a Sass comment (silent or loud).
+  #
+  # @see Sass::Tree
+  class CommentNode < Node
+    # The text of the comment, not including `/*` and `*/`.
+    # Interspersed with {Sass::Script::Tree::Node}s representing `#{}`-interpolation
+    # if this is a loud comment.
+    #
+    # @return [Array<String, Sass::Script::Tree::Node>]
+    attr_accessor :value
+
+    # The text of the comment
+    # after any interpolated SassScript has been resolved.
+    # Only set once \{Tree::Visitors::Perform} has been run.
+    #
+    # @return [String]
+    attr_accessor :resolved_value
+
+    # The type of the comment. `:silent` means it's never output to CSS,
+    # `:normal` means it's output in every compile mode except `:compressed`,
+    # and `:loud` means it's output even in `:compressed`.
+    #
+    # @return [Symbol]
+    attr_accessor :type
+
+    # @param value [Array<String, Sass::Script::Tree::Node>] See \{#value}
+    # @param type [Symbol] See \{#type}
+    def initialize(value, type)
+      @value = Sass::Util.with_extracted_values(value) {|str| normalize_indentation str}
+      @type = type
+      super()
+    end
+
+    # Compares the contents of two comments.
+    #
+    # @param other [Object] The object to compare with
+    # @return [Boolean] Whether or not this node and the other object
+    #   are the same
+    def ==(other)
+      self.class == other.class && value == other.value && type == other.type
+    end
+
+    # Returns `true` if this is a silent comment
+    # or the current style doesn't render comments.
+    #
+    # Comments starting with ! are never invisible (and the ! is removed from the output.)
+    #
+    # @return [Boolean]
+    def invisible?
+      case @type
+      when :loud; false
+      when :silent; true
+      else; style == :compressed
+      end
+    end
+
+    # Returns the number of lines in the comment.
+    #
+    # @return [Fixnum]
+    def lines
+      @value.inject(0) do |s, e|
+        next s + e.count("\n") if e.is_a?(String)
+        next s
+      end
+    end
+
+    private
+
+    def normalize_indentation(str)
+      ind = str.split("\n").inject(str[/^[ \t]*/].split("")) do |pre, line|
+        line[/^[ \t]*/].split("").zip(pre).inject([]) do |arr, (a, b)|
+          break arr if a != b
+          arr << a
+        end
+      end.join
+      str.gsub(/^#{ind}/, '')
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.2.12/lib/sass/tree/content_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/content_node.rb
similarity index 100%
rename from backends/css/gems/sass-3.2.12/lib/sass/tree/content_node.rb
rename to backends/css/gems/sass-3.4.9/lib/sass/tree/content_node.rb
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/css_import_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/css_import_node.rb
new file mode 100644
index 0000000..125ca13
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/css_import_node.rb
@@ -0,0 +1,60 @@
+module Sass::Tree
+  # A node representing an ` import` rule that's importing plain CSS.
+  #
+  # @see Sass::Tree
+  class CssImportNode < DirectiveNode
+    # The URI being imported, either as a plain string or an interpolated
+    # script string.
+    #
+    # @return [String, Sass::Script::Tree::Node]
+    attr_accessor :uri
+
+    # The text of the URI being imported after any interpolated SassScript has
+    # been resolved. Only set once {Tree::Visitors::Perform} has been run.
+    #
+    # @return [String]
+    attr_accessor :resolved_uri
+
+    # The media query for this rule, interspersed with
+    # {Sass::Script::Tree::Node}s representing `#{}`-interpolation. Any adjacent
+    # strings will be merged together.
+    #
+    # @return [Array<String, Sass::Script::Tree::Node>]
+    attr_accessor :query
+
+    # The media query for this rule, without any unresolved interpolation.
+    # It's only set once {Tree::Visitors::Perform} has been run.
+    #
+    # @return [Sass::Media::QueryList]
+    attr_accessor :resolved_query
+
+    # @param uri [String, Sass::Script::Tree::Node] See \{#uri}
+    # @param query [Array<String, Sass::Script::Tree::Node>] See \{#query}
+    def initialize(uri, query = [])
+      @uri = uri
+      @query = query
+      super('')
+    end
+
+    # @param uri [String] See \{#resolved_uri}
+    # @return [CssImportNode]
+    def self.resolved(uri)
+      node = new(uri)
+      node.resolved_uri = uri
+      node
+    end
+
+    # @see DirectiveNode#value
+    def value; raise NotImplementedError; end
+
+    # @see DirectiveNode#resolved_value
+    def resolved_value
+      @resolved_value ||=
+        begin
+          str = "@import #{resolved_uri}"
+          str << " #{resolved_query.to_css}" if resolved_query
+          str
+        end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/debug_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/debug_node.rb
new file mode 100644
index 0000000..5cc2842
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/debug_node.rb
@@ -0,0 +1,18 @@
+module Sass
+  module Tree
+    # A dynamic node representing a Sass ` debug` statement.
+    #
+    # @see Sass::Tree
+    class DebugNode < Node
+      # The expression to print.
+      # @return [Script::Tree::Node]
+      attr_accessor :expr
+
+      # @param expr [Script::Tree::Node] The expression to print
+      def initialize(expr)
+        @expr = expr
+        super()
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/directive_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/directive_node.rb
new file mode 100644
index 0000000..315bb70
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/directive_node.rb
@@ -0,0 +1,59 @@
+module Sass::Tree
+  # A static node representing an unprocessed Sass ` `-directive 
+  # Directives known to Sass, like ` for` and ` debug`,
+  # are handled by their own nodes;
+  # only CSS directives like ` media` and ` font-face` become {DirectiveNode}s.
+  #
+  # ` import` and ` charset` are special cases;
+  # they become {ImportNode}s and {CharsetNode}s, respectively.
+  #
+  # @see Sass::Tree
+  class DirectiveNode < Node
+    # The text of the directive, ` ` and all, with interpolation included.
+    #
+    # @return [Array<String, Sass::Script::Tree::Node>]
+    attr_accessor :value
+
+    # The text of the directive after any interpolated SassScript has been resolved.
+    # Only set once \{Tree::Visitors::Perform} has been run.
+    #
+    # @return [String]
+    attr_accessor :resolved_value
+
+    # @see RuleNode#tabs
+    attr_accessor :tabs
+
+    # @see RuleNode#group_end
+    attr_accessor :group_end
+
+    # @param value [Array<String, Sass::Script::Tree::Node>] See \{#value}
+    def initialize(value)
+      @value = value
+      @tabs = 0
+      super()
+    end
+
+    # @param value [String] See \{#resolved_value}
+    # @return [DirectiveNode]
+    def self.resolved(value)
+      node = new([value])
+      node.resolved_value = value
+      node
+    end
+
+    # @return [String] The name of the directive, including ` ` 
+    def name
+      @name ||= value.first.gsub(/ .*$/, '')
+    end
+
+    # Strips out any vendor prefixes and downcases the directive name.
+    # @return [String] The normalized name of the directive.
+    def normalized_name
+      @normalized_name ||= name.gsub(/^(@)(?:-[a-zA-Z0-9]+-)?/, '\1').downcase
+    end
+
+    def bubbles?
+      has_children
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/each_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/each_node.rb
new file mode 100644
index 0000000..586cfa7
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/each_node.rb
@@ -0,0 +1,24 @@
+require 'sass/tree/node'
+
+module Sass::Tree
+  # A dynamic node representing a Sass ` each` loop.
+  #
+  # @see Sass::Tree
+  class EachNode < Node
+    # The names of the loop variables.
+    # @return [Array<String>]
+    attr_reader :vars
+
+    # The parse tree for the list.
+    # @return [Script::Tree::Node]
+    attr_accessor :list
+
+    # @param vars [Array<String>] The names of the loop variables
+    # @param list [Script::Tree::Node] The parse tree for the list
+    def initialize(vars, list)
+      @vars = vars
+      @list = list
+      super()
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/error_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/error_node.rb
new file mode 100644
index 0000000..203fd62
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/error_node.rb
@@ -0,0 +1,18 @@
+module Sass
+  module Tree
+    # A dynamic node representing a Sass ` error` statement.
+    #
+    # @see Sass::Tree
+    class ErrorNode < Node
+      # The expression to print.
+      # @return [Script::Tree::Node]
+      attr_accessor :expr
+
+      # @param expr [Script::Tree::Node] The expression to print
+      def initialize(expr)
+        @expr = expr
+        super()
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/extend_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/extend_node.rb
new file mode 100644
index 0000000..817c20c
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/extend_node.rb
@@ -0,0 +1,43 @@
+require 'sass/tree/node'
+
+module Sass::Tree
+  # A static node representing an ` extend` directive.
+  #
+  # @see Sass::Tree
+  class ExtendNode < Node
+    # The parsed selector after interpolation has been resolved.
+    # Only set once {Tree::Visitors::Perform} has been run.
+    #
+    # @return [Selector::CommaSequence]
+    attr_accessor :resolved_selector
+
+    # The CSS selector to extend, interspersed with {Sass::Script::Tree::Node}s
+    # representing `#{}`-interpolation.
+    #
+    # @return [Array<String, Sass::Script::Tree::Node>]
+    attr_accessor :selector
+
+    # The extended selector source range.
+    #
+    # @return [Sass::Source::Range]
+    attr_accessor :selector_source_range
+
+    # Whether the ` extend` is allowed to match no selectors or not.
+    #
+    # @return [Boolean]
+    def optional?; @optional; end
+
+    # @param selector [Array<String, Sass::Script::Tree::Node>]
+    #   The CSS selector to extend,
+    #   interspersed with {Sass::Script::Tree::Node}s
+    #   representing `#{}`-interpolation.
+    # @param optional [Boolean] See \{ExtendNode#optional?}
+    # @param selector_source_range [Sass::Source::Range] The extended selector source range.
+    def initialize(selector, optional, selector_source_range)
+      @selector = selector
+      @optional = optional
+      @selector_source_range = selector_source_range
+      super()
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/for_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/for_node.rb
new file mode 100644
index 0000000..da3f655
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/for_node.rb
@@ -0,0 +1,36 @@
+require 'sass/tree/node'
+
+module Sass::Tree
+  # A dynamic node representing a Sass ` for` loop.
+  #
+  # @see Sass::Tree
+  class ForNode < Node
+    # The name of the loop variable.
+    # @return [String]
+    attr_reader :var
+
+    # The parse tree for the initial expression.
+    # @return [Script::Tree::Node]
+    attr_accessor :from
+
+    # The parse tree for the final expression.
+    # @return [Script::Tree::Node]
+    attr_accessor :to
+
+    # Whether to include `to` in the loop or stop just before.
+    # @return [Boolean]
+    attr_reader :exclusive
+
+    # @param var [String] See \{#var}
+    # @param from [Script::Tree::Node] See \{#from}
+    # @param to [Script::Tree::Node] See \{#to}
+    # @param exclusive [Boolean] See \{#exclusive}
+    def initialize(var, from, to, exclusive)
+      @var = var
+      @from = from
+      @to = to
+      @exclusive = exclusive
+      super()
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/function_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/function_node.rb
new file mode 100644
index 0000000..2ce47b7
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/function_node.rb
@@ -0,0 +1,39 @@
+module Sass
+  module Tree
+    # A dynamic node representing a function definition.
+    #
+    # @see Sass::Tree
+    class FunctionNode < Node
+      # The name of the function.
+      # @return [String]
+      attr_reader :name
+
+      # The arguments to the function. Each element is a tuple
+      # containing the variable for argument and the parse tree for
+      # the default value of the argument
+      #
+      # @return [Array<Script::Tree::Node>]
+      attr_accessor :args
+
+      # The splat argument for this function, if one exists.
+      #
+      # @return [Script::Tree::Node?]
+      attr_accessor :splat
+
+      # @param name [String] The function name
+      # @param args [Array<(Script::Tree::Node, Script::Tree::Node)>]
+      #   The arguments for the function.
+      # @param splat [Script::Tree::Node] See \{#splat}
+      def initialize(name, args, splat)
+        @name = name
+        @args = args
+        @splat = splat
+        super()
+
+        if %w[and or not].include?(name)
+          raise Sass::SyntaxError.new("Invalid function name \"#{name}\".")
+        end
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/if_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/if_node.rb
new file mode 100644
index 0000000..ebfec7c
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/if_node.rb
@@ -0,0 +1,52 @@
+require 'sass/tree/node'
+
+module Sass::Tree
+  # A dynamic node representing a Sass ` if` statement.
+  #
+  # {IfNode}s are a little odd, in that they also represent ` else` and ` else if`s.
+  # This is done as a linked list:
+  # each {IfNode} has a link (\{#else}) to the next {IfNode}.
+  #
+  # @see Sass::Tree
+  class IfNode < Node
+    # The conditional expression.
+    # If this is nil, this is an ` else` node, not an ` else if`.
+    #
+    # @return [Script::Expr]
+    attr_accessor :expr
+
+    # The next {IfNode} in the if-else list, or `nil`.
+    #
+    # @return [IfNode]
+    attr_accessor :else
+
+    # @param expr [Script::Expr] See \{#expr}
+    def initialize(expr)
+      @expr = expr
+      @last_else = self
+      super()
+    end
+
+    # Append an ` else` node to the end of the list.
+    #
+    # @param node [IfNode] The ` else` node to append
+    def add_else(node)
+      @last_else.else = node
+      @last_else = node
+    end
+
+    def _dump(f)
+      Marshal.dump([expr, self.else, children])
+    end
+
+    def self._load(data)
+      expr, else_, children = Marshal.load(data)
+      node = IfNode.new(expr)
+      node.else = else_
+      node.children = children
+      node.instance_variable_set('@last_else',
+        node.else ? node.else.instance_variable_get('@last_else') : node)
+      node
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/import_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/import_node.rb
new file mode 100644
index 0000000..01dc0a9
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/import_node.rb
@@ -0,0 +1,74 @@
+module Sass
+  module Tree
+    # A static node that wraps the {Sass::Tree} for an ` import`ed file.
+    # It doesn't have a functional purpose other than to add the ` import`ed file
+    # to the backtrace if an error occurs.
+    class ImportNode < RootNode
+      # The name of the imported file as it appears in the Sass document.
+      #
+      # @return [String]
+      attr_reader :imported_filename
+
+      # Sets the imported file.
+      attr_writer :imported_file
+
+      # @param imported_filename [String] The name of the imported file
+      def initialize(imported_filename)
+        @imported_filename = imported_filename
+        super(nil)
+      end
+
+      def invisible?; to_s.empty?; end
+
+      # Returns the imported file.
+      #
+      # @return [Sass::Engine]
+      # @raise [Sass::SyntaxError] If no file could be found to import.
+      def imported_file
+        @imported_file ||= import
+      end
+
+      # Returns whether or not this import should emit a CSS @import declaration
+      #
+      # @return [Boolean] Whether or not this is a simple CSS @import declaration.
+      def css_import?
+        if @imported_filename =~ /\.css$/
+          @imported_filename
+        elsif imported_file.is_a?(String) && imported_file =~ /\.css$/
+          imported_file
+        end
+      end
+
+      private
+
+      def import
+        paths = @options[:load_paths]
+
+        if @options[:importer]
+          f = @options[:importer].find_relative(
+            @imported_filename, @options[:filename], options_for_importer)
+          return f if f
+        end
+
+        paths.each do |p|
+          f = p.find(@imported_filename, options_for_importer)
+          return f if f
+        end
+
+        message = "File to import not found or unreadable: #{ imported_filename} \n"
+        if paths.size == 1
+          message << "Load path: #{paths.first}"
+        else
+          message << "Load paths:\n  " << paths.join("\n  ")
+        end
+        raise SyntaxError.new(message)
+      rescue SyntaxError => e
+        raise SyntaxError.new(e.message, :line => line, :filename => @filename)
+      end
+
+      def options_for_importer
+        @options.merge(:_from_import_node => true)
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/keyframe_rule_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/keyframe_rule_node.rb
new file mode 100644
index 0000000..9f75f94
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/keyframe_rule_node.rb
@@ -0,0 +1,15 @@
+module Sass::Tree
+  class KeyframeRuleNode < Node
+    # The text of the directive after any interpolated SassScript has been resolved.
+    # Since this is only a static node, this is the only value property.
+    #
+    # @return [String]
+    attr_accessor :resolved_value
+
+    # @param resolved_value [String] See \{#resolved_value}
+    def initialize(resolved_value)
+      @resolved_value = resolved_value
+      super()
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/media_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/media_node.rb
new file mode 100644
index 0000000..3178de0
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/media_node.rb
@@ -0,0 +1,48 @@
+module Sass::Tree
+  # A static node representing a ` media` rule.
+  # ` media` rules behave differently from other directives
+  # in that when they're nested within rules,
+  # they bubble up to top-level.
+  #
+  # @see Sass::Tree
+  class MediaNode < DirectiveNode
+    # TODO: parse and cache the query immediately if it has no dynamic elements
+
+    # The media query for this rule, interspersed with {Sass::Script::Tree::Node}s
+    # representing `#{}`-interpolation. Any adjacent strings will be merged
+    # together.
+    #
+    # @return [Array<String, Sass::Script::Tree::Node>]
+    attr_accessor :query
+
+    # The media query for this rule, without any unresolved interpolation. It's
+    # only set once {Tree::Visitors::Perform} has been run.
+    #
+    # @return [Sass::Media::QueryList]
+    attr_accessor :resolved_query
+
+    # @param query [Array<String, Sass::Script::Tree::Node>] See \{#query}
+    def initialize(query)
+      @query = query
+      super('')
+    end
+
+    # @see DirectiveNode#value
+    def value; raise NotImplementedError; end
+
+    # @see DirectiveNode#name
+    def name; '@media'; end
+
+    # @see DirectiveNode#resolved_value
+    def resolved_value
+      @resolved_value ||= "@media #{resolved_query.to_css}"
+    end
+
+    # True when the directive has no visible children.
+    #
+    # @return [Boolean]
+    def invisible?
+      children.all? {|c| c.invisible?}
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/mixin_def_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/mixin_def_node.rb
new file mode 100644
index 0000000..9ed8bfb
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/mixin_def_node.rb
@@ -0,0 +1,38 @@
+module Sass
+  module Tree
+    # A dynamic node representing a mixin definition.
+    #
+    # @see Sass::Tree
+    class MixinDefNode < Node
+      # The mixin name.
+      # @return [String]
+      attr_reader :name
+
+      # The arguments for the mixin.
+      # Each element is a tuple containing the variable for argument
+      # and the parse tree for the default value of the argument.
+      #
+      # @return [Array<(Script::Tree::Node, Script::Tree::Node)>]
+      attr_accessor :args
+
+      # The splat argument for this mixin, if one exists.
+      #
+      # @return [Script::Tree::Node?]
+      attr_accessor :splat
+
+      # Whether the mixin uses ` content`  Set during the nesting check phase.
+      # @return [Boolean]
+      attr_accessor :has_content
+
+      # @param name [String] The mixin name
+      # @param args [Array<(Script::Tree::Node, Script::Tree::Node)>] See \{#args}
+      # @param splat [Script::Tree::Node] See \{#splat}
+      def initialize(name, args, splat)
+        @name = name
+        @args = args
+        @splat = splat
+        super()
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/mixin_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/mixin_node.rb
new file mode 100644
index 0000000..48592c1
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/mixin_node.rb
@@ -0,0 +1,52 @@
+require 'sass/tree/node'
+
+module Sass::Tree
+  # A static node representing a mixin include.
+  # When in a static tree, the sole purpose is to wrap exceptions
+  # to add the mixin to the backtrace.
+  #
+  # @see Sass::Tree
+  class MixinNode < Node
+    # The name of the mixin.
+    # @return [String]
+    attr_reader :name
+
+    # The arguments to the mixin.
+    # @return [Array<Script::Tree::Node>]
+    attr_accessor :args
+
+    # A hash from keyword argument names to values.
+    # @return [Sass::Util::NormalizedMap<Script::Tree::Node>]
+    attr_accessor :keywords
+
+    # The first splat argument for this mixin, if one exists.
+    #
+    # This could be a list of positional arguments, a map of keyword
+    # arguments, or an arglist containing both.
+    #
+    # @return [Node?]
+    attr_accessor :splat
+
+    # The second splat argument for this mixin, if one exists.
+    #
+    # If this exists, it's always a map of keyword arguments, and
+    # \{#splat} is always either a list or an arglist.
+    #
+    # @return [Node?]
+    attr_accessor :kwarg_splat
+
+    # @param name [String] The name of the mixin
+    # @param args [Array<Script::Tree::Node>] See \{#args}
+    # @param splat [Script::Tree::Node] See \{#splat}
+    # @param kwarg_splat [Script::Tree::Node] See \{#kwarg_splat}
+    # @param keywords [Sass::Util::NormalizedMap<Script::Tree::Node>] See \{#keywords}
+    def initialize(name, args, keywords, splat, kwarg_splat)
+      @name = name
+      @args = args
+      @keywords = keywords
+      @splat = splat
+      @kwarg_splat = kwarg_splat
+      super()
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/node.rb
new file mode 100644
index 0000000..3ebb5e8
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/node.rb
@@ -0,0 +1,238 @@
+module Sass
+  # A namespace for nodes in the Sass parse tree.
+  #
+  # The Sass parse tree has three states: dynamic, static Sass, and static CSS.
+  #
+  # When it's first parsed, a Sass document is in the dynamic state.
+  # It has nodes for mixin definitions and ` for` loops and so forth,
+  # in addition to nodes for CSS rules and properties.
+  # Nodes that only appear in this state are called **dynamic nodes**.
+  #
+  # {Tree::Visitors::Perform} creates a static Sass tree, which is
+  # different. It still has nodes for CSS rules and properties but it
+  # doesn't have any dynamic-generation-related nodes. The nodes in
+  # this state are in a similar structure to the Sass document: rules
+  # and properties are nested beneath one another, although the
+  # {Tree::RuleNode} selectors are already in their final state. Nodes
+  # that can be in this state or in the dynamic state are called
+  # **static nodes**; nodes that can only be in this state are called
+  # **solely static nodes**.
+  #
+  # {Tree::Visitors::Cssize} is then used to create a static CSS tree.
+  # This is like a static Sass tree,
+  # but the structure exactly mirrors that of the generated CSS.
+  # Rules and properties can't be nested beneath one another in this state.
+  #
+  # Finally, {Tree::Visitors::ToCss} can be called on a static CSS tree
+  # to get the actual CSS code as a string.
+  module Tree
+    # The abstract superclass of all parse-tree nodes.
+    class Node
+      include Enumerable
+
+      def self.inherited(base)
+        node_name = base.name.gsub(/.*::(.*?)Node$/, '\\1').downcase
+        base.instance_eval <<-METHODS
+          # @return [Symbol] The name that is used for this node when visiting.
+          def node_name
+            :#{node_name}
+          end
+
+          # @return [Symbol] The method that is used on the visitor to visit nodes of this type.
+          def visit_method
+            :visit_#{node_name}
+          end
+
+          # @return [Symbol] The method name that determines if the parent is invalid.
+          def invalid_child_method_name
+            :"invalid_#{node_name}_child?"
+          end
+
+          # @return [Symbol] The method name that determines if the node is an invalid parent.
+          def invalid_parent_method_name
+            :"invalid_#{node_name}_parent?"
+          end
+        METHODS
+      end
+
+      # The child nodes of this node.
+      #
+      # @return [Array<Tree::Node>]
+      attr_reader :children
+
+      # Whether or not this node has child nodes.
+      # This may be true even when \{#children} is empty,
+      # in which case this node has an empty block (e.g. `{}`).
+      #
+      # @return [Boolean]
+      attr_accessor :has_children
+
+      # The line of the document on which this node appeared.
+      #
+      # @return [Fixnum]
+      attr_accessor :line
+
+      # The source range in the document on which this node appeared.
+      #
+      # @return [Sass::Source::Range]
+      attr_accessor :source_range
+
+      # The name of the document on which this node appeared.
+      #
+      # @return [String]
+      attr_writer :filename
+
+      # The options hash for the node.
+      # See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
+      #
+      # @return [{Symbol => Object}]
+      attr_reader :options
+
+      def initialize
+        @children = []
+      end
+
+      # Sets the options hash for the node and all its children.
+      #
+      # @param options [{Symbol => Object}] The options
+      # @see #options
+      def options=(options)
+        Sass::Tree::Visitors::SetOptions.visit(self, options)
+      end
+
+      # @private
+      def children=(children)
+        self.has_children ||= !children.empty?
+        @children = children
+      end
+
+      # The name of the document on which this node appeared.
+      #
+      # @return [String]
+      def filename
+        @filename || (@options && @options[:filename])
+      end
+
+      # Appends a child to the node.
+      #
+      # @param child [Tree::Node, Array<Tree::Node>] The child node or nodes
+      # @raise [Sass::SyntaxError] if `child` is invalid
+      def <<(child)
+        return if child.nil?
+        if child.is_a?(Array)
+          child.each {|c| self << c}
+        else
+          self.has_children = true
+          @children << child
+        end
+      end
+
+      # Compares this node and another object (only other {Tree::Node}s will be equal).
+      # This does a structural comparison;
+      # if the contents of the nodes and all the child nodes are equivalent,
+      # then the nodes are as well.
+      #
+      # Only static nodes need to override this.
+      #
+      # @param other [Object] The object to compare with
+      # @return [Boolean] Whether or not this node and the other object
+      #   are the same
+      # @see Sass::Tree
+      def ==(other)
+        self.class == other.class && other.children == children
+      end
+
+      # True if \{#to\_s} will return `nil`;
+      # that is, if the node shouldn't be rendered.
+      # Should only be called in a static tree.
+      #
+      # @return [Boolean]
+      def invisible?; false; end
+
+      # The output style. See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
+      #
+      # @return [Symbol]
+      def style
+        @options[:style]
+      end
+
+      # Computes the CSS corresponding to this static CSS tree.
+      #
+      # @return [String] The resulting CSS
+      # @see Sass::Tree
+      def css
+        Sass::Tree::Visitors::ToCss.new.visit(self)
+      end
+
+      # Computes the CSS corresponding to this static CSS tree, along with
+      # the respective source map.
+      #
+      # @return [(String, Sass::Source::Map)] The resulting CSS and the source map
+      # @see Sass::Tree
+      def css_with_sourcemap
+        visitor = Sass::Tree::Visitors::ToCss.new(:build_source_mapping)
+        result = visitor.visit(self)
+        return result, visitor.source_mapping
+      end
+
+      # Returns a representation of the node for debugging purposes.
+      #
+      # @return [String]
+      def inspect
+        return self.class.to_s unless has_children
+        "(#{self.class} #{children.map {|c| c.inspect}.join(' ')})"
+      end
+
+      # Iterates through each node in the tree rooted at this node
+      # in a pre-order walk.
+      #
+      # @yield node
+      # @yieldparam node [Node] a node in the tree
+      def each
+        yield self
+        children.each {|c| c.each {|n| yield n}}
+      end
+
+      # Converts a node to Sass code that will generate it.
+      #
+      # @param options [{Symbol => Object}] An options hash (see {Sass::CSS#initialize})
+      # @return [String] The Sass code corresponding to the node
+      def to_sass(options = {})
+        Sass::Tree::Visitors::Convert.visit(self, options, :sass)
+      end
+
+      # Converts a node to SCSS code that will generate it.
+      #
+      # @param options [{Symbol => Object}] An options hash (see {Sass::CSS#initialize})
+      # @return [String] The Sass code corresponding to the node
+      def to_scss(options = {})
+        Sass::Tree::Visitors::Convert.visit(self, options, :scss)
+      end
+
+      # Return a deep clone of this node.
+      # The child nodes are cloned, but options are not.
+      #
+      # @return [Node]
+      def deep_copy
+        Sass::Tree::Visitors::DeepCopy.visit(self)
+      end
+
+      # Whether or not this node bubbles up through RuleNodes.
+      #
+      # @return [Boolean]
+      def bubbles?
+        false
+      end
+
+      protected
+
+      # @see Sass::Shared.balance
+      # @raise [Sass::SyntaxError] if the brackets aren't balanced
+      def balance(*args)
+        res = Sass::Shared.balance(*args)
+        return res if res
+        raise Sass::SyntaxError.new("Unbalanced brackets.", :line => line)
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/prop_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/prop_node.rb
new file mode 100644
index 0000000..f157e41
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/prop_node.rb
@@ -0,0 +1,171 @@
+module Sass::Tree
+  # A static node representing a CSS property.
+  #
+  # @see Sass::Tree
+  class PropNode < Node
+    # The name of the property,
+    # interspersed with {Sass::Script::Tree::Node}s
+    # representing `#{}`-interpolation.
+    # Any adjacent strings will be merged together.
+    #
+    # @return [Array<String, Sass::Script::Tree::Node>]
+    attr_accessor :name
+
+    # The name of the property
+    # after any interpolated SassScript has been resolved.
+    # Only set once \{Tree::Visitors::Perform} has been run.
+    #
+    # @return [String]
+    attr_accessor :resolved_name
+
+    # The value of the property.
+    #
+    # @return [Sass::Script::Tree::Node]
+    attr_accessor :value
+
+    # The value of the property
+    # after any interpolated SassScript has been resolved.
+    # Only set once \{Tree::Visitors::Perform} has been run.
+    #
+    # @return [String]
+    attr_accessor :resolved_value
+
+    # How deep this property is indented
+    # relative to a normal property.
+    # This is only greater than 0 in the case that:
+    #
+    # * This node is in a CSS tree
+    # * The style is :nested
+    # * This is a child property of another property
+    # * The parent property has a value, and thus will be rendered
+    #
+    # @return [Fixnum]
+    attr_accessor :tabs
+
+    # The source range in which the property name appears.
+    #
+    # @return [Sass::Source::Range]
+    attr_accessor :name_source_range
+
+    # The source range in which the property value appears.
+    #
+    # @return [Sass::Source::Range]
+    attr_accessor :value_source_range
+
+    # @param name [Array<String, Sass::Script::Tree::Node>] See \{#name}
+    # @param value [Sass::Script::Tree::Node] See \{#value}
+    # @param prop_syntax [Symbol] `:new` if this property uses `a: b`-style syntax,
+    #   `:old` if it uses `:a b`-style syntax
+    def initialize(name, value, prop_syntax)
+      @name = Sass::Util.strip_string_array(
+        Sass::Util.merge_adjacent_strings(name))
+      @value = value
+      @tabs = 0
+      @prop_syntax = prop_syntax
+      super()
+    end
+
+    # Compares the names and values of two properties.
+    #
+    # @param other [Object] The object to compare with
+    # @return [Boolean] Whether or not this node and the other object
+    #   are the same
+    def ==(other)
+      self.class == other.class && name == other.name && value == other.value && super
+    end
+
+    # Returns a appropriate message indicating how to escape pseudo-class selectors.
+    # This only applies for old-style properties with no value,
+    # so returns the empty string if this is new-style.
+    #
+    # @return [String] The message
+    def pseudo_class_selector_message
+      if @prop_syntax == :new ||
+          !value.is_a?(Sass::Script::Tree::Literal) ||
+          !value.value.is_a?(Sass::Script::Value::String) ||
+          !value.value.value.empty?
+        return ""
+      end
+
+      "\nIf #{declaration.dump} should be a selector, use \"\\#{declaration}\" instead."
+    end
+
+    # Computes the Sass or SCSS code for the variable declaration.
+    # This is like \{#to\_scss} or \{#to\_sass},
+    # except it doesn't print any child properties or a trailing semicolon.
+    #
+    # @param opts [{Symbol => Object}] The options hash for the tree.
+    # @param fmt [Symbol] `:scss` or `:sass`.
+    def declaration(opts = {:old => @prop_syntax == :old}, fmt = :sass)
+      name = self.name.map {|n| n.is_a?(String) ? n : n.to_sass(opts)}.join
+      if name[0] == ?:
+        raise Sass::SyntaxError.new("The \"#{name}: #{self.class.val_to_sass(value, opts)}\"" +
+                                    " hack is not allowed in the Sass indented syntax")
+      end
+
+      old = opts[:old] && fmt == :sass
+      initial = old ? ':' : ''
+      mid = old ? '' : ':'
+      "#{initial}#{name}#{mid} #{self.class.val_to_sass(value, opts)}".rstrip
+    end
+
+    # A property node is invisible if its value is empty.
+    #
+    # @return [Boolean]
+    def invisible?
+      resolved_value.empty?
+    end
+
+    private
+
+    def check!
+      if @options[:property_syntax] && @options[:property_syntax] != @prop_syntax
+        raise Sass::SyntaxError.new(
+          "Illegal property syntax: can't use #{ prop_syntax} syntax when " +
+          ":property_syntax => #{ options[:property_syntax].inspect} is set.")
+      end
+    end
+
+    class << self
+      # @private
+      def val_to_sass(value, opts)
+        val_to_sass_comma(value, opts).to_sass(opts)
+      end
+
+      private
+
+      def val_to_sass_comma(node, opts)
+        return node unless node.is_a?(Sass::Script::Tree::Operation)
+        return val_to_sass_concat(node, opts) unless node.operator == :comma
+
+        Sass::Script::Tree::Operation.new(
+          val_to_sass_concat(node.operand1, opts),
+          val_to_sass_comma(node.operand2, opts),
+          node.operator)
+      end
+
+      def val_to_sass_concat(node, opts)
+        return node unless node.is_a?(Sass::Script::Tree::Operation)
+        return val_to_sass_div(node, opts) unless node.operator == :space
+
+        Sass::Script::Tree::Operation.new(
+          val_to_sass_div(node.operand1, opts),
+          val_to_sass_concat(node.operand2, opts),
+          node.operator)
+      end
+
+      def val_to_sass_div(node, opts)
+        unless node.is_a?(Sass::Script::Tree::Operation) && node.operator == :div &&
+            node.operand1.is_a?(Sass::Script::Tree::Literal) &&
+            node.operand1.value.is_a?(Sass::Script::Value::Number) &&
+            node.operand2.is_a?(Sass::Script::Tree::Literal) &&
+            node.operand2.value.is_a?(Sass::Script::Value::Number) &&
+            (!node.operand1.value.original || !node.operand2.value.original)
+          return node
+        end
+
+        Sass::Script::Value::String.new("(#{node.to_sass(opts)})")
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/return_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/return_node.rb
new file mode 100644
index 0000000..3056406
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/return_node.rb
@@ -0,0 +1,19 @@
+module Sass
+  module Tree
+    # A dynamic node representing returning from a function.
+    #
+    # @see Sass::Tree
+    class ReturnNode < Node
+      # The expression to return.
+      #
+      # @return [Script::Tree::Node]
+      attr_accessor :expr
+
+      # @param expr [Script::Tree::Node] The expression to return
+      def initialize(expr)
+        @expr = expr
+        super()
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/root_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/root_node.rb
new file mode 100644
index 0000000..1f02cbd
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/root_node.rb
@@ -0,0 +1,44 @@
+module Sass
+  module Tree
+    # A static node that is the root node of the Sass document.
+    class RootNode < Node
+      # The Sass template from which this node was created
+      #
+      # @param template [String]
+      attr_reader :template
+
+      # @param template [String] The Sass template from which this node was created
+      def initialize(template)
+        super()
+        @template = template
+      end
+
+      # Runs the dynamic Sass code and computes the CSS for the tree.
+      #
+      # @return [String] The compiled CSS.
+      def render
+        css_tree.css
+      end
+
+      # Runs the dynamic Sass code and computes the CSS for the tree, along with
+      # the sourcemap.
+      #
+      # @return [(String, Sass::Source::Map)] The compiled CSS, as well as
+      #   the source map. @see #render
+      def render_with_sourcemap
+        css_tree.css_with_sourcemap
+      end
+
+      private
+
+      def css_tree
+        Visitors::CheckNesting.visit(self)
+        result = Visitors::Perform.visit(self)
+        Visitors::CheckNesting.visit(result) # Check again to validate mixins
+        result, extends = Visitors::Cssize.visit(result)
+        Visitors::Extend.visit(result, extends)
+        result
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/rule_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/rule_node.rb
new file mode 100644
index 0000000..5e0883b
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/rule_node.rb
@@ -0,0 +1,145 @@
+require 'pathname'
+
+module Sass::Tree
+  # A static node representing a CSS rule.
+  #
+  # @see Sass::Tree
+  class RuleNode < Node
+    # The character used to include the parent selector
+    PARENT = '&'
+
+    # The CSS selector for this rule,
+    # interspersed with {Sass::Script::Tree::Node}s
+    # representing `#{}`-interpolation.
+    # Any adjacent strings will be merged together.
+    #
+    # @return [Array<String, Sass::Script::Tree::Node>]
+    attr_accessor :rule
+
+    # The CSS selector for this rule, without any unresolved
+    # interpolation but with parent references still intact. It's only
+    # guaranteed to be set once {Tree::Visitors::Perform} has been
+    # run, but it may be set before then for optimization reasons.
+    #
+    # @return [Selector::CommaSequence]
+    attr_accessor :parsed_rules
+
+    # The CSS selector for this rule, without any unresolved
+    # interpolation or parent references. It's only set once
+    # {Tree::Visitors::Perform} has been run.
+    #
+    # @return [Selector::CommaSequence]
+    attr_accessor :resolved_rules
+
+    # How deep this rule is indented
+    # relative to a base-level rule.
+    # This is only greater than 0 in the case that:
+    #
+    # * This node is in a CSS tree
+    # * The style is :nested
+    # * This is a child rule of another rule
+    # * The parent rule has properties, and thus will be rendered
+    #
+    # @return [Fixnum]
+    attr_accessor :tabs
+
+    # The entire selector source range for this rule.
+    # @return [Sass::Source::Range]
+    attr_accessor :selector_source_range
+
+    # Whether or not this rule is the last rule in a nested group.
+    # This is only set in a CSS tree.
+    #
+    # @return [Boolean]
+    attr_accessor :group_end
+
+    # The stack trace.
+    # This is only readable in a CSS tree as it is written during the perform step
+    # and only when the :trace_selectors option is set.
+    #
+    # @return [String]
+    attr_accessor :stack_trace
+
+    # @param rule [Array<String, Sass::Script::Tree::Node>, Sass::Selector::CommaSequence]
+    #   The CSS rule, either unparsed or parsed.
+    # @param selector_source_range [Sass::Source::Range]
+    def initialize(rule, selector_source_range = nil)
+      if rule.is_a?(Sass::Selector::CommaSequence)
+        @rule = [rule.to_s]
+        @parsed_rules = rule
+      else
+        merged = Sass::Util.merge_adjacent_strings(rule)
+        @rule = Sass::Util.strip_string_array(merged)
+        try_to_parse_non_interpolated_rules
+      end
+      @selector_source_range = selector_source_range
+      @tabs = 0
+      super()
+    end
+
+    # If we've precached the parsed selector, set the line on it, too.
+    def line=(line)
+      @parsed_rules.line = line if @parsed_rules
+      super
+    end
+
+    # If we've precached the parsed selector, set the filename on it, too.
+    def filename=(filename)
+      @parsed_rules.filename = filename if @parsed_rules
+      super
+    end
+
+    # Compares the contents of two rules.
+    #
+    # @param other [Object] The object to compare with
+    # @return [Boolean] Whether or not this node and the other object
+    #   are the same
+    def ==(other)
+      self.class == other.class && rule == other.rule && super
+    end
+
+    # Adds another {RuleNode}'s rules to this one's.
+    #
+    # @param node [RuleNode] The other node
+    def add_rules(node)
+      @rule = Sass::Util.strip_string_array(
+        Sass::Util.merge_adjacent_strings(@rule + ["\n"] + node.rule))
+      try_to_parse_non_interpolated_rules
+    end
+
+    # @return [Boolean] Whether or not this rule is continued on the next line
+    def continued?
+      last = @rule.last
+      last.is_a?(String) && last[-1] == ?,
+    end
+
+    # A hash that will be associated with this rule in the CSS document
+    # if the {file:SASS_REFERENCE.md#debug_info-option `:debug_info` option} is enabled.
+    # This data is used by e.g. [the FireSass Firebug
+    # extension](https://addons.mozilla.org/en-US/firefox/addon/103988).
+    #
+    # @return [{#to_s => #to_s}]
+    def debug_info
+      {:filename => filename && ("file://" + Sass::Util.escape_uri(File.expand_path(filename))),
+       :line => line}
+    end
+
+    # A rule node is invisible if it has only placeholder selectors.
+    def invisible?
+      resolved_rules.members.all? {|seq| seq.has_placeholder?}
+    end
+
+    private
+
+    def try_to_parse_non_interpolated_rules
+      if @rule.all? {|t| t.kind_of?(String)}
+        # We don't use real filename/line info because we don't have it yet.
+        # When we get it, we'll set it on the parsed rules if possible.
+        parser = Sass::SCSS::StaticParser.new(@rule.join.strip, nil, nil, 1)
+        # rubocop:disable RescueModifier
+        @parsed_rules = parser.parse_selector rescue nil
+        # rubocop:enable RescueModifier
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/supports_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/supports_node.rb
new file mode 100644
index 0000000..1a2f04b
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/supports_node.rb
@@ -0,0 +1,38 @@
+module Sass::Tree
+  # A static node representing a ` supports` rule.
+  #
+  # @see Sass::Tree
+  class SupportsNode < DirectiveNode
+    # The name, which may include a browser prefix.
+    #
+    # @return [String]
+    attr_accessor :name
+
+    # The supports condition.
+    #
+    # @return [Sass::Supports::Condition]
+    attr_accessor :condition
+
+    # @param condition [Sass::Supports::Condition] See \{#condition}
+    def initialize(name, condition)
+      @name = name
+      @condition = condition
+      super('')
+    end
+
+    # @see DirectiveNode#value
+    def value; raise NotImplementedError; end
+
+    # @see DirectiveNode#resolved_value
+    def resolved_value
+      @resolved_value ||= "@#{name} #{condition.to_css}"
+    end
+
+    # True when the directive has no visible children.
+    #
+    # @return [Boolean]
+    def invisible?
+      children.all? {|c| c.invisible?}
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/trace_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/trace_node.rb
new file mode 100644
index 0000000..2c71e88
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/trace_node.rb
@@ -0,0 +1,33 @@
+require 'sass/tree/node'
+
+module Sass::Tree
+  # A solely static node left over after a mixin include or @content has been performed.
+  # Its sole purpose is to wrap exceptions to add to the backtrace.
+  #
+  # @see Sass::Tree
+  class TraceNode < Node
+    # The name of the trace entry to add.
+    #
+    # @return [String]
+    attr_reader :name
+
+    # @param name [String] The name of the trace entry to add.
+    def initialize(name)
+      @name = name
+      self.has_children = true
+      super()
+    end
+
+    # Initializes this node from an existing node.
+    # @param name [String] The name of the trace entry to add.
+    # @param node [Node] The node to copy information from.
+    # @return [TraceNode]
+    def self.from_node(name, node)
+      trace = new(name)
+      trace.line = node.line
+      trace.filename = node.filename
+      trace.options = node.options
+      trace
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/variable_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/variable_node.rb
new file mode 100644
index 0000000..2c0ed55
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/variable_node.rb
@@ -0,0 +1,36 @@
+module Sass
+  module Tree
+    # A dynamic node representing a variable definition.
+    #
+    # @see Sass::Tree
+    class VariableNode < Node
+      # The name of the variable.
+      # @return [String]
+      attr_reader :name
+
+      # The parse tree for the variable value.
+      # @return [Script::Tree::Node]
+      attr_accessor :expr
+
+      # Whether this is a guarded variable assignment (`!default`).
+      # @return [Boolean]
+      attr_reader :guarded
+
+      # Whether this is a global variable assignment (`!global`).
+      # @return [Boolean]
+      attr_reader :global
+
+      # @param name [String] The name of the variable
+      # @param expr [Script::Tree::Node] See \{#expr}
+      # @param guarded [Boolean] See \{#guarded}
+      # @param global [Boolean] See \{#global}
+      def initialize(name, expr, guarded, global)
+        @name = name
+        @expr = expr
+        @guarded = guarded
+        @global = global
+        super()
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/base.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/base.rb
new file mode 100644
index 0000000..2c8e134
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/base.rb
@@ -0,0 +1,72 @@
+# Visitors are used to traverse the Sass parse tree.
+# Visitors should extend {Visitors::Base},
+# which provides a small amount of scaffolding for traversal.
+module Sass::Tree::Visitors
+  # The abstract base class for Sass visitors.
+  # Visitors should extend this class,
+  # then implement `visit_*` methods for each node they care about
+  # (e.g. `visit_rule` for {RuleNode} or `visit_for` for {ForNode}).
+  # These methods take the node in question as argument.
+  # They may `yield` to visit the child nodes of the current node.
+  #
+  # *Note*: due to the unusual nature of {Sass::Tree::IfNode},
+  # special care must be taken to ensure that it is properly handled.
+  # In particular, there is no built-in scaffolding
+  # for dealing with the return value of ` else` nodes.
+  #
+  # @abstract
+  class Base
+    # Runs the visitor on a tree.
+    #
+    # @param root [Tree::Node] The root node of the Sass tree.
+    # @return [Object] The return value of \{#visit} for the root node.
+    def self.visit(root)
+      new.send(:visit, root)
+    end
+
+    protected
+
+    # Runs the visitor on the given node.
+    # This can be overridden by subclasses that need to do something for each node.
+    #
+    # @param node [Tree::Node] The node to visit.
+    # @return [Object] The return value of the `visit_*` method for this node.
+    def visit(node)
+      if respond_to?(node.class.visit_method, true)
+        send(node.class.visit_method, node) {visit_children(node)}
+      else
+        visit_children(node)
+      end
+    end
+
+    # Visit the child nodes for a given node.
+    # This can be overridden by subclasses that need to do something
+    # with the child nodes' return values.
+    #
+    # This method is run when `visit_*` methods `yield`,
+    # and its return value is returned from the `yield`.
+    #
+    # @param parent [Tree::Node] The parent node of the children to visit.
+    # @return [Array<Object>] The return values of the `visit_*` methods for the children.
+    def visit_children(parent)
+      parent.children.map {|c| visit(c)}
+    end
+
+    # Returns the name of a node as used in the `visit_*` method.
+    #
+    # @param [Tree::Node] node The node.
+    # @return [String] The name.
+    def self.node_name(node)
+      Sass::Util.deprecated(self, "Call node.class.node_name instead.")
+      node.class.node_name
+    end
+
+    # `yield`s, then runs the visitor on the ` else` clause if the node has one.
+    # This exists to ensure that the contents of the ` else` clause get visited.
+    def visit_if(node)
+      yield
+      visit(node.else) if node.else
+      node
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/check_nesting.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/check_nesting.rb
new file mode 100644
index 0000000..cbead20
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/check_nesting.rb
@@ -0,0 +1,177 @@
+# A visitor for checking that all nodes are properly nested.
+class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
+  protected
+
+  def initialize
+    @parents = []
+  end
+
+  def visit(node)
+    if (error = @parent && (
+        try_send(@parent.class.invalid_child_method_name, @parent, node) ||
+        try_send(node.class.invalid_parent_method_name, @parent, node)))
+      raise Sass::SyntaxError.new(error)
+    end
+    super
+  rescue Sass::SyntaxError => e
+    e.modify_backtrace(:filename => node.filename, :line => node.line)
+    raise e
+  end
+
+  CONTROL_NODES = [Sass::Tree::EachNode, Sass::Tree::ForNode, Sass::Tree::IfNode,
+                   Sass::Tree::WhileNode, Sass::Tree::TraceNode]
+  SCRIPT_NODES = [Sass::Tree::ImportNode] + CONTROL_NODES
+  def visit_children(parent)
+    old_parent = @parent
+
+    # When checking a static tree, resolve at-roots to be sure they won't send
+    # nodes where they don't belong.
+    if parent.is_a?(Sass::Tree::AtRootNode) && parent.resolved_value
+      old_parents = @parents
+      @parents = @parents.reject {|p| parent.exclude_node?(p)}
+      @parent = Sass::Util.enum_with_index(@parents.reverse).
+        find {|p, i| !transparent_parent?(p, @parents[-i - 2])}.first
+
+      begin
+        return super
+      ensure
+        @parents = old_parents
+        @parent = old_parent
+      end
+    end
+
+    unless transparent_parent?(parent, old_parent)
+      @parent = parent
+    end
+
+    @parents.push parent
+    begin
+      super
+    ensure
+      @parent = old_parent
+      @parents.pop
+    end
+  end
+
+  def visit_root(node)
+    yield
+  rescue Sass::SyntaxError => e
+    e.sass_template ||= node.template
+    raise e
+  end
+
+  def visit_import(node)
+    yield
+  rescue Sass::SyntaxError => e
+    e.modify_backtrace(:filename => node.children.first.filename)
+    e.add_backtrace(:filename => node.filename, :line => node.line)
+    raise e
+  end
+
+  def visit_mixindef(node)
+    @current_mixin_def, old_mixin_def = node, @current_mixin_def
+    yield
+  ensure
+    @current_mixin_def = old_mixin_def
+  end
+
+  def invalid_content_parent?(parent, child)
+    if @current_mixin_def
+      @current_mixin_def.has_content = true
+      nil
+    else
+      "@content may only be used within a mixin."
+    end
+  end
+
+  def invalid_charset_parent?(parent, child)
+    "@charset may only be used at the root of a document." unless parent.is_a?(Sass::Tree::RootNode)
+  end
+
+  VALID_EXTEND_PARENTS = [Sass::Tree::RuleNode, Sass::Tree::MixinDefNode, Sass::Tree::MixinNode]
+  def invalid_extend_parent?(parent, child)
+    unless is_any_of?(parent, VALID_EXTEND_PARENTS)
+      return "Extend directives may only be used within rules."
+    end
+  end
+
+  INVALID_IMPORT_PARENTS = CONTROL_NODES +
+    [Sass::Tree::MixinDefNode, Sass::Tree::MixinNode]
+  def invalid_import_parent?(parent, child)
+    unless (@parents.map {|p| p.class} & INVALID_IMPORT_PARENTS).empty?
+      return "Import directives may not be used within control directives or mixins."
+    end
+    return if parent.is_a?(Sass::Tree::RootNode)
+    return "CSS import directives may only be used at the root of a document." if child.css_import?
+  rescue Sass::SyntaxError => e
+    e.modify_backtrace(:filename => child.imported_file.options[:filename])
+    e.add_backtrace(:filename => child.filename, :line => child.line)
+    raise e
+  end
+
+  def invalid_mixindef_parent?(parent, child)
+    unless (@parents.map {|p| p.class} & INVALID_IMPORT_PARENTS).empty?
+      return "Mixins may not be defined within control directives or other mixins."
+    end
+  end
+
+  def invalid_function_parent?(parent, child)
+    unless (@parents.map {|p| p.class} & INVALID_IMPORT_PARENTS).empty?
+      return "Functions may not be defined within control directives or other mixins."
+    end
+  end
+
+  VALID_FUNCTION_CHILDREN = [
+    Sass::Tree::CommentNode,  Sass::Tree::DebugNode, Sass::Tree::ReturnNode,
+    Sass::Tree::VariableNode, Sass::Tree::WarnNode, Sass::Tree::ErrorNode
+  ] + CONTROL_NODES
+  def invalid_function_child?(parent, child)
+    unless is_any_of?(child, VALID_FUNCTION_CHILDREN)
+      "Functions can only contain variable declarations and control directives."
+    end
+  end
+
+  VALID_PROP_CHILDREN =  CONTROL_NODES + [Sass::Tree::CommentNode,
+                                          Sass::Tree::PropNode,
+                                          Sass::Tree::MixinNode]
+  def invalid_prop_child?(parent, child)
+    unless is_any_of?(child, VALID_PROP_CHILDREN)
+      "Illegal nesting: Only properties may be nested beneath properties."
+    end
+  end
+
+  VALID_PROP_PARENTS = [Sass::Tree::RuleNode, Sass::Tree::KeyframeRuleNode, Sass::Tree::PropNode,
+                        Sass::Tree::MixinDefNode, Sass::Tree::DirectiveNode, Sass::Tree::MixinNode]
+  def invalid_prop_parent?(parent, child)
+    unless is_any_of?(parent, VALID_PROP_PARENTS)
+      "Properties are only allowed within rules, directives, mixin includes, or other properties." +
+        child.pseudo_class_selector_message
+    end
+  end
+
+  def invalid_return_parent?(parent, child)
+    "@return may only be used within a function." unless parent.is_a?(Sass::Tree::FunctionNode)
+  end
+
+  private
+
+  # Whether `parent` should be assigned to ` parent` 
+  def transparent_parent?(parent, grandparent)
+    is_any_of?(parent, SCRIPT_NODES) ||
+      (parent.bubbles? &&
+       !grandparent.is_a?(Sass::Tree::RootNode) &&
+       !grandparent.is_a?(Sass::Tree::AtRootNode))
+  end
+
+  def is_any_of?(val, classes)
+    classes.each do |c|
+      return true if val.is_a?(c)
+    end
+    false
+  end
+
+  def try_send(method, *args)
+    return unless respond_to?(method, true)
+    send(method, *args)
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/convert.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/convert.rb
new file mode 100644
index 0000000..ecbf0c9
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/convert.rb
@@ -0,0 +1,334 @@
+# A visitor for converting a Sass tree into a source string.
+class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
+  # Runs the visitor on a tree.
+  #
+  # @param root [Tree::Node] The root node of the Sass tree.
+  # @param options [{Symbol => Object}] An options hash (see {Sass::CSS#initialize}).
+  # @param format [Symbol] `:sass` or `:scss`.
+  # @return [String] The Sass or SCSS source for the tree.
+  def self.visit(root, options, format)
+    new(options, format).send(:visit, root)
+  end
+
+  protected
+
+  def initialize(options, format)
+    @options = options
+    @format = format
+    @tabs = 0
+    # 2 spaces by default
+    @tab_chars = @options[:indent] || "  "
+  end
+
+  def visit_children(parent)
+    @tabs += 1
+    return @format == :sass ? "\n" : " {}\n" if parent.children.empty?
+    if @format == :sass
+      "\n"  + super.join.rstrip + "\n"
+    else
+      " {\n" + super.join.rstrip + "\n#{ @tab_chars * (@tabs - 1)}}\n"
+    end
+  ensure
+    @tabs -= 1
+  end
+
+  # Ensures proper spacing between top-level nodes.
+  def visit_root(node)
+    Sass::Util.enum_cons(node.children + [nil], 2).map do |child, nxt|
+      visit(child) +
+        if nxt &&
+            (child.is_a?(Sass::Tree::CommentNode) &&
+              child.line + child.lines + 1 == nxt.line) ||
+            (child.is_a?(Sass::Tree::ImportNode) && nxt.is_a?(Sass::Tree::ImportNode) &&
+              child.line + 1 == nxt.line) ||
+            (child.is_a?(Sass::Tree::VariableNode) && nxt.is_a?(Sass::Tree::VariableNode) &&
+              child.line + 1 == nxt.line)
+          ""
+        else
+          "\n"
+        end
+    end.join.rstrip + "\n"
+  end
+
+  def visit_charset(node)
+    "#{tab_str} charset \"#{node.name}\"#{semi}\n"
+  end
+
+  def visit_comment(node)
+    value = interp_to_src(node.value)
+    if @format == :sass
+      content = value.gsub(/\*\/$/, '').rstrip
+      if content =~ /\A[ \t]/
+        # Re-indent SCSS comments like this:
+        #     /* foo
+        #   bar
+        #       baz */
+        content.gsub!(/^/, '   ')
+        content.sub!(/\A([ \t]*)\/\*/, '/*\1')
+      end
+
+      if content.include?("\n")
+        content.gsub!(/\n \*/, "\n  ")
+        spaces = content.scan(/\n( *)/).map {|s| s.first.size}.min
+        sep = node.type == :silent ? "\n//" : "\n *"
+        if spaces >= 2
+          content.gsub!(/\n  /, sep)
+        else
+          content.gsub!(/\n#{' ' * spaces}/, sep)
+        end
+      end
+
+      content.gsub!(/\A\/\*/, '//') if node.type == :silent
+      content.gsub!(/^/, tab_str)
+      content = content.rstrip + "\n"
+    else
+      spaces = (@tab_chars * [ tabs - value[/^ */].size, 0].max)
+      content = if node.type == :silent
+                  value.gsub(/^[\/ ]\*/, '//').gsub(/ *\*\/$/, '')
+                else
+                  value
+                end.gsub(/^/, spaces) + "\n"
+    end
+    content
+  end
+
+  def visit_debug(node)
+    "#{tab_str} debug #{node.expr.to_sass(@options)}#{semi}\n"
+  end
+
+  def visit_error(node)
+    "#{tab_str} error #{node.expr.to_sass(@options)}#{semi}\n"
+  end
+
+  def visit_directive(node)
+    res = "#{tab_str}#{interp_to_src(node.value)}"
+    res.gsub!(/^ import \#\{(.*)\}([^}]*)$/, '@import \1\2')
+    return res + "#{semi}\n" unless node.has_children
+    res + yield + "\n"
+  end
+
+  def visit_each(node)
+    vars = node.vars.map {|var| "$#{dasherize(var)}"}.join(", ")
+    "#{tab_str} each #{vars} in #{node.list.to_sass(@options)}#{yield}"
+  end
+
+  def visit_extend(node)
+    "#{tab_str} extend #{selector_to_src(node.selector).lstrip}" +
+      "#{" !optional" if node.optional?}#{semi}\n"
+  end
+
+  def visit_for(node)
+    "#{tab_str} for $#{dasherize(node.var)} from #{node.from.to_sass(@options)} " +
+      "#{node.exclusive ? "to" : "through"} #{node.to.to_sass(@options)}#{yield}"
+  end
+
+  def visit_function(node)
+    args = node.args.map do |v, d|
+      d ? "#{v.to_sass(@options)}: #{d.to_sass(@options)}" : v.to_sass(@options)
+    end.join(", ")
+    if node.splat
+      args << ", " unless node.args.empty?
+      args << node.splat.to_sass(@options) << "..."
+    end
+
+    "#{tab_str} function #{dasherize(node.name)}(#{args})#{yield}"
+  end
+
+  def visit_if(node)
+    name =
+      if ! is_else
+        "if"
+      elsif node.expr
+        "else if"
+      else
+        "else"
+      end
+    @is_else = false
+    str = "#{tab_str} #{name}"
+    str << " #{node.expr.to_sass(@options)}" if node.expr
+    str << yield
+    @is_else = true
+    str << visit(node.else) if node.else
+    str
+  ensure
+    @is_else = false
+  end
+
+  def visit_import(node)
+    quote = @format == :scss ? '"' : ''
+    "#{tab_str} import #{quote}#{node.imported_filename}#{quote}#{semi}\n"
+  end
+
+  def visit_media(node)
+    "#{tab_str} media #{query_interp_to_src(node.query)}#{yield}"
+  end
+
+  def visit_supports(node)
+    "#{tab_str} #{node name} #{node.condition.to_src(@options)}#{yield}"
+  end
+
+  def visit_cssimport(node)
+    if node.uri.is_a?(Sass::Script::Tree::Node)
+      str = "#{tab_str} import #{node.uri.to_sass(@options)}"
+    else
+      str = "#{tab_str} import #{node.uri}"
+    end
+    str << " #{interp_to_src(node.query)}" unless node.query.empty?
+    "#{str}#{semi}\n"
+  end
+
+  def visit_mixindef(node)
+    args =
+      if node.args.empty? && node.splat.nil?
+        ""
+      else
+        str = '('
+        str << node.args.map do |v, d|
+          if d
+            "#{v.to_sass(@options)}: #{d.to_sass(@options)}"
+          else
+            v.to_sass(@options)
+          end
+        end.join(", ")
+
+        if node.splat
+          str << ", " unless node.args.empty?
+          str << node.splat.to_sass(@options) << '...'
+        end
+
+        str << ')'
+      end
+
+    "#{tab_str}#{ format == :sass ? '=' : '@mixin '}#{dasherize(node.name)}#{args}#{yield}"
+  end
+
+  def visit_mixin(node)
+    arg_to_sass = lambda do |arg|
+      sass = arg.to_sass(@options)
+      sass = "(#{sass})" if arg.is_a?(Sass::Script::Tree::ListLiteral) && arg.separator == :comma
+      sass
+    end
+
+    unless node.args.empty? && node.keywords.empty? && node.splat.nil?
+      args = node.args.map(&arg_to_sass)
+      keywords = Sass::Util.hash_to_a(node.keywords.as_stored).
+        map {|k, v| "$#{dasherize(k)}: #{arg_to_sass[v]}"}
+
+      if node.splat
+        splat = "#{arg_to_sass[node.splat]}..."
+        kwarg_splat = "#{arg_to_sass[node.kwarg_splat]}..." if node.kwarg_splat
+      end
+
+      arglist = "(#{[args, splat, keywords, kwarg_splat].flatten.compact.join(', ')})"
+    end
+    "#{tab_str}#{ format == :sass ? '+' : '@include '}" +
+      "#{dasherize(node.name)}#{arglist}#{node.has_children ? yield : semi}\n"
+  end
+
+  def visit_content(node)
+    "#{tab_str} content#{semi}\n"
+  end
+
+  def visit_prop(node)
+    res = tab_str + node.declaration(@options, @format)
+    return res + semi + "\n" if node.children.empty?
+    res + yield.rstrip + semi + "\n"
+  end
+
+  def visit_return(node)
+    "#{tab_str} return #{node.expr.to_sass(@options)}#{semi}\n"
+  end
+
+  def visit_rule(node)
+    rule = node.parsed_rules ? [node.parsed_rules.to_s] : node.rule
+    if @format == :sass
+      name = selector_to_sass(rule)
+      name = "\\" + name if name[0] == ?:
+      name.gsub(/^/, tab_str) + yield
+    elsif @format == :scss
+      name = selector_to_scss(rule)
+      res = name + yield
+      if node.children.last.is_a?(Sass::Tree::CommentNode) && node.children.last.type == :silent
+        res.slice!(-3..-1)
+        res << "\n" << tab_str << "}\n"
+      end
+      res
+    end
+  end
+
+  def visit_variable(node)
+    "#{tab_str}$#{dasherize(node.name)}: #{node.expr.to_sass(@options)}" +
+      "#{' !global' if node.global}#{' !default' if node.guarded}#{semi}\n"
+  end
+
+  def visit_warn(node)
+    "#{tab_str} warn #{node.expr.to_sass(@options)}#{semi}\n"
+  end
+
+  def visit_while(node)
+    "#{tab_str} while #{node.expr.to_sass(@options)}#{yield}"
+  end
+
+  def visit_atroot(node)
+    if node.query
+      "#{tab_str} at-root #{query_interp_to_src(node.query)}#{yield}"
+    elsif node.children.length == 1 && node.children.first.is_a?(Sass::Tree::RuleNode)
+      rule = node.children.first
+      "#{tab_str} at-root #{selector_to_src(rule.rule).lstrip}#{visit_children(rule)}"
+    else
+      "#{tab_str} at-root#{yield}"
+    end
+  end
+
+  private
+
+  def interp_to_src(interp)
+    interp.map {|r| r.is_a?(String) ? r : r.to_sass(@options)}.join
+  end
+
+  # Like interp_to_src, but removes the unnecessary `#{}` around the keys and
+  # values in query expressions.
+  def query_interp_to_src(interp)
+    interp = interp.map do |e|
+      next e unless e.is_a?(Sass::Script::Tree::Literal)
+      next e unless e.value.is_a?(Sass::Script::Value::String)
+      e.value.value
+    end
+
+    interp_to_src(interp)
+  end
+
+  def selector_to_src(sel)
+    @format == :sass ? selector_to_sass(sel) : selector_to_scss(sel)
+  end
+
+  def selector_to_sass(sel)
+    sel.map do |r|
+      if r.is_a?(String)
+        r.gsub(/(,)?([ \t]*)\n\s*/) {$1 ? "#{$1}#{$2}\n" : " "}
+      else
+        r.to_sass(@options)
+      end
+    end.join
+  end
+
+  def selector_to_scss(sel)
+    interp_to_src(sel).gsub(/^[ \t]*/, tab_str).gsub(/[ \t]*$/, '')
+  end
+
+  def semi
+    @format == :sass ? "" : ";"
+  end
+
+  def tab_str
+    @tab_chars * @tabs
+  end
+
+  def dasherize(s)
+    if @options[:dasherize]
+      s.gsub('_', '-')
+    else
+      s
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/cssize.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/cssize.rb
new file mode 100644
index 0000000..ff18dde
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/cssize.rb
@@ -0,0 +1,373 @@
+# A visitor for converting a static Sass tree into a static CSS tree.
+class Sass::Tree::Visitors::Cssize < Sass::Tree::Visitors::Base
+  # @param root [Tree::Node] The root node of the tree to visit.
+  # @return [(Tree::Node, Sass::Util::SubsetMap)] The resulting tree of static nodes
+  #   *and* the extensions defined for this tree
+  def self.visit(root); super; end
+
+  protected
+
+  # Returns the immediate parent of the current node.
+  # @return [Tree::Node]
+  def parent
+    @parents.last
+  end
+
+  def initialize
+    @parents = []
+    @extends = Sass::Util::SubsetMap.new
+  end
+
+  # If an exception is raised, this adds proper metadata to the backtrace.
+  def visit(node)
+    super(node)
+  rescue Sass::SyntaxError => e
+    e.modify_backtrace(:filename => node.filename, :line => node.line)
+    raise e
+  end
+
+  # Keeps track of the current parent node.
+  def visit_children(parent)
+    with_parent parent do
+      parent.children = visit_children_without_parent(parent)
+      parent
+    end
+  end
+
+  # Like {#visit\_children}, but doesn't set {#parent}.
+  #
+  # @param node [Sass::Tree::Node]
+  # @return [Array<Sass::Tree::Node>] the flattened results of
+  #   visiting all the children of `node`
+  def visit_children_without_parent(node)
+    node.children.map {|c| visit(c)}.flatten
+  end
+
+  # Runs a block of code with the current parent node
+  # replaced with the given node.
+  #
+  # @param parent [Tree::Node] The new parent for the duration of the block.
+  # @yield A block in which the parent is set to `parent`.
+  # @return [Object] The return value of the block.
+  def with_parent(parent)
+    @parents.push parent
+    yield
+  ensure
+    @parents.pop
+  end
+
+  # In Ruby 1.8, ensures that there's only one ` charset` directive
+  # and that it's at the top of the document.
+  #
+  # @return [(Tree::Node, Sass::Util::SubsetMap)] The resulting tree of static nodes
+  #   *and* the extensions defined for this tree
+  def visit_root(node)
+    yield
+
+    if parent.nil?
+      # In Ruby 1.9 we can make all @charset nodes invisible
+      # and infer the final @charset from the encoding of the final string.
+      if Sass::Util.ruby1_8?
+        charset = node.children.find {|c| c.is_a?(Sass::Tree::CharsetNode)}
+        node.children.reject! {|c| c.is_a?(Sass::Tree::CharsetNode)}
+        node.children.unshift charset if charset
+      end
+
+      imports_to_move = []
+      import_limit = nil
+      i = -1
+      node.children.reject! do |n|
+        i += 1
+        if import_limit
+          next false unless n.is_a?(Sass::Tree::CssImportNode)
+          imports_to_move << n
+          next true
+        end
+
+        if !n.is_a?(Sass::Tree::CommentNode) &&
+            !n.is_a?(Sass::Tree::CharsetNode) &&
+            !n.is_a?(Sass::Tree::CssImportNode)
+          import_limit = i
+        end
+
+        false
+      end
+
+      if import_limit
+        node.children = node.children[0...import_limit] + imports_to_move +
+          node.children[import_limit..-1]
+      end
+    end
+
+    return node, @extends
+  rescue Sass::SyntaxError => e
+    e.sass_template ||= node.template
+    raise e
+  end
+
+  # A simple struct wrapping up information about a single ` extend` instance. A
+  # single {ExtendNode} can have multiple Extends if either the parent node or
+  # the extended selector is a comma sequence.
+  #
+  # @attr extender [Sass::Selector::Sequence]
+  #   The selector of the CSS rule containing the ` extend` 
+  # @attr target [Array<Sass::Selector::Simple>] The selector being ` extend`ed 
+  # @attr node [Sass::Tree::ExtendNode] The node that produced this extend.
+  # @attr directives [Array<Sass::Tree::DirectiveNode>]
+  #   The directives containing the ` extend` 
+  # @attr result [Symbol]
+  #   The result of this extend. One of `:not_found` (the target doesn't exist
+  #   in the document), `:failed_to_unify` (the target exists but cannot be
+  #   unified with the extender), or `:succeeded`.
+  Extend = Struct.new(:extender, :target, :node, :directives, :result)
+
+  # Registers an extension in the ` extends` subset map.
+  def visit_extend(node)
+    parent.resolved_rules.populate_extends(@extends, node.resolved_selector, node,
+      @parents.select {|p| p.is_a?(Sass::Tree::DirectiveNode)})
+    []
+  end
+
+  # Modifies exception backtraces to include the imported file.
+  def visit_import(node)
+    visit_children_without_parent(node)
+  rescue Sass::SyntaxError => e
+    e.modify_backtrace(:filename => node.children.first.filename)
+    e.add_backtrace(:filename => node.filename, :line => node.line)
+    raise e
+  end
+
+  # Asserts that all the traced children are valid in their new location.
+  def visit_trace(node)
+    visit_children_without_parent(node)
+  rescue Sass::SyntaxError => e
+    e.modify_backtrace(:mixin => node.name, :filename => node.filename, :line => node.line)
+    e.add_backtrace(:filename => node.filename, :line => node.line)
+    raise e
+  end
+
+  # Converts nested properties into flat properties
+  # and updates the indentation of the prop node based on the nesting level.
+  def visit_prop(node)
+    if parent.is_a?(Sass::Tree::PropNode)
+      node.resolved_name = "#{parent.resolved_name}-#{node.resolved_name}"
+      node.tabs = parent.tabs + (parent.resolved_value.empty? ? 0 : 1) if node.style == :nested
+    end
+
+    yield
+
+    result = node.children.dup
+    if !node.resolved_value.empty? || node.children.empty?
+      node.send(:check!)
+      result.unshift(node)
+    end
+
+    result
+  end
+
+  def visit_atroot(node)
+    # If there aren't any more directives or rules that this @at-root needs to
+    # exclude, we can get rid of it and just evaluate the children.
+    if @parents.none? {|n| node.exclude_node?(n)}
+      results = visit_children_without_parent(node)
+      results.each {|c| c.tabs += node.tabs if bubblable?(c)}
+      if !results.empty? && bubblable?(results.last)
+        results.last.group_end = node.group_end
+      end
+      return results
+    end
+
+    # If this @at-root excludes the immediate parent, return it as-is so that it
+    # can be bubbled up by the parent node.
+    return Bubble.new(node) if node.exclude_node?(parent)
+
+    # Otherwise, duplicate the current parent and move it into the @at-root
+    # node. As above, returning an @at-root node signals to the parent directive
+    # that it should be bubbled upwards.
+    bubble(node)
+  end
+
+  # The following directives are visible and have children. This means they need
+  # to be able to handle bubbling up nodes such as @at-root and @media.
+
+  # Updates the indentation of the rule node based on the nesting
+  # level. The selectors were resolved in {Perform}.
+  def visit_rule(node)
+    yield
+
+    rules = node.children.select {|c| bubblable?(c)}
+    props = node.children.reject {|c| bubblable?(c) || c.invisible?}
+
+    unless props.empty?
+      node.children = props
+      rules.each {|r| r.tabs += 1} if node.style == :nested
+      rules.unshift(node)
+    end
+
+    rules = debubble(rules)
+    unless parent.is_a?(Sass::Tree::RuleNode) || rules.empty? || !bubblable?(rules.last)
+      rules.last.group_end = true
+    end
+    rules
+  end
+
+  def visit_keyframerule(node)
+    return node unless node.has_children
+
+    yield
+
+    debubble(node.children, node)
+  end
+
+  # Bubbles a directive up through RuleNodes.
+  def visit_directive(node)
+    return node unless node.has_children
+    if parent.is_a?(Sass::Tree::RuleNode)
+      # @keyframes shouldn't include the rule nodes, so we manually create a
+      # bubble that doesn't have the parent's contents for them.
+      return node.normalized_name == '@keyframes' ? Bubble.new(node) : bubble(node)
+    end
+
+    yield
+
+    # Since we don't know if the mere presence of an unknown directive may be
+    # important, we should keep an empty version around even if all the contents
+    # are removed via @at-root. However, if the contents are just bubbled out,
+    # we don't need to do so.
+    directive_exists = node.children.any? do |child|
+      next true unless child.is_a?(Bubble)
+      next false unless child.node.is_a?(Sass::Tree::DirectiveNode)
+      child.node.resolved_value == node.resolved_value
+    end
+
+    # We know empty @keyframes directives do nothing.
+    if directive_exists || node.name == '@keyframes'
+      []
+    else
+      empty_node = node.dup
+      empty_node.children = []
+      [empty_node]
+    end + debubble(node.children, node)
+  end
+
+  # Bubbles the ` media` directive up through RuleNodes
+  # and merges it with other ` media` directives.
+  def visit_media(node)
+    return bubble(node) if parent.is_a?(Sass::Tree::RuleNode)
+    return Bubble.new(node) if parent.is_a?(Sass::Tree::MediaNode)
+
+    yield
+
+    debubble(node.children, node) do |child|
+      next child unless child.is_a?(Sass::Tree::MediaNode)
+      # Copies of `node` can be bubbled, and we don't want to merge it with its
+      # own query.
+      next child if child.resolved_query == node.resolved_query
+      next child if child.resolved_query = child.resolved_query.merge(node.resolved_query)
+    end
+  end
+
+  # Bubbles the ` supports` directive up through RuleNodes.
+  def visit_supports(node)
+    return node unless node.has_children
+    return bubble(node) if parent.is_a?(Sass::Tree::RuleNode)
+
+    yield
+
+    debubble(node.children, node)
+  end
+
+  private
+
+  # "Bubbles" `node` one level by copying the parent and wrapping `node`'s
+  # children with it.
+  #
+  # @param node [Sass::Tree::Node].
+  # @return [Bubble]
+  def bubble(node)
+    new_rule = parent.dup
+    new_rule.children = node.children
+    node.children = [new_rule]
+    Bubble.new(node)
+  end
+
+  # Pops all bubbles in `children` and intersperses the results with the other
+  # values.
+  #
+  # If `parent` is passed, it's copied and used as the parent node for the
+  # nested portions of `children`.
+  #
+  # @param children [List<Sass::Tree::Node, Bubble>]
+  # @param parent [Sass::Tree::Node]
+  # @yield [node] An optional block for processing bubbled nodes. Each bubbled
+  #   node will be passed to this block.
+  # @yieldparam node [Sass::Tree::Node] A bubbled node.
+  # @yieldreturn [Sass::Tree::Node?] A node to use in place of the bubbled node.
+  #   This can be the node itself, or `nil` to indicate that the node should be
+  #   omitted.
+  # @return [List<Sass::Tree::Node, Bubble>]
+  def debubble(children, parent = nil)
+    # Keep track of the previous parent so that we don't divide `parent`
+    # unnecessarily if the ` at-root` doesn't produce any new nodes (e.g.
+    # ` at-root { extend %foo}`).
+    previous_parent = nil
+
+    Sass::Util.slice_by(children) {|c| c.is_a?(Bubble)}.map do |(is_bubble, slice)|
+      unless is_bubble
+        next slice unless parent
+        if previous_parent
+          previous_parent.children.push(*slice)
+          next []
+        else
+          previous_parent = new_parent = parent.dup
+          new_parent.children = slice
+          next new_parent
+        end
+      end
+
+      slice.map do |bubble|
+        next unless (node = block_given? ? yield(bubble.node) : bubble.node)
+        node.tabs += bubble.tabs
+        node.group_end = bubble.group_end
+        results = [visit(node)].flatten
+        previous_parent = nil unless results.empty?
+        results
+      end.compact
+    end.flatten
+  end
+
+  # Returns whether or not a node can be bubbled up through the syntax tree.
+  #
+  # @param node [Sass::Tree::Node]
+  # @return [Boolean]
+  def bubblable?(node)
+    node.is_a?(Sass::Tree::RuleNode) || node.bubbles?
+  end
+
+  # A wrapper class for a node that indicates to the parent that it should
+  # treat the wrapped node as a sibling rather than a child.
+  #
+  # Nodes should be wrapped before they're passed to \{Cssize.visit}. They will
+  # be automatically visited upon calling \{#pop}.
+  #
+  # This duck types as a [Sass::Tree::Node] for the purposes of
+  # tree-manipulation operations.
+  class Bubble
+    attr_accessor :node
+    attr_accessor :tabs
+    attr_accessor :group_end
+
+    def initialize(node)
+      @node = node
+      @tabs = 0
+    end
+
+    def bubbles?
+      true
+    end
+
+    def inspect
+      "(Bubble #{node.inspect})"
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/deep_copy.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/deep_copy.rb
new file mode 100644
index 0000000..2a7036d
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/deep_copy.rb
@@ -0,0 +1,107 @@
+# A visitor for copying the full structure of a Sass tree.
+class Sass::Tree::Visitors::DeepCopy < Sass::Tree::Visitors::Base
+  protected
+
+  def visit(node)
+    super(node.dup)
+  end
+
+  def visit_children(parent)
+    parent.children = parent.children.map {|c| visit(c)}
+    parent
+  end
+
+  def visit_debug(node)
+    node.expr = node.expr.deep_copy
+    yield
+  end
+
+  def visit_error(node)
+    node.expr = node.expr.deep_copy
+    yield
+  end
+
+  def visit_each(node)
+    node.list = node.list.deep_copy
+    yield
+  end
+
+  def visit_extend(node)
+    node.selector = node.selector.map {|c| c.is_a?(Sass::Script::Tree::Node) ? c.deep_copy : c}
+    yield
+  end
+
+  def visit_for(node)
+    node.from = node.from.deep_copy
+    node.to = node.to.deep_copy
+    yield
+  end
+
+  def visit_function(node)
+    node.args = node.args.map {|k, v| [k.deep_copy, v && v.deep_copy]}
+    yield
+  end
+
+  def visit_if(node)
+    node.expr = node.expr.deep_copy if node.expr
+    node.else = visit(node.else) if node.else
+    yield
+  end
+
+  def visit_mixindef(node)
+    node.args = node.args.map {|k, v| [k.deep_copy, v && v.deep_copy]}
+    yield
+  end
+
+  def visit_mixin(node)
+    node.args = node.args.map {|a| a.deep_copy}
+    node.keywords = Hash[node.keywords.map {|k, v| [k, v.deep_copy]}]
+    yield
+  end
+
+  def visit_prop(node)
+    node.name = node.name.map {|c| c.is_a?(Sass::Script::Tree::Node) ? c.deep_copy : c}
+    node.value = node.value.deep_copy
+    yield
+  end
+
+  def visit_return(node)
+    node.expr = node.expr.deep_copy
+    yield
+  end
+
+  def visit_rule(node)
+    node.rule = node.rule.map {|c| c.is_a?(Sass::Script::Tree::Node) ? c.deep_copy : c}
+    yield
+  end
+
+  def visit_variable(node)
+    node.expr = node.expr.deep_copy
+    yield
+  end
+
+  def visit_warn(node)
+    node.expr = node.expr.deep_copy
+    yield
+  end
+
+  def visit_while(node)
+    node.expr = node.expr.deep_copy
+    yield
+  end
+
+  def visit_directive(node)
+    node.value = node.value.map {|c| c.is_a?(Sass::Script::Tree::Node) ? c.deep_copy : c}
+    yield
+  end
+
+  def visit_media(node)
+    node.query = node.query.map {|c| c.is_a?(Sass::Script::Tree::Node) ? c.deep_copy : c}
+    yield
+  end
+
+  def visit_supports(node)
+    node.condition = node.condition.deep_copy
+    yield
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/extend.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/extend.rb
new file mode 100644
index 0000000..4fcad49
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/extend.rb
@@ -0,0 +1,68 @@
+# A visitor for performing selector inheritance on a static CSS tree.
+#
+# Destructively modifies the tree.
+class Sass::Tree::Visitors::Extend < Sass::Tree::Visitors::Base
+  # Performs the given extensions on the static CSS tree based in `root`, then
+  # validates that all extends matched some selector.
+  #
+  # @param root [Tree::Node] The root node of the tree to visit.
+  # @param extends [Sass::Util::SubsetMap{Selector::Simple =>
+  #                                       Sass::Tree::Visitors::Cssize::Extend}]
+  #   The extensions to perform on this tree.
+  # @return [Object] The return value of \{#visit} for the root node.
+  def self.visit(root, extends)
+    return if extends.empty?
+    new(extends).send(:visit, root)
+    check_extends_fired! extends
+  end
+
+  protected
+
+  def initialize(extends)
+    @parent_directives = []
+    @extends = extends
+  end
+
+  # If an exception is raised, this adds proper metadata to the backtrace.
+  def visit(node)
+    super(node)
+  rescue Sass::SyntaxError => e
+    e.modify_backtrace(:filename => node.filename, :line => node.line)
+    raise e
+  end
+
+  # Keeps track of the current parent directives.
+  def visit_children(parent)
+    @parent_directives.push parent if parent.is_a?(Sass::Tree::DirectiveNode)
+    super
+  ensure
+    @parent_directives.pop if parent.is_a?(Sass::Tree::DirectiveNode)
+  end
+
+  # Applies the extend to a single rule's selector.
+  def visit_rule(node)
+    node.resolved_rules = node.resolved_rules.do_extend(@extends, @parent_directives)
+  end
+
+  private
+
+  def self.check_extends_fired!(extends)
+    extends.each_value do |ex|
+      next if ex.result == :succeeded || ex.node.optional?
+      message = "\"#{ex.extender}\" failed to @extend \"#{ex.target.join}\"."
+      reason =
+        if ex.result == :not_found
+          "The selector \"#{ex.target.join}\" was not found."
+        else
+          "No selectors matching \"#{ex.target.join}\" could be unified with \"#{ex.extender}\"."
+        end
+
+      # TODO(nweiz): this should use the Sass stack trace of the extend node.
+      raise Sass::SyntaxError.new(<<MESSAGE, :filename => ex.node.filename, :line => ex.node.line)
+#{message}
+#{reason}
+Use "@extend #{ex.target.join} !optional" if the extend should be able to fail.
+MESSAGE
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/perform.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/perform.rb
new file mode 100644
index 0000000..280c936
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/perform.rb
@@ -0,0 +1,547 @@
+# A visitor for converting a dynamic Sass tree into a static Sass tree.
+class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
+  class << self
+    # @param root [Tree::Node] The root node of the tree to visit.
+    # @param environment [Sass::Environment] The lexical environment.
+    # @return [Tree::Node] The resulting tree of static nodes.
+    def visit(root, environment = nil)
+      new(environment).send(:visit, root)
+    end
+
+    # @api private
+    # @comment
+    #   rubocop:disable MethodLength
+    def perform_arguments(callable, args, splat, environment)
+      desc = "#{callable.type.capitalize} #{callable.name}"
+      downcase_desc = "#{callable.type} #{callable.name}"
+
+      # All keywords are contained in splat.keywords for consistency,
+      # even if there were no splats passed in.
+      old_keywords_accessed = splat.keywords_accessed
+      keywords = splat.keywords
+      splat.keywords_accessed = old_keywords_accessed
+
+      begin
+        unless keywords.empty?
+          unknown_args = Sass::Util.array_minus(keywords.keys,
+            callable.args.map {|var| var.first.underscored_name})
+          if callable.splat && unknown_args.include?(callable.splat.underscored_name)
+            raise Sass::SyntaxError.new("Argument $#{callable.splat.name} of #{downcase_desc} " +
+                                        "cannot be used as a named argument.")
+          elsif unknown_args.any?
+            description = unknown_args.length > 1 ? 'the following arguments:' : 'an argument named'
+            raise Sass::SyntaxError.new("#{desc} doesn't have #{description} " +
+                                        "#{unknown_args.map {|name| "$#{name}"}.join ', '}.")
+          end
+        end
+      rescue Sass::SyntaxError => keyword_exception
+      end
+
+      # If there's no splat, raise the keyword exception immediately. The actual
+      # raising happens in the ensure clause at the end of this function.
+      return if keyword_exception && !callable.splat
+
+      splat_sep = :comma
+      if splat
+        args += splat.to_a
+        splat_sep = splat.separator
+      end
+
+      if args.size > callable.args.size && !callable.splat
+        extra_args_because_of_splat = splat && args.size - splat.to_a.size <= callable.args.size
+
+        takes = callable.args.size
+        passed = args.size
+        message = "#{desc} takes #{takes} argument#{'s' unless takes == 1} " +
+          "but #{passed} #{passed == 1 ? 'was' : 'were'} passed."
+        raise Sass::SyntaxError.new(message) unless extra_args_because_of_splat
+        # TODO: when the deprecation period is over, make this an error.
+        Sass::Util.sass_warn("WARNING: #{message}\n" +
+          environment.stack.to_s.gsub(/^/m, " " * 8) + "\n" +
+          "This will be an error in future versions of Sass.")
+      end
+
+      env = Sass::Environment.new(callable.environment)
+      callable.args.zip(args[0...callable.args.length]) do |(var, default), value|
+        if value && keywords.has_key?(var.name)
+          raise Sass::SyntaxError.new("#{desc} was passed argument $#{var.name} " +
+                                      "both by position and by name.")
+        end
+
+        value ||= keywords.delete(var.name)
+        value ||= default && default.perform(env)
+        raise Sass::SyntaxError.new("#{desc} is missing argument #{var.inspect}.") unless value
+        env.set_local_var(var.name, value)
+      end
+
+      if callable.splat
+        rest = args[callable.args.length..-1] || []
+        arg_list = Sass::Script::Value::ArgList.new(rest, keywords, splat_sep)
+        arg_list.options = env.options
+        env.set_local_var(callable.splat.name, arg_list)
+      end
+
+      yield env
+    rescue StandardError => e
+    ensure
+      # If there's a keyword exception, we don't want to throw it immediately,
+      # because the invalid keywords may be part of a glob argument that should be
+      # passed on to another function. So we only raise it if we reach the end of
+      # this function *and* the keywords attached to the argument list glob object
+      # haven't been accessed.
+      #
+      # The keyword exception takes precedence over any Sass errors, but not over
+      # non-Sass exceptions.
+      if keyword_exception &&
+          !(arg_list && arg_list.keywords_accessed) &&
+          (e.nil? || e.is_a?(Sass::SyntaxError))
+        raise keyword_exception
+      elsif e
+        raise e
+      end
+    end
+
+    # @api private
+    # @return [Sass::Script::Value::ArgList]
+    def perform_splat(splat, performed_keywords, kwarg_splat, environment)
+      args, kwargs, separator = [], nil, :comma
+
+      if splat
+        splat = splat.perform(environment)
+        separator = splat.separator || separator
+        if splat.is_a?(Sass::Script::Value::ArgList)
+          args = splat.to_a
+          kwargs = splat.keywords
+        elsif splat.is_a?(Sass::Script::Value::Map)
+          kwargs = arg_hash(splat)
+        else
+          args = splat.to_a
+        end
+      end
+      kwargs ||= Sass::Util::NormalizedMap.new
+      kwargs.update(performed_keywords)
+
+      if kwarg_splat
+        kwarg_splat = kwarg_splat.perform(environment)
+        unless kwarg_splat.is_a?(Sass::Script::Value::Map)
+          raise Sass::SyntaxError.new("Variable keyword arguments must be a map " +
+                                      "(was #{kwarg_splat.inspect}).")
+        end
+        kwargs.update(arg_hash(kwarg_splat))
+      end
+
+      Sass::Script::Value::ArgList.new(args, kwargs, separator)
+    end
+
+    private
+
+    def arg_hash(map)
+      Sass::Util.map_keys(map.to_h) do |key|
+        next key.value if key.is_a?(Sass::Script::Value::String)
+        raise Sass::SyntaxError.new("Variable keyword argument map must have string keys.\n" +
+          "#{key.inspect} is not a string in #{map.inspect}.")
+      end
+    end
+  end
+  # @comment
+  #   rubocop:enable MethodLength
+
+  protected
+
+  def initialize(env)
+    @environment = env
+  end
+
+  # If an exception is raised, this adds proper metadata to the backtrace.
+  def visit(node)
+    return super(node.dup) unless @environment
+    @environment.stack.with_base(node.filename, node.line) {super(node.dup)}
+  rescue Sass::SyntaxError => e
+    e.modify_backtrace(:filename => node.filename, :line => node.line)
+    raise e
+  end
+
+  # Keeps track of the current environment.
+  def visit_children(parent)
+    with_environment Sass::Environment.new(@environment, parent.options) do
+      parent.children = super.flatten
+      parent
+    end
+  end
+
+  # Runs a block of code with the current environment replaced with the given one.
+  #
+  # @param env [Sass::Environment] The new environment for the duration of the block.
+  # @yield A block in which the environment is set to `env`.
+  # @return [Object] The return value of the block.
+  def with_environment(env)
+    old_env, @environment = @environment, env
+    yield
+  ensure
+    @environment = old_env
+  end
+
+  # Sets the options on the environment if this is the top-level root.
+  def visit_root(node)
+    yield
+  rescue Sass::SyntaxError => e
+    e.sass_template ||= node.template
+    raise e
+  end
+
+  # Removes this node from the tree if it's a silent comment.
+  def visit_comment(node)
+    return [] if node.invisible?
+    node.resolved_value = run_interp_no_strip(node.value)
+    node.resolved_value.gsub!(/\\([\\#])/, '\1')
+    node
+  end
+
+  # Prints the expression to STDERR.
+  def visit_debug(node)
+    res = node.expr.perform(@environment)
+    if res.is_a?(Sass::Script::Value::String)
+      res = res.value
+    else
+      res = res.to_sass
+    end
+    if node.filename
+      Sass::Util.sass_warn "#{node.filename}:#{node.line} DEBUG: #{res}"
+    else
+      Sass::Util.sass_warn "Line #{node.line} DEBUG: #{res}"
+    end
+    []
+  end
+
+  # Throws the expression as an error.
+  def visit_error(node)
+    res = node.expr.perform(@environment)
+    if res.is_a?(Sass::Script::Value::String)
+      res = res.value
+    else
+      res = res.to_sass
+    end
+    raise Sass::SyntaxError.new(res)
+  end
+
+  # Runs the child nodes once for each value in the list.
+  def visit_each(node)
+    list = node.list.perform(@environment)
+
+    with_environment Sass::SemiGlobalEnvironment.new(@environment) do
+      list.to_a.map do |value|
+        if node.vars.length == 1
+          @environment.set_local_var(node.vars.first, value)
+        else
+          node.vars.zip(value.to_a) do |(var, sub_value)|
+            @environment.set_local_var(var, sub_value || Sass::Script::Value::Null.new)
+          end
+        end
+        node.children.map {|c| visit(c)}
+      end.flatten
+    end
+  end
+
+  # Runs SassScript interpolation in the selector,
+  # and then parses the result into a {Sass::Selector::CommaSequence}.
+  def visit_extend(node)
+    parser = Sass::SCSS::StaticParser.new(run_interp(node.selector),
+      node.filename, node.options[:importer], node.line)
+    node.resolved_selector = parser.parse_selector
+    node
+  end
+
+  # Runs the child nodes once for each time through the loop, varying the variable each time.
+  def visit_for(node)
+    from = node.from.perform(@environment)
+    to = node.to.perform(@environment)
+    from.assert_int!
+    to.assert_int!
+
+    to = to.coerce(from.numerator_units, from.denominator_units)
+    direction = from.to_i > to.to_i ? -1 : 1
+    range = Range.new(direction * from.to_i, direction * to.to_i, node.exclusive)
+
+    with_environment Sass::SemiGlobalEnvironment.new(@environment) do
+      range.map do |i|
+        @environment.set_local_var(node.var,
+          Sass::Script::Value::Number.new(direction * i,
+            from.numerator_units, from.denominator_units))
+        node.children.map {|c| visit(c)}
+      end.flatten
+    end
+  end
+
+  # Loads the function into the environment.
+  def visit_function(node)
+    env = Sass::Environment.new(@environment, node.options)
+    @environment.set_local_function(node.name,
+      Sass::Callable.new(node.name, node.args, node.splat, env,
+                         node.children, !:has_content, "function"))
+    []
+  end
+
+  # Runs the child nodes if the conditional expression is true;
+  # otherwise, tries the else nodes.
+  def visit_if(node)
+    if node.expr.nil? || node.expr.perform(@environment).to_bool
+      with_environment Sass::SemiGlobalEnvironment.new(@environment) do
+        node.children.map {|c| visit(c)}
+      end.flatten
+    elsif node.else
+      visit(node.else)
+    else
+      []
+    end
+  end
+
+  # Returns a static DirectiveNode if this is importing a CSS file,
+  # or parses and includes the imported Sass file.
+  def visit_import(node)
+    if (path = node.css_import?)
+      resolved_node = Sass::Tree::CssImportNode.resolved("url(#{path})")
+      resolved_node.source_range = node.source_range
+      return resolved_node
+    end
+    file = node.imported_file
+    if @environment.stack.frames.any? {|f| f.is_import? && f.filename == file.options[:filename]}
+      handle_import_loop!(node)
+    end
+
+    begin
+      @environment.stack.with_import(node.filename, node.line) do
+        root = file.to_tree
+        Sass::Tree::Visitors::CheckNesting.visit(root)
+        node.children = root.children.map {|c| visit(c)}.flatten
+        node
+      end
+    rescue Sass::SyntaxError => e
+      e.modify_backtrace(:filename => node.imported_file.options[:filename])
+      e.add_backtrace(:filename => node.filename, :line => node.line)
+      raise e
+    end
+  end
+
+  # Loads a mixin into the environment.
+  def visit_mixindef(node)
+    env = Sass::Environment.new(@environment, node.options)
+    @environment.set_local_mixin(node.name,
+      Sass::Callable.new(node.name, node.args, node.splat, env,
+                         node.children, node.has_content, "mixin"))
+    []
+  end
+
+  # Runs a mixin.
+  def visit_mixin(node)
+    @environment.stack.with_mixin(node.filename, node.line, node.name) do
+      mixin = @environment.mixin(node.name)
+      raise Sass::SyntaxError.new("Undefined mixin '#{node.name}'.") unless mixin
+
+      if node.children.any? && !mixin.has_content
+        raise Sass::SyntaxError.new(%Q{Mixin "#{node.name}" does not accept a content block.})
+      end
+
+      args = node.args.map {|a| a.perform(@environment)}
+      keywords = Sass::Util.map_vals(node.keywords) {|v| v.perform(@environment)}
+      splat = self.class.perform_splat(node.splat, keywords, node.kwarg_splat, @environment)
+
+      self.class.perform_arguments(mixin, args, splat, @environment) do |env|
+        env.caller = Sass::Environment.new(@environment)
+        env.content = [node.children, @environment] if node.has_children
+
+        trace_node = Sass::Tree::TraceNode.from_node(node.name, node)
+        with_environment(env) {trace_node.children = mixin.tree.map {|c| visit(c)}.flatten}
+        trace_node
+      end
+    end
+  rescue Sass::SyntaxError => e
+    e.modify_backtrace(:mixin => node.name, :line => node.line)
+    e.add_backtrace(:line => node.line)
+    raise e
+  end
+
+  def visit_content(node)
+    content, content_env = @environment.content
+    return [] unless content
+    @environment.stack.with_mixin(node.filename, node.line, '@content') do
+      trace_node = Sass::Tree::TraceNode.from_node('@content', node)
+      content_env = Sass::Environment.new(content_env)
+      content_env.caller = Sass::Environment.new(@environment)
+      with_environment(content_env) do
+        trace_node.children = content.map {|c| visit(c.dup)}.flatten
+      end
+      trace_node
+    end
+  rescue Sass::SyntaxError => e
+    e.modify_backtrace(:mixin => '@content', :line => node.line)
+    e.add_backtrace(:line => node.line)
+    raise e
+  end
+
+  # Runs any SassScript that may be embedded in a property.
+  def visit_prop(node)
+    node.resolved_name = run_interp(node.name)
+    val = node.value.perform(@environment)
+    node.resolved_value = val.to_s
+    node.value_source_range = val.source_range if val.source_range
+    yield
+  end
+
+  # Returns the value of the expression.
+  def visit_return(node)
+    throw :_sass_return, node.expr.perform(@environment)
+  end
+
+  # Runs SassScript interpolation in the selector,
+  # and then parses the result into a {Sass::Selector::CommaSequence}.
+  def visit_rule(node)
+    old_at_root_without_rule = @at_root_without_rule
+    parser = Sass::SCSS::StaticParser.new(run_interp(node.rule),
+      node.filename, node.options[:importer], node.line)
+    if @in_keyframes
+      keyframe_rule_node = Sass::Tree::KeyframeRuleNode.new(parser.parse_keyframes_selector)
+      keyframe_rule_node.options = node.options
+      keyframe_rule_node.line = node.line
+      keyframe_rule_node.filename = node.filename
+      keyframe_rule_node.source_range = node.source_range
+      keyframe_rule_node.has_children = node.has_children
+      with_environment Sass::Environment.new(@environment, node.options) do
+        keyframe_rule_node.children = node.children.map {|c| visit(c)}.flatten
+      end
+      keyframe_rule_node
+    else
+      @at_root_without_rule = false
+      node.parsed_rules ||= parser.parse_selector
+      node.resolved_rules = node.parsed_rules.resolve_parent_refs(
+        @environment.selector, !old_at_root_without_rule)
+      node.stack_trace = @environment.stack.to_s if node.options[:trace_selectors]
+      with_environment Sass::Environment.new(@environment, node.options) do
+        @environment.selector = node.resolved_rules
+        node.children = node.children.map {|c| visit(c)}.flatten
+      end
+      node
+    end
+  ensure
+    @at_root_without_rule = old_at_root_without_rule
+  end
+
+  # Sets a variable that indicates that the first level of rule nodes
+  # shouldn't include the parent selector by default.
+  def visit_atroot(node)
+    if node.query
+      parser = Sass::SCSS::StaticParser.new(run_interp(node.query),
+        node.filename, node.options[:importer], node.line)
+      node.resolved_type, node.resolved_value = parser.parse_static_at_root_query
+    else
+      node.resolved_type, node.resolved_value = :without, ['rule']
+    end
+
+    old_at_root_without_rule = @at_root_without_rule
+    old_in_keyframes = @in_keyframes
+    @at_root_without_rule = true if node.exclude?('rule')
+    @in_keyframes = false if node.exclude?('keyframes')
+    yield
+  ensure
+    @in_keyframes = old_in_keyframes
+    @at_root_without_rule = old_at_root_without_rule
+  end
+
+  # Loads the new variable value into the environment.
+  def visit_variable(node)
+    env = @environment
+    env = env.global_env if node.global
+    if node.guarded
+      var = env.var(node.name)
+      return [] if var && !var.null?
+    end
+
+    val = node.expr.perform(@environment)
+    if node.expr.source_range
+      val.source_range = node.expr.source_range
+    else
+      val.source_range = node.source_range
+    end
+    env.set_var(node.name, val)
+    []
+  end
+
+  # Prints the expression to STDERR with a stylesheet trace.
+  def visit_warn(node)
+    res = node.expr.perform(@environment)
+    res = res.value if res.is_a?(Sass::Script::Value::String)
+    msg = "WARNING: #{res}\n         "
+    msg << @environment.stack.to_s.gsub("\n", "\n         ") << "\n"
+    Sass::Util.sass_warn msg
+    []
+  end
+
+  # Runs the child nodes until the continuation expression becomes false.
+  def visit_while(node)
+    children = []
+    with_environment Sass::SemiGlobalEnvironment.new(@environment) do
+      children += node.children.map {|c| visit(c)} while node.expr.perform(@environment).to_bool
+    end
+    children.flatten
+  end
+
+  def visit_directive(node)
+    node.resolved_value = run_interp(node.value)
+    old_in_keyframes, @in_keyframes = @in_keyframes, node.normalized_name == "@keyframes"
+    with_environment Sass::Environment.new(@environment) do
+      node.children = node.children.map {|c| visit(c)}.flatten
+      node
+    end
+  ensure
+    @in_keyframes = old_in_keyframes
+  end
+
+  def visit_media(node)
+    parser = Sass::SCSS::StaticParser.new(run_interp(node.query),
+      node.filename, node.options[:importer], node.line)
+    node.resolved_query ||= parser.parse_media_query_list
+    yield
+  end
+
+  def visit_supports(node)
+    node.condition = node.condition.deep_copy
+    node.condition.perform(@environment)
+    yield
+  end
+
+  def visit_cssimport(node)
+    node.resolved_uri = run_interp([node.uri])
+    if node.query && !node.query.empty?
+      parser = Sass::SCSS::StaticParser.new(run_interp(node.query),
+        node.filename, node.options[:importer], node.line)
+      node.resolved_query ||= parser.parse_media_query_list
+    end
+    yield
+  end
+
+  private
+
+  def run_interp_no_strip(text)
+    text.map do |r|
+      next r if r.is_a?(String)
+      r.perform(@environment).to_s(:quote => :none)
+    end.join
+  end
+
+  def run_interp(text)
+    run_interp_no_strip(text).strip
+  end
+
+  def handle_import_loop!(node)
+    msg = "An @import loop has been found:"
+    files = @environment.stack.frames.select {|f| f.is_import?}.map {|f| f.filename}.compact
+    if node.filename == node.imported_file.options[:filename]
+      raise Sass::SyntaxError.new("#{msg} #{node.filename} imports itself")
+    end
+
+    files << node.filename << node.imported_file.options[:filename]
+    msg << "\n" << Sass::Util.enum_cons(files, 2).map do |m1, m2|
+      "    #{m1} imports #{m2}"
+    end.join("\n")
+    raise Sass::SyntaxError.new(msg)
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/set_options.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/set_options.rb
new file mode 100644
index 0000000..48cd946
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/set_options.rb
@@ -0,0 +1,139 @@
+# A visitor for setting options on the Sass tree
+class Sass::Tree::Visitors::SetOptions < Sass::Tree::Visitors::Base
+  # @param root [Tree::Node] The root node of the tree to visit.
+  # @param options [{Symbol => Object}] The options has to set.
+  def self.visit(root, options); new(options).send(:visit, root); end
+
+  protected
+
+  def initialize(options)
+    @options = options
+  end
+
+  def visit(node)
+    node.instance_variable_set('@options', @options)
+    super
+  end
+
+  def visit_comment(node)
+    node.value.each {|c| c.options = @options if c.is_a?(Sass::Script::Tree::Node)}
+    yield
+  end
+
+  def visit_debug(node)
+    node.expr.options = @options
+    yield
+  end
+
+  def visit_error(node)
+    node.expr.options = @options
+    yield
+  end
+
+  def visit_each(node)
+    node.list.options = @options
+    yield
+  end
+
+  def visit_extend(node)
+    node.selector.each {|c| c.options = @options if c.is_a?(Sass::Script::Tree::Node)}
+    yield
+  end
+
+  def visit_for(node)
+    node.from.options = @options
+    node.to.options = @options
+    yield
+  end
+
+  def visit_function(node)
+    node.args.each do |k, v|
+      k.options = @options
+      v.options = @options if v
+    end
+    node.splat.options = @options if node.splat
+    yield
+  end
+
+  def visit_if(node)
+    node.expr.options = @options if node.expr
+    visit(node.else) if node.else
+    yield
+  end
+
+  def visit_import(node)
+    # We have no good way of propagating the new options through an Engine
+    # instance, so we just null it out. This also lets us avoid caching an
+    # imported Engine along with the importing source tree.
+    node.imported_file = nil
+    yield
+  end
+
+  def visit_mixindef(node)
+    node.args.each do |k, v|
+      k.options = @options
+      v.options = @options if v
+    end
+    node.splat.options = @options if node.splat
+    yield
+  end
+
+  def visit_mixin(node)
+    node.args.each {|a| a.options = @options}
+    node.keywords.each {|k, v| v.options = @options}
+    node.splat.options = @options if node.splat
+    node.kwarg_splat.options = @options if node.kwarg_splat
+    yield
+  end
+
+  def visit_prop(node)
+    node.name.each {|c| c.options = @options if c.is_a?(Sass::Script::Tree::Node)}
+    node.value.options = @options
+    yield
+  end
+
+  def visit_return(node)
+    node.expr.options = @options
+    yield
+  end
+
+  def visit_rule(node)
+    node.rule.each {|c| c.options = @options if c.is_a?(Sass::Script::Tree::Node)}
+    yield
+  end
+
+  def visit_variable(node)
+    node.expr.options = @options
+    yield
+  end
+
+  def visit_warn(node)
+    node.expr.options = @options
+    yield
+  end
+
+  def visit_while(node)
+    node.expr.options = @options
+    yield
+  end
+
+  def visit_directive(node)
+    node.value.each {|c| c.options = @options if c.is_a?(Sass::Script::Tree::Node)}
+    yield
+  end
+
+  def visit_media(node)
+    node.query.each {|c| c.options = @options if c.is_a?(Sass::Script::Tree::Node)}
+    yield
+  end
+
+  def visit_cssimport(node)
+    node.query.each {|c| c.options = @options if c.is_a?(Sass::Script::Tree::Node)} if node.query
+    yield
+  end
+
+  def visit_supports(node)
+    node.condition.options = @options
+    yield
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/to_css.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/to_css.rb
new file mode 100644
index 0000000..0d5c03a
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/visitors/to_css.rb
@@ -0,0 +1,381 @@
+# A visitor for converting a Sass tree into CSS.
+class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
+  # The source mapping for the generated CSS file. This is only set if
+  # `build_source_mapping` is passed to the constructor and \{Sass::Engine#render} has been
+  # run.
+  attr_reader :source_mapping
+
+  # @param build_source_mapping [Boolean] Whether to build a
+  #   \{Sass::Source::Map} while creating the CSS output. The mapping will
+  #   be available from \{#source\_mapping} after the visitor has completed.
+  def initialize(build_source_mapping = false)
+    @tabs = 0
+    @line = 1
+    @offset = 1
+    @result = ""
+    @source_mapping = Sass::Source::Map.new if build_source_mapping
+  end
+
+  # Runs the visitor on `node`.
+  #
+  # @param node [Sass::Tree::Node] The root node of the tree to convert to CSS>
+  # @return [String] The CSS output.
+  def visit(node)
+    super
+  rescue Sass::SyntaxError => e
+    e.modify_backtrace(:filename => node.filename, :line => node.line)
+    raise e
+  end
+
+  protected
+
+  def with_tabs(tabs)
+    old_tabs, @tabs = @tabs, tabs
+    yield
+  ensure
+    @tabs = old_tabs
+  end
+
+  # Associate all output produced in a block with a given node. Used for source
+  # mapping.
+  def for_node(node, attr_prefix = nil)
+    return yield unless @source_mapping
+    start_pos = Sass::Source::Position.new(@line, @offset)
+    yield
+
+    range_attr = attr_prefix ? :"#{attr_prefix}_source_range" : :source_range
+    return if node.invisible? || !node.send(range_attr)
+    source_range = node.send(range_attr)
+    target_end_pos = Sass::Source::Position.new(@line, @offset)
+    target_range = Sass::Source::Range.new(start_pos, target_end_pos, nil)
+    @source_mapping.add(source_range, target_range)
+  end
+
+  # Move the output cursor back `chars` characters.
+  def erase!(chars)
+    return if chars == 0
+    str = @result.slice!(-chars..-1)
+    newlines = str.count("\n")
+    if newlines > 0
+      @line -= newlines
+      @offset = @result[ result rindex("\n") || 0..-1].size
+    else
+      @offset -= chars
+    end
+  end
+
+  # Avoid allocating lots of new strings for `#output`. This is important
+  # because `#output` is called all the time.
+  NEWLINE = "\n"
+
+  # Add `s` to the output string and update the line and offset information
+  # accordingly.
+  def output(s)
+    if @lstrip
+      s = s.gsub(/\A\s+/, "")
+      @lstrip = false
+    end
+
+    newlines = s.count(NEWLINE)
+    if newlines > 0
+      @line += newlines
+      @offset = s[s.rindex(NEWLINE)..-1].size
+    else
+      @offset += s.size
+    end
+
+    @result << s
+  end
+
+  # Strip all trailing whitespace from the output string.
+  def rstrip!
+    erase! @result.length - 1 - (@result.rindex(/[^\s]/) || -1)
+  end
+
+  # lstrip the first output in the given block.
+  def lstrip
+    old_lstrip = @lstrip
+    @lstrip = true
+    yield
+  ensure
+    @lstrip = @lstrip && old_lstrip
+  end
+
+  # Prepend `prefix` to the output string.
+  def prepend!(prefix)
+    @result.insert 0, prefix
+    return unless @source_mapping
+
+    line_delta = prefix.count("\n")
+    offset_delta = prefix.gsub(/.*\n/, '').size
+    @source_mapping.shift_output_offsets(offset_delta)
+    @source_mapping.shift_output_lines(line_delta)
+  end
+
+  def visit_root(node)
+    node.children.each do |child|
+      next if child.invisible?
+      visit(child)
+      unless node.style == :compressed
+        output "\n"
+        if child.is_a?(Sass::Tree::DirectiveNode) && child.has_children && !child.bubbles?
+          output "\n"
+        end
+      end
+    end
+    rstrip!
+    return "" if @result.empty?
+
+    output "\n"
+
+    unless Sass::Util.ruby1_8? || @result.ascii_only?
+      if node.style == :compressed
+        # A byte order mark is sufficient to tell browsers that this
+        # file is UTF-8 encoded, and will override any other detection
+        # methods as per http://encoding.spec.whatwg.org/#decode-and-encode.
+        prepend! "\uFEFF"
+      else
+        prepend! "@charset \"UTF-8\";\n"
+      end
+    end
+
+    @result
+  rescue Sass::SyntaxError => e
+    e.sass_template ||= node.template
+    raise e
+  end
+
+  def visit_charset(node)
+    for_node(node) {output("@charset \"#{node.name}\";")}
+  end
+
+  def visit_comment(node)
+    return if node.invisible?
+    spaces = ('  ' * [ tabs - node.resolved_value[/^ */].size, 0].max)
+
+    content = node.resolved_value.gsub(/^/, spaces)
+    if node.type == :silent
+      content.gsub!(%r{^(\s*)//(.*)$}) {|md| "#{$1}/*#{$2} */"}
+    end
+    if (node.style == :compact || node.style == :compressed) && node.type != :loud
+      content.gsub!(/\n +(\* *(?!\/))?/, ' ')
+    end
+    for_node(node) {output(content)}
+  end
+
+  # @comment
+  #   rubocop:disable MethodLength
+  def visit_directive(node)
+    was_in_directive = @in_directive
+    tab_str = '  ' * @tabs
+    if !node.has_children || node.children.empty?
+      output(tab_str)
+      for_node(node) {output(node.resolved_value)}
+      output(!node.has_children ? ";" : " {}")
+      return
+    end
+
+    @in_directive = @in_directive || !node.is_a?(Sass::Tree::MediaNode)
+    output(tab_str) if node.style != :compressed
+    for_node(node) {output(node.resolved_value)}
+    output(node.style == :compressed ? "{" : " {")
+    output(node.style == :compact ? ' ' : "\n") if node.style != :compressed
+
+    was_prop = false
+    first = true
+    node.children.each do |child|
+      next if child.invisible?
+      if node.style == :compact
+        if child.is_a?(Sass::Tree::PropNode)
+          with_tabs(first || was_prop ? 0 : @tabs + 1) do
+            visit(child)
+            output(' ')
+          end
+        else
+          if was_prop
+            erase! 1
+            output "\n"
+          end
+
+          if first
+            lstrip {with_tabs(@tabs + 1) {visit(child)}}
+          else
+            with_tabs(@tabs + 1) {visit(child)}
+          end
+
+          rstrip!
+          output "\n"
+        end
+        was_prop = child.is_a?(Sass::Tree::PropNode)
+        first = false
+      elsif node.style == :compressed
+        output(was_prop ? ";" : "")
+        with_tabs(0) {visit(child)}
+        was_prop = child.is_a?(Sass::Tree::PropNode)
+      else
+        with_tabs(@tabs + 1) {visit(child)}
+        output "\n"
+      end
+    end
+    rstrip!
+    if node.style == :expanded
+      output("\n#{tab_str}")
+    elsif node.style != :compressed
+      output(" ")
+    end
+    output("}")
+  ensure
+    @in_directive = was_in_directive
+  end
+  # @comment
+  #   rubocop:enable MethodLength
+
+  def visit_media(node)
+    with_tabs(@tabs + node.tabs) {visit_directive(node)}
+    output("\n") if node.style != :compressed && node.group_end
+  end
+
+  def visit_supports(node)
+    visit_media(node)
+  end
+
+  def visit_cssimport(node)
+    visit_directive(node)
+  end
+
+  def visit_prop(node)
+    return if node.resolved_value.empty?
+    tab_str = '  ' * (@tabs + node.tabs)
+    output(tab_str)
+    for_node(node, :name) {output(node.resolved_name)}
+    if node.style == :compressed
+      output(":")
+      for_node(node, :value) {output(node.resolved_value)}
+    else
+      output(": ")
+      for_node(node, :value) {output(node.resolved_value)}
+      output(";")
+    end
+  end
+
+  # @comment
+  #   rubocop:disable MethodLength
+  def visit_rule(node)
+    with_tabs(@tabs + node.tabs) do
+      rule_separator = node.style == :compressed ? ',' : ', '
+      line_separator =
+        case node.style
+        when :nested, :expanded; "\n"
+        when :compressed; ""
+        else; " "
+        end
+      rule_indent = '  ' * @tabs
+      per_rule_indent, total_indent = if [:nested, :expanded].include?(node.style)
+                                        [rule_indent, '']
+                                      else
+                                        ['', rule_indent]
+                                      end
+
+      joined_rules = node.resolved_rules.members.map do |seq|
+        next if seq.has_placeholder?
+        rule_part = seq.to_s
+        if node.style == :compressed
+          rule_part.gsub!(/([^,])\s*\n\s*/m, '\1 ')
+          rule_part.gsub!(/\s*([,+>])\s*/m, '\1')
+          rule_part.strip!
+        end
+        rule_part
+      end.compact.join(rule_separator)
+
+      joined_rules.lstrip!
+      joined_rules.gsub!(/\s*\n\s*/, "#{line_separator}#{per_rule_indent}")
+
+      old_spaces = '  ' * @tabs
+      if node.style != :compressed
+        if node.options[:debug_info] && ! in_directive
+          visit(debug_info_rule(node.debug_info, node.options))
+          output "\n"
+        elsif node.options[:trace_selectors]
+          output("#{old_spaces}/* ")
+          output(node.stack_trace.gsub("\n", "\n   #{old_spaces}"))
+          output(" */\n")
+        elsif node.options[:line_comments]
+          output("#{old_spaces}/* line #{node.line}")
+
+          if node.filename
+            relative_filename =
+              if node.options[:css_filename]
+                begin
+                  Sass::Util.relative_path_from(
+                    node.filename, File.dirname(node.options[:css_filename])).to_s
+                rescue ArgumentError
+                  nil
+                end
+              end
+            relative_filename ||= node.filename
+            output(", #{relative_filename}")
+          end
+
+          output(" */\n")
+        end
+      end
+
+      end_props, trailer, tabs  = '', '', 0
+      if node.style == :compact
+        separator, end_props, bracket = ' ', ' ', ' { '
+        trailer = "\n" if node.group_end
+      elsif node.style == :compressed
+        separator, bracket = ';', '{'
+      else
+        tabs = @tabs + 1
+        separator, bracket = "\n", " {\n"
+        trailer = "\n" if node.group_end
+        end_props = (node.style == :expanded ? "\n" + old_spaces : ' ')
+      end
+      output(total_indent + per_rule_indent)
+      for_node(node, :selector) {output(joined_rules)}
+      output(bracket)
+
+      with_tabs(tabs) do
+        node.children.each_with_index do |child, i|
+          output(separator) if i > 0
+          visit(child)
+        end
+      end
+
+      output(end_props)
+      output("}" + trailer)
+    end
+  end
+  # @comment
+  #   rubocop:enable MethodLength
+
+  def visit_keyframerule(node)
+    visit_directive(node)
+  end
+
+  private
+
+  def debug_info_rule(debug_info, options)
+    node = Sass::Tree::DirectiveNode.resolved("@media -sass-debug-info")
+    Sass::Util.hash_to_a(debug_info.map {|k, v| [k.to_s, v.to_s]}).each do |k, v|
+      rule = Sass::Tree::RuleNode.new([""])
+      rule.resolved_rules = Sass::Selector::CommaSequence.new(
+        [Sass::Selector::Sequence.new(
+            [Sass::Selector::SimpleSequence.new(
+                [Sass::Selector::Element.new(k.to_s.gsub(/[^\w-]/, "\\\\\\0"), nil)],
+                false)
+            ])
+        ])
+      prop = Sass::Tree::PropNode.new([""], Sass::Script::Value::String.new(''), :new)
+      prop.resolved_name = "font-family"
+      prop.resolved_value = Sass::SCSS::RX.escape_ident(v.to_s)
+      rule << prop
+      node << rule
+    end
+    node.options = options.merge(:debug_info => false,
+                                 :line_comments => false,
+                                 :style => :compressed)
+    node
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/warn_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/warn_node.rb
new file mode 100644
index 0000000..4af4789
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/warn_node.rb
@@ -0,0 +1,18 @@
+module Sass
+  module Tree
+    # A dynamic node representing a Sass ` warn` statement.
+    #
+    # @see Sass::Tree
+    class WarnNode < Node
+      # The expression to print.
+      # @return [Script::Tree::Node]
+      attr_accessor :expr
+
+      # @param expr [Script::Tree::Node] The expression to print
+      def initialize(expr)
+        @expr = expr
+        super()
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/tree/while_node.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/tree/while_node.rb
new file mode 100644
index 0000000..93529f0
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/tree/while_node.rb
@@ -0,0 +1,18 @@
+require 'sass/tree/node'
+
+module Sass::Tree
+  # A dynamic node representing a Sass ` while` loop.
+  #
+  # @see Sass::Tree
+  class WhileNode < Node
+    # The parse tree for the continuation expression.
+    # @return [Script::Tree::Node]
+    attr_accessor :expr
+
+    # @param expr [Script::Tree::Node] See \{#expr}
+    def initialize(expr)
+      @expr = expr
+      super()
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/util.rb b/backends/css/gems/sass-3.4.9/lib/sass/util.rb
new file mode 100644
index 0000000..4fcc45f
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/util.rb
@@ -0,0 +1,1376 @@
+# -*- coding: utf-8 -*-
+require 'erb'
+require 'set'
+require 'enumerator'
+require 'stringio'
+require 'rbconfig'
+require 'uri'
+require 'thread'
+require 'pathname'
+
+require 'sass/root'
+require 'sass/util/subset_map'
+
+module Sass
+  # A module containing various useful functions.
+  module Util
+    extend self
+
+    # An array of ints representing the Ruby version number.
+    # @api public
+    RUBY_VERSION_COMPONENTS = RUBY_VERSION.split(".").map {|s| s.to_i}
+
+    # The Ruby engine we're running under. Defaults to `"ruby"`
+    # if the top-level constant is undefined.
+    # @api public
+    RUBY_ENGINE = defined?(::RUBY_ENGINE) ? ::RUBY_ENGINE : "ruby"
+
+    # Returns the path of a file relative to the Sass root directory.
+    #
+    # @param file [String] The filename relative to the Sass root
+    # @return [String] The filename relative to the the working directory
+    def scope(file)
+      File.join(Sass::ROOT_DIR, file)
+    end
+
+    # Converts an array of `[key, value]` pairs to a hash.
+    #
+    # @example
+    #   to_hash([[:foo, "bar"], [:baz, "bang"]])
+    #     #=> {:foo => "bar", :baz => "bang"}
+    # @param arr [Array<(Object, Object)>] An array of pairs
+    # @return [Hash] A hash
+    def to_hash(arr)
+      ordered_hash(*arr.compact)
+    end
+
+    # Maps the keys in a hash according to a block.
+    #
+    # @example
+    #   map_keys({:foo => "bar", :baz => "bang"}) {|k| k.to_s}
+    #     #=> {"foo" => "bar", "baz" => "bang"}
+    # @param hash [Hash] The hash to map
+    # @yield [key] A block in which the keys are transformed
+    # @yieldparam key [Object] The key that should be mapped
+    # @yieldreturn [Object] The new value for the key
+    # @return [Hash] The mapped hash
+    # @see #map_vals
+    # @see #map_hash
+    def map_keys(hash)
+      map_hash(hash) {|k, v| [yield(k), v]}
+    end
+
+    # Maps the values in a hash according to a block.
+    #
+    # @example
+    #   map_values({:foo => "bar", :baz => "bang"}) {|v| v.to_sym}
+    #     #=> {:foo => :bar, :baz => :bang}
+    # @param hash [Hash] The hash to map
+    # @yield [value] A block in which the values are transformed
+    # @yieldparam value [Object] The value that should be mapped
+    # @yieldreturn [Object] The new value for the value
+    # @return [Hash] The mapped hash
+    # @see #map_keys
+    # @see #map_hash
+    def map_vals(hash)
+      # We don't delegate to map_hash for performance here
+      # because map_hash does more than is necessary.
+      rv = hash.class.new
+      hash = hash.as_stored if hash.is_a?(NormalizedMap)
+      hash.each do |k, v|
+        rv[k] = yield(v)
+      end
+      rv
+    end
+
+    # Maps the key-value pairs of a hash according to a block.
+    #
+    # @example
+    #   map_hash({:foo => "bar", :baz => "bang"}) {|k, v| [k.to_s, v.to_sym]}
+    #     #=> {"foo" => :bar, "baz" => :bang}
+    # @param hash [Hash] The hash to map
+    # @yield [key, value] A block in which the key-value pairs are transformed
+    # @yieldparam [key] The hash key
+    # @yieldparam [value] The hash value
+    # @yieldreturn [(Object, Object)] The new value for the `[key, value]` pair
+    # @return [Hash] The mapped hash
+    # @see #map_keys
+    # @see #map_vals
+    def map_hash(hash)
+      # Copy and modify is more performant than mapping to an array and using
+      # to_hash on the result.
+      rv = hash.class.new
+      hash.each do |k, v|
+        new_key, new_value = yield(k, v)
+        new_key = hash.denormalize(new_key) if hash.is_a?(NormalizedMap) && new_key == k
+        rv[new_key] = new_value
+      end
+      rv
+    end
+
+    # Computes the powerset of the given array.
+    # This is the set of all subsets of the array.
+    #
+    # @example
+    #   powerset([1, 2, 3]) #=>
+    #     Set[Set[], Set[1], Set[2], Set[3], Set[1, 2], Set[2, 3], Set[1, 3], Set[1, 2, 3]]
+    # @param arr [Enumerable]
+    # @return [Set<Set>] The subsets of `arr`
+    def powerset(arr)
+      arr.inject([Set.new].to_set) do |powerset, el|
+        new_powerset = Set.new
+        powerset.each do |subset|
+          new_powerset << subset
+          new_powerset << subset + [el]
+        end
+        new_powerset
+      end
+    end
+
+    # Restricts a number to falling within a given range.
+    # Returns the number if it falls within the range,
+    # or the closest value in the range if it doesn't.
+    #
+    # @param value [Numeric]
+    # @param range [Range<Numeric>]
+    # @return [Numeric]
+    def restrict(value, range)
+      [[value, range.first].max, range.last].min
+    end
+
+    # Concatenates all strings that are adjacent in an array,
+    # while leaving other elements as they are.
+    #
+    # @example
+    #   merge_adjacent_strings([1, "foo", "bar", 2, "baz"])
+    #     #=> [1, "foobar", 2, "baz"]
+    # @param arr [Array]
+    # @return [Array] The enumerable with strings merged
+    def merge_adjacent_strings(arr)
+      # Optimize for the common case of one element
+      return arr if arr.size < 2
+      arr.inject([]) do |a, e|
+        if e.is_a?(String)
+          if a.last.is_a?(String)
+            a.last << e
+          else
+            a << e.dup
+          end
+        else
+          a << e
+        end
+        a
+      end
+    end
+
+    # Non-destructively replaces all occurrences of a subsequence in an array
+    # with another subsequence.
+    #
+    # @example
+    #   replace_subseq([1, 2, 3, 4, 5], [2, 3], [:a, :b])
+    #     #=> [1, :a, :b, 4, 5]
+    #
+    # @param arr [Array] The array whose subsequences will be replaced.
+    # @param subseq [Array] The subsequence to find and replace.
+    # @param replacement [Array] The sequence that `subseq` will be replaced with.
+    # @return [Array] `arr` with `subseq` replaced with `replacement`.
+    def replace_subseq(arr, subseq, replacement)
+      new = []
+      matched = []
+      i = 0
+      arr.each do |elem|
+        if elem != subseq[i]
+          new.push(*matched)
+          matched = []
+          i = 0
+          new << elem
+          next
+        end
+
+        if i == subseq.length - 1
+          matched = []
+          i = 0
+          new.push(*replacement)
+        else
+          matched << elem
+          i += 1
+        end
+      end
+      new.push(*matched)
+      new
+    end
+
+    # Intersperses a value in an enumerable, as would be done with `Array#join`
+    # but without concatenating the array together afterwards.
+    #
+    # @param enum [Enumerable]
+    # @param val
+    # @return [Array]
+    def intersperse(enum, val)
+      enum.inject([]) {|a, e| a << e << val}[0...-1]
+    end
+
+    def slice_by(enum)
+      results = []
+      enum.each do |value|
+        key = yield(value)
+        if !results.empty? && results.last.first == key
+          results.last.last << value
+        else
+          results << [key, [value]]
+        end
+      end
+      results
+    end
+
+    # Substitutes a sub-array of one array with another sub-array.
+    #
+    # @param ary [Array] The array in which to make the substitution
+    # @param from [Array] The sequence of elements to replace with `to`
+    # @param to [Array] The sequence of elements to replace `from` with
+    def substitute(ary, from, to)
+      res = ary.dup
+      i = 0
+      while i < res.size
+        if res[i...i + from.size] == from
+          res[i...i + from.size] = to
+        end
+        i += 1
+      end
+      res
+    end
+
+    # Destructively strips whitespace from the beginning and end
+    # of the first and last elements, respectively,
+    # in the array (if those elements are strings).
+    #
+    # @param arr [Array]
+    # @return [Array] `arr`
+    def strip_string_array(arr)
+      arr.first.lstrip! if arr.first.is_a?(String)
+      arr.last.rstrip! if arr.last.is_a?(String)
+      arr
+    end
+
+    # Return an array of all possible paths through the given arrays.
+    #
+    # @param arrs [Array<Array>]
+    # @return [Array<Arrays>]
+    #
+    # @example
+    #   paths([[1, 2], [3, 4], [5]]) #=>
+    #     # [[1, 3, 5],
+    #     #  [2, 3, 5],
+    #     #  [1, 4, 5],
+    #     #  [2, 4, 5]]
+    def paths(arrs)
+      arrs.inject([[]]) do |paths, arr|
+        flatten(arr.map {|e| paths.map {|path| path + [e]}}, 1)
+      end
+    end
+
+    # Computes a single longest common subsequence for `x` and `y`.
+    # If there are more than one longest common subsequences,
+    # the one returned is that which starts first in `x`.
+    #
+    # @param x [Array]
+    # @param y [Array]
+    # @yield [a, b] An optional block to use in place of a check for equality
+    #   between elements of `x` and `y`.
+    # @yieldreturn [Object, nil] If the two values register as equal,
+    #   this will return the value to use in the LCS array.
+    # @return [Array] The LCS
+    def lcs(x, y, &block)
+      x = [nil, *x]
+      y = [nil, *y]
+      block ||= proc {|a, b| a == b && a}
+      lcs_backtrace(lcs_table(x, y, &block), x, y, x.size - 1, y.size - 1, &block)
+    end
+
+    # Converts a Hash to an Array. This is usually identical to `Hash#to_a`,
+    # with the following exceptions:
+    #
+    # * In Ruby 1.8, `Hash#to_a` is not deterministically ordered, but this is.
+    # * In Ruby 1.9 when running tests, this is ordered in the same way it would
+    #   be under Ruby 1.8 (sorted key order rather than insertion order).
+    #
+    # @param hash [Hash]
+    # @return [Array]
+    def hash_to_a(hash)
+      return hash.to_a unless ruby1_8? || defined?(Test::Unit)
+      hash.sort_by {|k, v| k}
+    end
+
+    # Performs the equivalent of `enum.group_by.to_a`, but with a guaranteed
+    # order. Unlike {Util#hash_to_a}, the resulting order isn't sorted key order;
+    # instead, it's the same order as `#group_by` has under Ruby 1.9 (key
+    # appearance order).
+    #
+    # @param enum [Enumerable]
+    # @return [Array<[Object, Array]>] An array of pairs.
+    def group_by_to_a(enum)
+      return enum.group_by {|e| yield(e)}.to_a unless ruby1_8?
+      order = {}
+      arr = []
+      groups = enum.group_by do |e|
+        res = yield(e)
+        unless order.include?(res)
+          order[res] = order.size
+        end
+        res
+      end
+      groups.each do |key, vals|
+        arr[order[key]] = [key, vals]
+      end
+      arr
+    end
+
+    # Returns a sub-array of `minuend` containing only elements that are also in
+    # `subtrahend`. Ensures that the return value has the same order as
+    # `minuend`, even on Rubinius where that's not guaranteed by `Array#-`.
+    #
+    # @param minuend [Array]
+    # @param subtrahend [Array]
+    # @return [Array]
+    def array_minus(minuend, subtrahend)
+      return minuend - subtrahend unless rbx?
+      set = Set.new(minuend) - subtrahend
+      minuend.select {|e| set.include?(e)}
+    end
+
+    # Returns the maximum of `val1` and `val2`. We use this over \{Array.max} to
+    # avoid unnecessary garbage collection.
+    def max(val1, val2)
+      val1 > val2 ? val1 : val2
+    end
+
+    # Returns the minimum of `val1` and `val2`. We use this over \{Array.min} to
+    # avoid unnecessary garbage collection.
+    def min(val1, val2)
+      val1 <= val2 ? val1 : val2
+    end
+
+    # Returns a string description of the character that caused an
+    # `Encoding::UndefinedConversionError`.
+    #
+    # @param e [Encoding::UndefinedConversionError]
+    # @return [String]
+    def undefined_conversion_error_char(e)
+      # Rubinius (as of 2.0.0.rc1) pre-quotes the error character.
+      return e.error_char if rbx?
+      # JRuby (as of 1.7.2) doesn't have an error_char field on
+      # Encoding::UndefinedConversionError.
+      return e.error_char.dump unless jruby?
+      e.message[/^"[^"]+"/] # "
+    end
+
+    # Asserts that `value` falls within `range` (inclusive), leaving
+    # room for slight floating-point errors.
+    #
+    # @param name [String] The name of the value. Used in the error message.
+    # @param range [Range] The allowed range of values.
+    # @param value [Numeric, Sass::Script::Value::Number] The value to check.
+    # @param unit [String] The unit of the value. Used in error reporting.
+    # @return [Numeric] `value` adjusted to fall within range, if it
+    #   was outside by a floating-point margin.
+    def check_range(name, range, value, unit = '')
+      grace = (-0.00001..0.00001)
+      str = value.to_s
+      value = value.value if value.is_a?(Sass::Script::Value::Number)
+      return value if range.include?(value)
+      return range.first if grace.include?(value - range.first)
+      return range.last if grace.include?(value - range.last)
+      raise ArgumentError.new(
+        "#{name} #{str} must be between #{range.first}#{unit} and #{range.last}#{unit}")
+    end
+
+    # Returns whether or not `seq1` is a subsequence of `seq2`. That is, whether
+    # or not `seq2` contains every element in `seq1` in the same order (and
+    # possibly more elements besides).
+    #
+    # @param seq1 [Array]
+    # @param seq2 [Array]
+    # @return [Boolean]
+    def subsequence?(seq1, seq2)
+      i = j = 0
+      loop do
+        return true if i == seq1.size
+        return false if j == seq2.size
+        i += 1 if seq1[i] == seq2[j]
+        j += 1
+      end
+    end
+
+    # Returns information about the caller of the previous method.
+    #
+    # @param entry [String] An entry in the `#caller` list, or a similarly formatted string
+    # @return [[String, Fixnum, (String, nil)]]
+    #   An array containing the filename, line, and method name of the caller.
+    #   The method name may be nil
+    def caller_info(entry = nil)
+      # JRuby evaluates `caller` incorrectly when it's in an actual default argument.
+      entry ||= caller[1]
+      info = entry.scan(/^((?:[A-Za-z]:)?.*?):(-?.*?)(?::.*`(.+)')?$/).first
+      info[1] = info[1].to_i
+      # This is added by Rubinius to designate a block, but we don't care about it.
+      info[2].sub!(/ \{\}\Z/, '') if info[2]
+      info
+    end
+
+    # Returns whether one version string represents a more recent version than another.
+    #
+    # @param v1 [String] A version string.
+    # @param v2 [String] Another version string.
+    # @return [Boolean]
+    def version_gt(v1, v2)
+      # Construct an array to make sure the shorter version is padded with nil
+      Array.new([v1.length, v2.length].max).zip(v1.split("."), v2.split(".")) do |_, p1, p2|
+        p1 ||= "0"
+        p2 ||= "0"
+        release1 = p1 =~ /^[0-9]+$/
+        release2 = p2 =~ /^[0-9]+$/
+        if release1 && release2
+          # Integer comparison if both are full releases
+          p1, p2 = p1.to_i, p2.to_i
+          next if p1 == p2
+          return p1 > p2
+        elsif !release1 && !release2
+          # String comparison if both are prereleases
+          next if p1 == p2
+          return p1 > p2
+        else
+          # If only one is a release, that one is newer
+          return release1
+        end
+      end
+    end
+
+    # Returns whether one version string represents the same or a more
+    # recent version than another.
+    #
+    # @param v1 [String] A version string.
+    # @param v2 [String] Another version string.
+    # @return [Boolean]
+    def version_geq(v1, v2)
+      version_gt(v1, v2) || !version_gt(v2, v1)
+    end
+
+    # Throws a NotImplementedError for an abstract method.
+    #
+    # @param obj [Object] `self`
+    # @raise [NotImplementedError]
+    def abstract(obj)
+      raise NotImplementedError.new("#{obj.class} must implement ##{caller_info[2]}")
+    end
+
+    # Prints a deprecation warning for the caller method.
+    #
+    # @param obj [Object] `self`
+    # @param message [String] A message describing what to do instead.
+    def deprecated(obj, message = nil)
+      obj_class = obj.is_a?(Class) ? "#{obj}." : "#{obj.class}#"
+      full_message = "DEPRECATION WARNING: #{obj_class}#{caller_info[2]} " +
+        "will be removed in a future version of Sass.#{("\n" + message) if message}"
+      Sass::Util.sass_warn full_message
+    end
+
+    # Silence all output to STDERR within a block.
+    #
+    # @yield A block in which no output will be printed to STDERR
+    def silence_warnings
+      the_real_stderr, $stderr = $stderr, StringIO.new
+      yield
+    ensure
+      $stderr = the_real_stderr
+    end
+
+    # Silences all Sass warnings within a block.
+    #
+    # @yield A block in which no Sass warnings will be printed
+    def silence_sass_warnings
+      old_level, Sass.logger.log_level = Sass.logger.log_level, :error
+      yield
+    ensure
+      Sass.logger.log_level = old_level
+    end
+
+    # The same as `Kernel#warn`, but is silenced by \{#silence\_sass\_warnings}.
+    #
+    # @param msg [String]
+    def sass_warn(msg)
+      msg = msg + "\n" unless ruby1?
+      Sass.logger.warn(msg)
+    end
+
+    ## Cross Rails Version Compatibility
+
+    # Returns the root of the Rails application,
+    # if this is running in a Rails context.
+    # Returns `nil` if no such root is defined.
+    #
+    # @return [String, nil]
+    def rails_root
+      if defined?(::Rails.root)
+        return ::Rails.root.to_s if ::Rails.root
+        raise "ERROR: Rails.root is nil!"
+      end
+      return RAILS_ROOT.to_s if defined?(RAILS_ROOT)
+      nil
+    end
+
+    # Returns the environment of the Rails application,
+    # if this is running in a Rails context.
+    # Returns `nil` if no such environment is defined.
+    #
+    # @return [String, nil]
+    def rails_env
+      return ::Rails.env.to_s if defined?(::Rails.env)
+      return RAILS_ENV.to_s if defined?(RAILS_ENV)
+      nil
+    end
+
+    # Returns whether this environment is using ActionPack
+    # version 3.0.0 or greater.
+    #
+    # @return [Boolean]
+    def ap_geq_3?
+      ap_geq?("3.0.0.beta1")
+    end
+
+    # Returns whether this environment is using ActionPack
+    # of a version greater than or equal to that specified.
+    #
+    # @param version [String] The string version number to check against.
+    #   Should be greater than or equal to Rails 3,
+    #   because otherwise ActionPack::VERSION isn't autoloaded
+    # @return [Boolean]
+    def ap_geq?(version)
+      # The ActionPack module is always loaded automatically in Rails >= 3
+      return false unless defined?(ActionPack) && defined?(ActionPack::VERSION) &&
+        defined?(ActionPack::VERSION::STRING)
+
+      version_geq(ActionPack::VERSION::STRING, version)
+    end
+
+    # Returns whether this environment is using Listen
+    # version 2.0.0 or greater.
+    #
+    # @return [Boolean]
+    def listen_geq_2?
+      return @listen_geq_2 unless @listen_geq_2.nil?
+      @listen_geq_2 =
+        begin
+          require 'listen/version'
+          version_geq(::Listen::VERSION, '2.0.0')
+        rescue LoadError
+          false
+        end
+    end
+
+    # Returns an ActionView::Template* class.
+    # In pre-3.0 versions of Rails, most of these classes
+    # were of the form `ActionView::TemplateFoo`,
+    # while afterwards they were of the form `ActionView;:Template::Foo`.
+    #
+    # @param name [#to_s] The name of the class to get.
+    #   For example, `:Error` will return `ActionView::TemplateError`
+    #   or `ActionView::Template::Error`.
+    def av_template_class(name)
+      return ActionView.const_get("Template#{name}") if ActionView.const_defined?("Template#{name}")
+      ActionView::Template.const_get(name.to_s)
+    end
+
+    ## Cross-OS Compatibility
+    #
+    # These methods are cached because some of them are called quite frequently
+    # and even basic checks like String#== are too costly to be called repeatedly.
+
+    # Whether or not this is running on Windows.
+    #
+    # @return [Boolean]
+    def windows?
+      return @windows if defined?(@windows)
+      @windows = (RbConfig::CONFIG['host_os'] =~ /mswin|windows|mingw/i)
+    end
+
+    # Whether or not this is running on IronRuby.
+    #
+    # @return [Boolean]
+    def ironruby?
+      return @ironruby if defined?(@ironruby)
+      @ironruby = RUBY_ENGINE == "ironruby"
+    end
+
+    # Whether or not this is running on Rubinius.
+    #
+    # @return [Boolean]
+    def rbx?
+      return @rbx if defined?(@rbx)
+      @rbx = RUBY_ENGINE == "rbx"
+    end
+
+    # Whether or not this is running on JRuby.
+    #
+    # @return [Boolean]
+    def jruby?
+      return @jruby if defined?(@jruby)
+      @jruby = RUBY_PLATFORM =~ /java/
+    end
+
+    # Returns an array of ints representing the JRuby version number.
+    #
+    # @return [Array<Fixnum>]
+    def jruby_version
+      @jruby_version ||= ::JRUBY_VERSION.split(".").map {|s| s.to_i}
+    end
+
+    # Like `Dir.glob`, but works with backslash-separated paths on Windows.
+    #
+    # @param path [String]
+    def glob(path)
+      path = path.gsub('\\', '/') if windows?
+      if block_given?
+        Dir.glob(path) {|f| yield(f)}
+      else
+        Dir.glob(path)
+      end
+    end
+
+    # Like `Pathname.new`, but normalizes Windows paths to always use backslash
+    # separators.
+    #
+    # `Pathname#relative_path_from` can break if the two pathnames aren't
+    # consistent in their slash style.
+    #
+    # @param path [String]
+    # @return [Pathname]
+    def pathname(path)
+      path = path.tr("/", "\\") if windows?
+      Pathname.new(path)
+    end
+
+    # Like `Pathname#cleanpath`, but normalizes Windows paths to always use
+    # backslash separators. Normally, `Pathname#cleanpath` actually does the
+    # reverse -- it will convert backslashes to forward slashes, which can break
+    # `Pathname#relative_path_from`.
+    #
+    # @param path [String, Pathname]
+    # @return [Pathname]
+    def cleanpath(path)
+      path = Pathname.new(path) unless path.is_a?(Pathname)
+      pathname(path.cleanpath.to_s)
+    end
+
+    # Returns `path` with all symlinks resolved.
+    #
+    # @param path [String, Pathname]
+    # @return [Pathname]
+    def realpath(path)
+      path = Pathname.new(path) unless path.is_a?(Pathname)
+
+      # Explicitly DON'T run #pathname here. We don't want to convert
+      # to Windows directory separators because we're comparing these
+      # against the paths returned by Listen, which use forward
+      # slashes everywhere.
+      begin
+        path.realpath
+      rescue SystemCallError
+        # If [path] doesn't actually exist, don't bail, just
+        # return the original.
+        path
+      end
+    end
+
+    # Returns `path` relative to `from`.
+    #
+    # This is like `Pathname#relative_path_from` except it accepts both strings
+    # and pathnames, it handles Windows path separators correctly, and it throws
+    # an error rather than crashing if the paths use different encodings
+    # (https://github.com/ruby/ruby/pull/713).
+    #
+    # @param path [String, Pathname]
+    # @param from [String, Pathname]
+    # @return [Pathname?]
+    def relative_path_from(path, from)
+      pathname(path.to_s).relative_path_from(pathname(from.to_s))
+    rescue NoMethodError => e
+      raise e unless e.name == :zero?
+
+      # Work around https://github.com/ruby/ruby/pull/713.
+      path = path.to_s
+      from = from.to_s
+      raise ArgumentError("Incompatible path encodings: #{path.inspect} is #{path.encoding}, " +
+        "#{from.inspect} is #{from.encoding}")
+    end
+
+    # Converts `path` to a "file:" URI. This handles Windows paths correctly.
+    #
+    # @param path [String, Pathname]
+    # @return [String]
+    def file_uri_from_path(path)
+      path = path.to_s if path.is_a?(Pathname)
+      path = path.tr('\\', '/') if windows?
+      path = Sass::Util.escape_uri(path)
+      return path.start_with?('/') ? "file://" + path : path unless windows?
+      return "file:///" + path.tr("\\", "/") if path =~ /^[a-zA-Z]:[\/\\]/
+      return "file:" + path.tr("\\", "/") if path =~ /\\\\[^\\]+\\[^\\\/]+/
+      path.tr("\\", "/")
+    end
+
+    # Retries a filesystem operation if it fails on Windows. Windows
+    # has weird and flaky locking rules that can cause operations to fail.
+    #
+    # @yield [] The filesystem operation.
+    def retry_on_windows
+      return yield unless windows?
+
+      begin
+        yield
+      rescue SystemCallError
+        sleep 0.1
+        yield
+      end
+    end
+
+    # Prepare a value for a destructuring assignment (e.g. `a, b =
+    # val`). This works around a performance bug when using
+    # ActiveSupport, and only needs to be called when `val` is likely
+    # to be `nil` reasonably often.
+    #
+    # See [this bug report](http://redmine.ruby-lang.org/issues/4917).
+    #
+    # @param val [Object]
+    # @return [Object]
+    def destructure(val)
+      val || []
+    end
+
+    ## Cross-Ruby-Version Compatibility
+
+    # Whether or not this is running under a Ruby version under 2.0.
+    #
+    # @return [Boolean]
+    def ruby1?
+      return @ruby1 if defined?(@ruby1)
+      @ruby1 = RUBY_VERSION_COMPONENTS[0] <= 1
+    end
+
+    # Whether or not this is running under Ruby 1.8 or lower.
+    #
+    # Note that IronRuby counts as Ruby 1.8,
+    # because it doesn't support the Ruby 1.9 encoding API.
+    #
+    # @return [Boolean]
+    def ruby1_8?
+      # IronRuby says its version is 1.9, but doesn't support any of the encoding APIs.
+      # We have to fall back to 1.8 behavior.
+      return @ruby1_8 if defined?(@ruby1_8)
+      @ruby1_8 = ironruby? ||
+                   (RUBY_VERSION_COMPONENTS[0] == 1 && RUBY_VERSION_COMPONENTS[1] < 9)
+    end
+
+    # Whether or not this is running under Ruby 1.8.6 or lower.
+    # Note that lower versions are not officially supported.
+    #
+    # @return [Boolean]
+    def ruby1_8_6?
+      return @ruby1_8_6 if defined?(@ruby1_8_6)
+      @ruby1_8_6 = ruby1_8? && RUBY_VERSION_COMPONENTS[2] < 7
+    end
+
+    # Whether or not this is running under Ruby 1.9.2 exactly.
+    #
+    # @return [Boolean]
+    def ruby1_9_2?
+      return @ruby1_9_2 if defined?(@ruby1_9_2)
+      @ruby1_9_2 = RUBY_VERSION_COMPONENTS == [1, 9, 2]
+    end
+
+    # Wehter or not this is running under JRuby 1.6 or lower.
+    def jruby1_6?
+      return @jruby1_6 if defined?(@jruby1_6)
+      @jruby1_6 = jruby? && jruby_version[0] == 1 && jruby_version[1] < 7
+    end
+
+    # Whether or not this is running under MacRuby.
+    #
+    # @return [Boolean]
+    def macruby?
+      return @macruby if defined?(@macruby)
+      @macruby = RUBY_ENGINE == 'macruby'
+    end
+
+    require 'sass/util/ordered_hash' if ruby1_8?
+
+    # Converts a hash or a list of pairs into an order-preserving hash.
+    #
+    # On Ruby 1.8.7, this uses the orderedhash gem to simulate an
+    # order-preserving hash. On Ruby 1.9 and up, it just uses the native Hash
+    # class, since that preserves the order itself.
+    #
+    # @overload ordered_hash(hash)
+    #   @param hash [Hash] a normal hash to convert to an ordered hash
+    #   @return [Hash]
+    # @overload ordered_hash(*pairs)
+    #   @example
+    #     ordered_hash([:foo, "bar"], [:baz, "bang"])
+    #       #=> {:foo => "bar", :baz => "bang"}
+    #     ordered_hash #=> {}
+    #   @param pairs [Array<(Object, Object)>] the list of key/value pairs for
+    #     the hash.
+    #   @return [Hash]
+    def ordered_hash(*pairs_or_hash)
+      if pairs_or_hash.length == 1 && pairs_or_hash.first.is_a?(Hash)
+        hash = pairs_or_hash.first
+        return hash unless ruby1_8?
+        return OrderedHash.new.merge hash
+      end
+
+      return Hash[pairs_or_hash] unless ruby1_8?
+      (pairs_or_hash.is_a?(NormalizedMap) ? NormalizedMap : OrderedHash)[*flatten(pairs_or_hash, 1)]
+    end
+
+    unless ruby1_8?
+      CHARSET_REGEXP = /\A charset "([^"]+)"/
+      UTF_8_BOM = "\xEF\xBB\xBF".force_encoding('BINARY')
+      UTF_16BE_BOM = "\xFE\xFF".force_encoding('BINARY')
+      UTF_16LE_BOM = "\xFF\xFE".force_encoding('BINARY')
+    end
+
+    # Like {\#check\_encoding}, but also checks for a ` charset` declaration
+    # at the beginning of the file and uses that encoding if it exists.
+    #
+    # Sass follows CSS's decoding rules.
+    #
+    # @param str [String] The string of which to check the encoding
+    # @return [(String, Encoding)] The original string encoded as UTF-8,
+    #   and the source encoding of the string (or `nil` under Ruby 1.8)
+    # @raise [Encoding::UndefinedConversionError] if the source encoding
+    #   cannot be converted to UTF-8
+    # @raise [ArgumentError] if the document uses an unknown encoding with ` charset`
+    # @raise [Sass::SyntaxError] If the document declares an encoding that
+    #   doesn't match its contents, or it doesn't declare an encoding and its
+    #   contents are invalid in the native encoding.
+    def check_sass_encoding(str)
+      # On Ruby 1.8 we can't do anything complicated with encodings.
+      # Instead, we just strip out a UTF-8 BOM if it exists and
+      # sanitize according to Section 3.3 of CSS Syntax Level 3. We
+      # don't sanitize null characters since they might be components
+      # of other characters.
+      if ruby1_8?
+        return str.gsub(/\A\xEF\xBB\xBF/, '').gsub(/\r\n?|\f/, "\n"), nil
+      end
+
+      # Determine the fallback encoding following section 3.2 of CSS Syntax Level 3 and Encodings:
+      # http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#determine-the-fallback-encoding
+      # http://encoding.spec.whatwg.org/#decode
+      binary = str.dup.force_encoding("BINARY")
+      if binary.start_with?(UTF_8_BOM)
+        binary.slice! 0, UTF_8_BOM.length
+        str = binary.force_encoding('UTF-8')
+      elsif binary.start_with?(UTF_16BE_BOM)
+        binary.slice! 0, UTF_16BE_BOM.length
+        str = binary.force_encoding('UTF-16BE')
+      elsif binary.start_with?(UTF_16LE_BOM)
+        binary.slice! 0, UTF_16LE_BOM.length
+        str = binary.force_encoding('UTF-16LE')
+      elsif binary =~ CHARSET_REGEXP
+        charset = $1.force_encoding('US-ASCII')
+        # Ruby 1.9.2 doesn't recognize a UTF-16 encoding without an endian marker.
+        if ruby1_9_2? && charset.downcase == 'utf-16'
+          encoding = Encoding.find('UTF-8')
+        else
+          encoding = Encoding.find(charset)
+          if encoding.name == 'UTF-16' || encoding.name == 'UTF-16BE'
+            encoding = Encoding.find('UTF-8')
+          end
+        end
+        str = binary.force_encoding(encoding)
+      elsif str.encoding.name == "ASCII-8BIT"
+        # Normally we want to fall back on believing the Ruby string
+        # encoding, but if that's just binary we want to make sure
+        # it's valid UTF-8.
+        str = str.force_encoding('utf-8')
+      end
+
+      find_encoding_error(str) unless str.valid_encoding?
+
+      begin
+        # If the string is valid, preprocess it according to section 3.3 of CSS Syntax Level 3.
+        return str.encode("UTF-8").gsub(/\r\n?|\f/, "\n").tr("\u0000", "�"), str.encoding
+      rescue EncodingError
+        find_encoding_error(str)
+      end
+    end
+
+    # Checks to see if a class has a given method.
+    # For example:
+    #
+    #     Sass::Util.has?(:public_instance_method, String, :gsub) #=> true
+    #
+    # Method collections like `Class#instance_methods`
+    # return strings in Ruby 1.8 and symbols in Ruby 1.9 and on,
+    # so this handles checking for them in a compatible way.
+    #
+    # @param attr [#to_s] The (singular) name of the method-collection method
+    #   (e.g. `:instance_methods`, `:private_methods`)
+    # @param klass [Module] The class to check the methods of which to check
+    # @param method [String, Symbol] The name of the method do check for
+    # @return [Boolean] Whether or not the given collection has the given method
+    def has?(attr, klass, method)
+      klass.send("#{attr}s").include?(ruby1_8? ? method.to_s : method.to_sym)
+    end
+
+    # A version of `Enumerable#enum_with_index` that works in Ruby 1.8 and 1.9.
+    #
+    # @param enum [Enumerable] The enumerable to get the enumerator for
+    # @return [Enumerator] The with-index enumerator
+    def enum_with_index(enum)
+      ruby1_8? ? enum.enum_with_index : enum.each_with_index
+    end
+
+    # A version of `Enumerable#enum_cons` that works in Ruby 1.8 and 1.9.
+    #
+    # @param enum [Enumerable] The enumerable to get the enumerator for
+    # @param n [Fixnum] The size of each cons
+    # @return [Enumerator] The consed enumerator
+    def enum_cons(enum, n)
+      ruby1_8? ? enum.enum_cons(n) : enum.each_cons(n)
+    end
+
+    # A version of `Enumerable#enum_slice` that works in Ruby 1.8 and 1.9.
+    #
+    # @param enum [Enumerable] The enumerable to get the enumerator for
+    # @param n [Fixnum] The size of each slice
+    # @return [Enumerator] The consed enumerator
+    def enum_slice(enum, n)
+      ruby1_8? ? enum.enum_slice(n) : enum.each_slice(n)
+    end
+
+    # Destructively removes all elements from an array that match a block, and
+    # returns the removed elements.
+    #
+    # @param array [Array] The array from which to remove elements.
+    # @yield [el] Called for each element.
+    # @yieldparam el [*] The element to test.
+    # @yieldreturn [Boolean] Whether or not to extract the element.
+    # @return [Array] The extracted elements.
+    def extract!(array)
+      out = []
+      array.reject! do |e|
+        next false unless yield e
+        out << e
+        true
+      end
+      out
+    end
+
+    # Returns the ASCII code of the given character.
+    #
+    # @param c [String] All characters but the first are ignored.
+    # @return [Fixnum] The ASCII code of `c`.
+    def ord(c)
+      ruby1_8? ? c[0] : c.ord
+    end
+
+    # Flattens the first `n` nested arrays in a cross-version manner.
+    #
+    # @param arr [Array] The array to flatten
+    # @param n [Fixnum] The number of levels to flatten
+    # @return [Array] The flattened array
+    def flatten(arr, n)
+      return arr.flatten(n) unless ruby1_8_6?
+      return arr if n == 0
+      arr.inject([]) {|res, e| e.is_a?(Array) ? res.concat(flatten(e, n - 1)) : res << e}
+    end
+
+    # Flattens the first level of nested arrays in `arrs`. Unlike
+    # `Array#flatten`, this orders the result by taking the first
+    # values from each array in order, then the second, and so on.
+    #
+    # @param arrs [Array] The array to flatten.
+    # @return [Array] The flattened array.
+    def flatten_vertically(arrs)
+      result = []
+      arrs = arrs.map {|sub| sub.is_a?(Array) ? sub.dup : Array(sub)}
+      until arrs.empty?
+        arrs.reject! do |arr|
+          result << arr.shift
+          arr.empty?
+        end
+      end
+      result
+    end
+
+    # Returns the hash code for a set in a cross-version manner.
+    # Aggravatingly, this is order-dependent in Ruby 1.8.6.
+    #
+    # @param set [Set]
+    # @return [Fixnum] The order-independent hashcode of `set`
+    def set_hash(set)
+      return set.hash unless ruby1_8_6?
+      set.map {|e| e.hash}.uniq.sort.hash
+    end
+
+    # Tests the hash-equality of two sets in a cross-version manner.
+    # Aggravatingly, this is order-dependent in Ruby 1.8.6.
+    #
+    # @param set1 [Set]
+    # @param set2 [Set]
+    # @return [Boolean] Whether or not the sets are hashcode equal
+    def set_eql?(set1, set2)
+      return set1.eql?(set2) unless ruby1_8_6?
+      set1.to_a.uniq.sort_by {|e| e.hash}.eql?(set2.to_a.uniq.sort_by {|e| e.hash})
+    end
+
+    # Like `Object#inspect`, but preserves non-ASCII characters rather than
+    # escaping them under Ruby 1.9.2.  This is necessary so that the
+    # precompiled Haml template can be `#encode`d into ` options[:encoding]`
+    # before being evaluated.
+    #
+    # @param obj {Object}
+    # @return {String}
+    def inspect_obj(obj)
+      return obj.inspect unless version_geq(RUBY_VERSION, "1.9.2")
+      return ':' + inspect_obj(obj.to_s) if obj.is_a?(Symbol)
+      return obj.inspect unless obj.is_a?(String)
+      '"' + obj.gsub(/[\x00-\x7F]+/) {|s| s.inspect[1...-1]} + '"'
+    end
+
+    # Extracts the non-string vlaues from an array containing both strings and non-strings.
+    # These values are replaced with escape sequences.
+    # This can be undone using \{#inject\_values}.
+    #
+    # This is useful e.g. when we want to do string manipulation
+    # on an interpolated string.
+    #
+    # The precise format of the resulting string is not guaranteed.
+    # However, it is guaranteed that newlines and whitespace won't be affected.
+    #
+    # @param arr [Array] The array from which values are extracted.
+    # @return [(String, Array)] The resulting string, and an array of extracted values.
+    def extract_values(arr)
+      values = []
+      mapped = arr.map do |e|
+        next e.gsub('{', '{{') if e.is_a?(String)
+        values << e
+        next "{#{values.count - 1}}"
+      end
+      return mapped.join, values
+    end
+
+    # Undoes \{#extract\_values} by transforming a string with escape sequences
+    # into an array of strings and non-string values.
+    #
+    # @param str [String] The string with escape sequences.
+    # @param values [Array] The array of values to inject.
+    # @return [Array] The array of strings and values.
+    def inject_values(str, values)
+      return [str.gsub('{{', '{')] if values.empty?
+      # Add an extra { so that we process the tail end of the string
+      result = (str + '{{').scan(/(.*?)(?:(\{\{)|\{(\d+)\})/m).map do |(pre, esc, n)|
+        [pre, esc ? '{' : '', n ? values[n.to_i] : '']
+      end.flatten(1)
+      result[-2] = '' # Get rid of the extra {
+      merge_adjacent_strings(result).reject {|s| s == ''}
+    end
+
+    # Allows modifications to be performed on the string form
+    # of an array containing both strings and non-strings.
+    #
+    # @param arr [Array] The array from which values are extracted.
+    # @yield [str] A block in which string manipulation can be done to the array.
+    # @yieldparam str [String] The string form of `arr`.
+    # @yieldreturn [String] The modified string.
+    # @return [Array] The modified, interpolated array.
+    def with_extracted_values(arr)
+      str, vals = extract_values(arr)
+      str = yield str
+      inject_values(str, vals)
+    end
+
+    # Builds a sourcemap file name given the generated CSS file name.
+    #
+    # @param css [String] The generated CSS file name.
+    # @return [String] The source map file name.
+    def sourcemap_name(css)
+      css + ".map"
+    end
+
+    # Escapes certain characters so that the result can be used
+    # as the JSON string value. Returns the original string if
+    # no escaping is necessary.
+    #
+    # @param s [String] The string to be escaped
+    # @return [String] The escaped string
+    def json_escape_string(s)
+      return s if s !~ /["\\\b\f\n\r\t]/
+
+      result = ""
+      s.split("").each do |c|
+        case c
+        when '"', "\\"
+          result << "\\" << c
+        when "\n" then result << "\\n"
+        when "\t" then result << "\\t"
+        when "\r" then result << "\\r"
+        when "\f" then result << "\\f"
+        when "\b" then result << "\\b"
+        else
+          result << c
+        end
+      end
+      result
+    end
+
+    # Converts the argument into a valid JSON value.
+    #
+    # @param v [Fixnum, String, Array, Boolean, nil]
+    # @return [String]
+    def json_value_of(v)
+      case v
+      when Fixnum
+        v.to_s
+      when String
+        "\"" + json_escape_string(v) + "\""
+      when Array
+        "[" + v.map {|x| json_value_of(x)}.join(",") + "]"
+      when NilClass
+        "null"
+      when TrueClass
+        "true"
+      when FalseClass
+        "false"
+      else
+        raise ArgumentError.new("Unknown type: #{v.class.name}")
+      end
+    end
+
+    VLQ_BASE_SHIFT = 5
+    VLQ_BASE = 1 << VLQ_BASE_SHIFT
+    VLQ_BASE_MASK = VLQ_BASE - 1
+    VLQ_CONTINUATION_BIT = VLQ_BASE
+
+    BASE64_DIGITS = ('A'..'Z').to_a  + ('a'..'z').to_a + ('0'..'9').to_a  + ['+', '/']
+    BASE64_DIGIT_MAP = begin
+      map = {}
+      Sass::Util.enum_with_index(BASE64_DIGITS).map do |digit, i|
+        map[digit] = i
+      end
+      map
+    end
+
+    # Encodes `value` as VLQ (http://en.wikipedia.org/wiki/VLQ).
+    #
+    # @param value [Fixnum]
+    # @return [String] The encoded value
+    def encode_vlq(value)
+      if value < 0
+        value = ((-value) << 1) | 1
+      else
+        value <<= 1
+      end
+
+      result = ''
+      begin
+        digit = value & VLQ_BASE_MASK
+        value >>= VLQ_BASE_SHIFT
+        if value > 0
+          digit |= VLQ_CONTINUATION_BIT
+        end
+        result << BASE64_DIGITS[digit]
+      end while value > 0
+      result
+    end
+
+    # This is a hack around the fact that you can't instantiate a URI parser on
+    # 1.8, so we have to have this hacky stuff to work around it. When 1.8
+    # support is dropped, we can remove this method.
+    #
+    # @private
+    URI_ESCAPE = URI.const_defined?("DEFAULT_PARSER") ? URI::DEFAULT_PARSER : URI
+
+    # URI-escape `string`.
+    #
+    # @param string [String]
+    # @return [String]
+    def escape_uri(string)
+      URI_ESCAPE.escape string
+    end
+
+    # A cross-platform implementation of `File.absolute_path`.
+    #
+    # @param path [String]
+    # @param dir_string [String] The directory to consider [path] relative to.
+    # @return [String] The absolute version of `path`.
+    def absolute_path(path, dir_string = nil)
+      # Ruby 1.8 doesn't support File.absolute_path.
+      return File.absolute_path(path, dir_string) unless ruby1_8?
+
+      # File.expand_path expands "~", which we don't want.
+      return File.expand_path(path, dir_string) unless path[0] == ?~
+      File.expand_path(File.join(".", path), dir_string)
+    end
+
+    ## Static Method Stuff
+
+    # The context in which the ERB for \{#def\_static\_method} will be run.
+    class StaticConditionalContext
+      # @param set [#include?] The set of variables that are defined for this context.
+      def initialize(set)
+        @set = set
+      end
+
+      # Checks whether or not a variable is defined for this context.
+      #
+      # @param name [Symbol] The name of the variable
+      # @return [Boolean]
+      def method_missing(name, *args)
+        super unless args.empty? && !block_given?
+        @set.include?(name)
+      end
+    end
+
+    # @private
+    ATOMIC_WRITE_MUTEX = Mutex.new
+
+    # This creates a temp file and yields it for writing. When the
+    # write is complete, the file is moved into the desired location.
+    # The atomicity of this operation is provided by the filesystem's
+    # rename operation.
+    #
+    # @param filename [String] The file to write to.
+    # @param perms [Integer] The permissions used for creating this file.
+    #   Will be masked by the process umask. Defaults to readable/writeable
+    #   by all users however the umask usually changes this to only be writable
+    #   by the process's user.
+    # @yieldparam tmpfile [Tempfile] The temp file that can be written to.
+    # @return The value returned by the block.
+    def atomic_create_and_write_file(filename, perms = 0666)
+      require 'tempfile'
+      tmpfile = Tempfile.new(File.basename(filename), File.dirname(filename))
+      tmpfile.binmode if tmpfile.respond_to?(:binmode)
+      result = yield tmpfile
+      tmpfile.close
+      ATOMIC_WRITE_MUTEX.synchronize do
+        begin
+          File.chmod(perms & ~File.umask, tmpfile.path)
+        rescue Errno::EPERM
+          # If we don't have permissions to chmod the file, don't let that crash
+          # the compilation. See issue 1215.
+        end
+        File.rename tmpfile.path, filename
+      end
+      result
+    ensure
+      # close and remove the tempfile if it still exists,
+      # presumably due to an error during write
+      tmpfile.close if tmpfile
+      tmpfile.unlink if tmpfile
+    end
+
+    def load_listen!
+      if defined?(gem)
+        begin
+          gem 'listen', '>= 1.1.0', '< 3.0.0'
+          require 'listen'
+        rescue Gem::LoadError
+          dir = scope("vendor/listen/lib")
+          $LOAD_PATH.unshift dir
+          begin
+            require 'listen'
+          rescue LoadError => e
+            if version_geq(RUBY_VERSION, "1.9.3")
+              version_constraint = "~> 2.7"
+            else
+              version_constraint = "~> 1.1"
+            end
+            e.message << "\n" <<
+              "Run \"gem install listen --version '#{version_constraint}'\" to get it."
+            raise e
+          end
+        end
+      else
+        begin
+          require 'listen'
+        rescue LoadError => e
+          dir = scope("vendor/listen/lib")
+          if $LOAD_PATH.include?(dir)
+            raise e unless File.exist?(scope(".git"))
+            e.message << "\n" <<
+              'Run "git submodule update --init" to get the bundled version.'
+          else
+            $LOAD_PATH.unshift dir
+            retry
+          end
+        end
+      end
+    end
+
+    private
+
+    def find_encoding_error(str)
+      encoding = str.encoding
+      cr = Regexp.quote("\r".encode(encoding).force_encoding('BINARY'))
+      lf = Regexp.quote("\n".encode(encoding).force_encoding('BINARY'))
+      ff = Regexp.quote("\f".encode(encoding).force_encoding('BINARY'))
+      line_break = /#{cr}#{lf}?|#{ff}|#{lf}/
+
+      str.force_encoding("binary").split(line_break).each_with_index do |line, i|
+        begin
+          line.encode(encoding)
+        rescue Encoding::UndefinedConversionError => e
+          raise Sass::SyntaxError.new(
+            "Invalid #{encoding.name} character #{undefined_conversion_error_char(e)}",
+            :line => i + 1)
+        end
+      end
+
+      # We shouldn't get here, but it's possible some weird encoding stuff causes it.
+      return str, str.encoding
+    end
+
+    # rubocop:disable LineLength
+
+    # Calculates the memoization table for the Least Common Subsequence algorithm.
+    # Algorithm from 
[Wikipedia](http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Computing_the_length_of_the_LCS)
+    def lcs_table(x, y)
+      # This method does not take a block as an explicit parameter for performance reasons.
+      # rubocop:enable LineLength
+      c = Array.new(x.size) {[]}
+      x.size.times {|i| c[i][0] = 0}
+      y.size.times {|j| c[0][j] = 0}
+      (1...x.size).each do |i|
+        (1...y.size).each do |j|
+          c[i][j] =
+            if yield x[i], y[j]
+              c[i - 1][j - 1] + 1
+            else
+              [c[i][j - 1], c[i - 1][j]].max
+            end
+        end
+      end
+      c
+    end
+    # rubocop:disable ParameterLists, LineLength
+
+    # Computes a single longest common subsequence for arrays x and y.
+    # Algorithm from 
[Wikipedia](http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Reading_out_an_LCS)
+    def lcs_backtrace(c, x, y, i, j, &block)
+      # rubocop:enable ParameterList, LineLengths
+      return [] if i == 0 || j == 0
+      if (v = yield(x[i], y[j]))
+        return lcs_backtrace(c, x, y, i - 1, j - 1, &block) << v
+      end
+
+      return lcs_backtrace(c, x, y, i, j - 1, &block) if c[i][j - 1] > c[i - 1][j]
+      lcs_backtrace(c, x, y, i - 1, j, &block)
+    end
+
+    singleton_methods.each {|method| module_function method}
+  end
+end
+
+require 'sass/util/multibyte_string_scanner'
+require 'sass/util/normalized_map'
+require 'sass/util/cross_platform_random'
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/util/cross_platform_random.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/util/cross_platform_random.rb
new file mode 100644
index 0000000..54ff739
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/util/cross_platform_random.rb
@@ -0,0 +1,19 @@
+module Sass
+  module Util
+    # Ruby 1.8 doesn't support an actual Random class with a settable seed.
+    class CrossPlatformRandom
+      def initialize(seed = nil)
+        if Sass::Util.ruby1_8?
+          srand(seed) if seed
+        else
+          @random = seed ? ::Random.new(seed) : ::Random.new
+        end
+      end
+
+      def rand(*args)
+        return @random.rand(*args) if @random
+        Kernel.rand(*args)
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/util/multibyte_string_scanner.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/util/multibyte_string_scanner.rb
new file mode 100644
index 0000000..6675aa5
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/util/multibyte_string_scanner.rb
@@ -0,0 +1,157 @@
+require 'strscan'
+
+if Sass::Util.ruby1_8?
+  # rubocop:disable ConstantName
+  Sass::Util::MultibyteStringScanner = StringScanner
+  # rubocop:enable ConstantName
+else
+  if Sass::Util.rbx?
+    # Rubinius's StringScanner class implements some of its methods in terms of
+    # others, which causes us to double-count bytes in some cases if we do
+    # straightforward inheritance. To work around this, we use a delegate class.
+    require 'delegate'
+    class Sass::Util::MultibyteStringScanner < DelegateClass(StringScanner)
+      def initialize(str)
+        super(StringScanner.new(str))
+        @mb_pos = 0
+        @mb_matched_size = nil
+        @mb_last_pos = nil
+      end
+
+      def is_a?(klass)
+        __getobj__.is_a?(klass) || super
+      end
+    end
+  else
+    class Sass::Util::MultibyteStringScanner < StringScanner
+      def initialize(str)
+        super
+        @mb_pos = 0
+        @mb_matched_size = nil
+        @mb_last_pos = nil
+      end
+    end
+  end
+
+  # A wrapper of the native StringScanner class that works correctly with
+  # multibyte character encodings. The native class deals only in bytes, not
+  # characters, for methods like [#pos] and [#matched_size]. This class deals
+  # only in characters, instead.
+  class Sass::Util::MultibyteStringScanner
+    def self.new(str)
+      return StringScanner.new(str) if str.ascii_only?
+      super
+    end
+
+    alias_method :byte_pos, :pos
+    alias_method :byte_matched_size, :matched_size
+
+    def check(pattern); _match super; end
+    def check_until(pattern); _matched super; end
+    def getch; _forward _match super; end
+    def match?(pattern); _size check(pattern); end
+    def matched_size; @mb_matched_size; end
+    def peek(len); string[ mb_pos, len]; end
+    alias_method :peep, :peek
+    def pos; @mb_pos; end
+    alias_method :pointer, :pos
+    def rest_size; rest.size; end
+    def scan(pattern); _forward _match super; end
+    def scan_until(pattern); _forward _matched super; end
+    def skip(pattern); _size scan(pattern); end
+    def skip_until(pattern); _matched _size scan_until(pattern); end
+
+    def get_byte
+      raise "MultibyteStringScanner doesn't support #get_byte."
+    end
+
+    def getbyte
+      raise "MultibyteStringScanner doesn't support #getbyte."
+    end
+
+    def pos=(n)
+      @mb_last_pos = nil
+
+      # We set position kind of a lot during parsing, so we want it to be as
+      # efficient as possible. This is complicated by the fact that UTF-8 is a
+      # variable-length encoding, so it's difficult to find the byte length that
+      # corresponds to a given character length.
+      #
+      # Our heuristic here is to try to count the fewest possible characters. So
+      # if the new position is close to the current one, just count the
+      # characters between the two; if the new position is closer to the
+      # beginning of the string, just count the characters from there.
+      if @mb_pos - n < @mb_pos / 2
+        # New position is close to old position
+        byte_delta = @mb_pos > n ? -string[n    mb_pos] bytesize : string[ mb_pos   n] bytesize
+        super(byte_pos + byte_delta)
+      else
+        # New position is close to BOS
+        super(string[0...n].bytesize)
+      end
+      @mb_pos = n
+    end
+
+    def reset
+      @mb_pos = 0
+      @mb_matched_size = nil
+      @mb_last_pos = nil
+      super
+    end
+
+    def scan_full(pattern, advance_pointer_p, return_string_p)
+      res = _match super(pattern, advance_pointer_p, true)
+      _forward res if advance_pointer_p
+      return res if return_string_p
+    end
+
+    def search_full(pattern, advance_pointer_p, return_string_p)
+      res = super(pattern, advance_pointer_p, true)
+      _forward res if advance_pointer_p
+      _matched((res if return_string_p))
+    end
+
+    def string=(str)
+      @mb_pos = 0
+      @mb_matched_size = nil
+      @mb_last_pos = nil
+      super
+    end
+
+    def terminate
+      @mb_pos = string.size
+      @mb_matched_size = nil
+      @mb_last_pos = nil
+      super
+    end
+    alias_method :clear, :terminate
+
+    def unscan
+      super
+      @mb_pos = @mb_last_pos
+      @mb_last_pos = @mb_matched_size = nil
+    end
+
+    private
+
+    def _size(str)
+      str && str.size
+    end
+
+    def _match(str)
+      @mb_matched_size = str && str.size
+      str
+    end
+
+    def _matched(res)
+      _match matched
+      res
+    end
+
+    def _forward(str)
+      @mb_last_pos = @mb_pos
+      @mb_pos += str.size if str
+      str
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/util/normalized_map.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/util/normalized_map.rb
new file mode 100644
index 0000000..b7d7e83
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/util/normalized_map.rb
@@ -0,0 +1,130 @@
+require 'delegate'
+require 'sass/util'
+
+module Sass
+  module Util
+    # A hash that normalizes its string keys while still allowing you to get back
+    # to the original keys that were stored. If several different values normalize
+    # to the same value, whichever is stored last wins.
+    require 'sass/util/ordered_hash' if ruby1_8?
+    class NormalizedMap
+      # Create a normalized map
+      def initialize(map = nil)
+        @key_strings = {}
+        @map = Util.ruby1_8? ? OrderedHash.new : {}
+
+        map.each {|key, value| self[key] = value} if map
+      end
+
+      # Specifies how to transform the key.
+      #
+      # This can be overridden to create other normalization behaviors.
+      def normalize(key)
+        key.tr("-", "_")
+      end
+
+      # Returns the version of `key` as it was stored before
+      # normalization. If `key` isn't in the map, returns it as it was
+      # passed in.
+      #
+      # @return [String]
+      def denormalize(key)
+        @key_strings[normalize(key)] || key
+      end
+
+      # @private
+      def []=(k, v)
+        normalized = normalize(k)
+        @map[normalized] = v
+        @key_strings[normalized] = k
+        v
+      end
+
+      # @private
+      def [](k)
+        @map[normalize(k)]
+      end
+
+      # @private
+      def has_key?(k)
+        @map.has_key?(normalize(k))
+      end
+
+      # @private
+      def delete(k)
+        normalized = normalize(k)
+        @key_strings.delete(normalized)
+        @map.delete(normalized)
+      end
+
+      # @return [Hash] Hash with the keys as they were stored (before normalization).
+      def as_stored
+        Sass::Util.map_keys(@map) {|k| @key_strings[k]}
+      end
+
+      def empty?
+        @map.empty?
+      end
+
+      def values
+        @map.values
+      end
+
+      def keys
+        @map.keys
+      end
+
+      def each
+        @map.each {|k, v| yield(k, v)}
+      end
+
+      def size
+        @map.size
+      end
+
+      def to_hash
+        @map.dup
+      end
+
+      def to_a
+        @map.to_a
+      end
+
+      def map
+        @map.map {|k, v| yield(k, v)}
+      end
+
+      def dup
+        d = super
+        d.send(:instance_variable_set, "@map", @map.dup)
+        d
+      end
+
+      def sort_by
+        @map.sort_by {|k, v| yield k, v}
+      end
+
+      def update(map)
+        map = map.as_stored if map.is_a?(NormalizedMap)
+        map.each {|k, v| self[k] = v}
+      end
+
+      def method_missing(method, *args, &block)
+        if Sass.tests_running
+          raise ArgumentError.new("The method #{method} must be implemented explicitly")
+        end
+        @map.send(method, *args, &block)
+      end
+
+      if Sass::Util.ruby1_8?
+        def respond_to?(method, include_private = false)
+          super || @map.respond_to?(method, include_private)
+        end
+      end
+
+      def respond_to_missing?(method, include_private = false)
+        @map.respond_to?(method, include_private)
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/util/ordered_hash.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/util/ordered_hash.rb
new file mode 100644
index 0000000..e11a6ec
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/util/ordered_hash.rb
@@ -0,0 +1,192 @@
+# Copyright (c) 2005-2013 David Heinemeier Hansson
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+# This class was copied from an old version of ActiveSupport.
+class OrderedHash < ::Hash
+  # In MRI the Hash class is core and written in C. In particular, methods are
+  # programmed with explicit C function calls and polymorphism is not honored.
+  #
+  # For example, []= is crucial in this implementation to maintain the @keys
+  # array but hash.c invokes rb_hash_aset() originally. This prevents method
+  # reuse through inheritance and forces us to reimplement stuff.
+  #
+  # For instance, we cannot use the inherited #merge! because albeit the algorithm
+  # itself would work, our []= is not being called at all by the C code.
+
+  def initialize(*args)
+    super
+    @keys = []
+  end
+
+  def self.[](*args)
+    ordered_hash = new
+
+    if args.length == 1 && args.first.is_a?(Array)
+      args.first.each do |key_value_pair|
+        next unless key_value_pair.is_a?(Array)
+        ordered_hash[key_value_pair[0]] = key_value_pair[1]
+      end
+
+      return ordered_hash
+    end
+
+    unless args.size.even?
+      raise ArgumentError.new("odd number of arguments for Hash")
+    end
+
+    args.each_with_index do |val, ind|
+      next if ind.odd?
+      ordered_hash[val] = args[ind + 1]
+    end
+
+    ordered_hash
+  end
+
+  def initialize_copy(other)
+    super
+    # make a deep copy of keys
+    @keys = other.keys
+  end
+
+  def []=(key, value)
+    @keys << key unless has_key?(key)
+    super
+  end
+
+  def delete(key)
+    if has_key? key
+      index = @keys.index(key)
+      @keys.delete_at index
+    end
+    super
+  end
+
+  def delete_if
+    super
+    sync_keys!
+    self
+  end
+
+  def reject!
+    super
+    sync_keys!
+    self
+  end
+
+  def reject
+    dup.reject! {|h, k| yield h, k}
+  end
+
+  def keys
+    @keys.dup
+  end
+
+  def values
+    @keys.map {|key| self[key]}
+  end
+
+  def to_hash
+    self
+  end
+
+  def to_a
+    @keys.map {|key| [key, self[key]]}
+  end
+
+  def each_key
+    return to_enum(:each_key) unless block_given?
+    @keys.each {|key| yield key}
+    self
+  end
+
+  def each_value
+    return to_enum(:each_value) unless block_given?
+    @keys.each {|key| yield self[key]}
+    self
+  end
+
+  def each
+    return to_enum(:each) unless block_given?
+    @keys.each {|key| yield [key, self[key]]}
+    self
+  end
+
+  def each_pair
+    return to_enum(:each_pair) unless block_given?
+    @keys.each {|key| yield key, self[key]}
+    self
+  end
+
+  alias_method :select, :find_all
+
+  def clear
+    super
+    @keys.clear
+    self
+  end
+
+  def shift
+    k = @keys.first
+    v = delete(k)
+    [k, v]
+  end
+
+  def merge!(other_hash)
+    if block_given?
+      other_hash.each {|k, v| self[k] = key?(k) ? yield(k, self[k], v) : v}
+    else
+      other_hash.each {|k, v| self[k] = v}
+    end
+    self
+  end
+
+  alias_method :update, :merge!
+
+  def merge(other_hash)
+    if block_given?
+      dup.merge!(other_hash) {|k, v1, v2| yield k, v1, v2}
+    else
+      dup.merge!(other_hash)
+    end
+  end
+
+  # When replacing with another hash, the initial order of our keys must come from the other hash --
+  # ordered or not.
+  def replace(other)
+    super
+    @keys = other.keys
+    self
+  end
+
+  def invert
+    OrderedHash[to_a.map! {|key_value_pair| key_value_pair.reverse}]
+  end
+
+  def inspect
+    "#<OrderedHash #{super}>"
+  end
+
+  private
+
+  def sync_keys!
+    @keys.delete_if {|k| !has_key?(k)}
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/util/subset_map.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/util/subset_map.rb
new file mode 100644
index 0000000..a976acf
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/util/subset_map.rb
@@ -0,0 +1,110 @@
+require 'set'
+
+module Sass
+  module Util
+    # A map from sets to values.
+    # A value is \{#\[]= set} by providing a set (the "set-set") and a value,
+    # which is then recorded as corresponding to that set.
+    # Values are \{#\[] accessed} by providing a set (the "get-set")
+    # and returning all values that correspond to set-sets
+    # that are subsets of the get-set.
+    #
+    # SubsetMap preserves the order of values as they're inserted.
+    #
+    # @example
+    #   ssm = SubsetMap.new
+    #   ssm[Set[1, 2]] = "Foo"
+    #   ssm[Set[2, 3]] = "Bar"
+    #   ssm[Set[1, 2, 3]] = "Baz"
+    #
+    #   ssm[Set[1, 2, 3]] #=> ["Foo", "Bar", "Baz"]
+    class SubsetMap
+      # Creates a new, empty SubsetMap.
+      def initialize
+        @hash = {}
+        @vals = []
+      end
+
+      # Whether or not this SubsetMap has any key-value pairs.
+      #
+      # @return [Boolean]
+      def empty?
+        @hash.empty?
+      end
+
+      # Associates a value with a set.
+      # When `set` or any of its supersets is accessed,
+      # `value` will be among the values returned.
+      #
+      # Note that if the same `set` is passed to this method multiple times,
+      # all given `value`s will be associated with that `set`.
+      #
+      # This runs in `O(n)` time, where `n` is the size of `set`.
+      #
+      # @param set [#to_set] The set to use as the map key. May not be empty.
+      # @param value [Object] The value to associate with `set`.
+      # @raise [ArgumentError] If `set` is empty.
+      def []=(set, value)
+        raise ArgumentError.new("SubsetMap keys may not be empty.") if set.empty?
+
+        index = @vals.size
+        @vals << value
+        set.each do |k|
+          @hash[k] ||= []
+          @hash[k] << [set, set.to_set, index]
+        end
+      end
+
+      # Returns all values associated with subsets of `set`.
+      #
+      # In the worst case, this runs in `O(m*max(n, log m))` time,
+      # where `n` is the size of `set`
+      # and `m` is the number of associations in the map.
+      # However, unless many keys in the map overlap with `set`,
+      # `m` will typically be much smaller.
+      #
+      # @param set [Set] The set to use as the map key.
+      # @return [Array<(Object, #to_set)>] An array of pairs,
+      #   where the first value is the value associated with a subset of `set`,
+      #   and the second value is that subset of `set`
+      #   (or whatever `#to_set` object was used to set the value)
+      #   This array is in insertion order.
+      # @see #[]
+      def get(set)
+        res = set.map do |k|
+          subsets = @hash[k]
+          next unless subsets
+          subsets.map do |subenum, subset, index|
+            next unless subset.subset?(set)
+            [index, subenum]
+          end
+        end
+        res = Sass::Util.flatten(res, 1)
+        res.compact!
+        res.uniq!
+        res.sort!
+        res.map! {|i, s| [ vals[i], s]}
+        res
+      end
+
+      # Same as \{#get}, but doesn't return the subsets of the argument
+      # for which values were found.
+      #
+      # @param set [Set] The set to use as the map key.
+      # @return [Array] The array of all values
+      #   associated with subsets of `set`, in insertion order.
+      # @see #get
+      def [](set)
+        get(set).map {|v, _| v}
+      end
+
+      # Iterates over each value in the subset map. Ignores keys completely. If
+      # multiple keys have the same value, this will return them multiple times.
+      #
+      # @yield [Object] Each value in the map.
+      def each_value
+        @vals.each {|v| yield v}
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/util/test.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/util/test.rb
new file mode 100644
index 0000000..905e81f
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/util/test.rb
@@ -0,0 +1,9 @@
+module Sass
+  module Util
+    module Test
+      def skip(msg = nil, bt = caller)
+        super if defined?(super)
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/lib/sass/version.rb 
b/backends/css/gems/sass-3.4.9/lib/sass/version.rb
new file mode 100644
index 0000000..89c8a06
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/lib/sass/version.rb
@@ -0,0 +1,124 @@
+require 'date'
+require 'sass/util'
+
+module Sass
+  # Handles Sass version-reporting.
+  # Sass not only reports the standard three version numbers,
+  # but its Git revision hash as well,
+  # if it was installed from Git.
+  module Version
+    # Returns a hash representing the version of Sass.
+    # The `:major`, `:minor`, and `:teeny` keys have their respective numbers as Fixnums.
+    # The `:name` key has the name of the version.
+    # The `:string` key contains a human-readable string representation of the version.
+    # The `:number` key is the major, minor, and teeny keys separated by periods.
+    # The `:date` key, which is not guaranteed to be defined, is the `DateTime`
+    #   at which this release was cut.
+    # If Sass is checked out from Git, the `:rev` key will have the revision hash.
+    # For example:
+    #
+    #     {
+    #       :string => "2.1.0.9616393",
+    #       :rev    => "9616393b8924ef36639c7e82aa88a51a24d16949",
+    #       :number => "2.1.0",
+    #       :date   => DateTime.parse("Apr 30 13:52:01 2009 -0700"),
+    #       :major  => 2, :minor => 1, :teeny => 0
+    #     }
+    #
+    # If a prerelease version of Sass is being used,
+    # the `:string` and `:number` fields will reflect the full version
+    # (e.g. `"2.2.beta.1"`), and the `:teeny` field will be `-1`.
+    # A `:prerelease` key will contain the name of the prerelease (e.g. `"beta"`),
+    # and a `:prerelease_number` key will contain the rerelease number.
+    # For example:
+    #
+    #     {
+    #       :string => "3.0.beta.1",
+    #       :number => "3.0.beta.1",
+    #       :date   => DateTime.parse("Mar 31 00:38:04 2010 -0700"),
+    #       :major => 3, :minor => 0, :teeny => -1,
+    #       :prerelease => "beta",
+    #       :prerelease_number => 1
+    #     }
+    #
+    # @return [{Symbol => String/Fixnum}] The version hash
+    # @comment
+    #   rubocop:disable ClassVars
+    def version
+      return @@version if defined?(@@version)
+
+      numbers = File.read(Sass::Util.scope('VERSION')).strip.split('.').
+        map {|n| n =~ /^[0-9]+$/ ? n.to_i : n}
+      name = File.read(Sass::Util.scope('VERSION_NAME')).strip
+      @@version = {
+        :major => numbers[0],
+        :minor => numbers[1],
+        :teeny => numbers[2],
+        :name => name
+      }
+
+      if (date = version_date)
+        @@version[:date] = date
+      end
+
+      if numbers[3].is_a?(String)
+        @@version[:teeny] = -1
+        @@version[:prerelease] = numbers[3]
+        @@version[:prerelease_number] = numbers[4]
+      end
+
+      @@version[:number] = numbers.join('.')
+      @@version[:string] = @@version[:number].dup
+
+      if (rev = revision_number)
+        @@version[:rev] = rev
+        unless rev[0] == ?(
+          @@version[:string] << "." << rev[0...7]
+        end
+      end
+
+      @@version[:string] << " (#{name})"
+      @@version
+    end
+    # rubocop:enable ClassVars
+
+    private
+
+    def revision_number
+      if File.exist?(Sass::Util.scope('REVISION'))
+        rev = File.read(Sass::Util.scope('REVISION')).strip
+        return rev unless rev =~ /^([a-f0-9]+|\(.*\))$/ || rev == '(unknown)'
+      end
+
+      return unless File.exist?(Sass::Util.scope('.git/HEAD'))
+      rev = File.read(Sass::Util.scope('.git/HEAD')).strip
+      return rev unless rev =~ /^ref: (.*)$/
+
+      ref_name = $1
+      ref_file = Sass::Util.scope(".git/#{ref_name}")
+      info_file = Sass::Util.scope(".git/info/refs")
+      return File.read(ref_file).strip if File.exist?(ref_file)
+      return unless File.exist?(info_file)
+      File.open(info_file) do |f|
+        f.each do |l|
+          sha, ref = l.strip.split("\t", 2)
+          next unless ref == ref_name
+          return sha
+        end
+      end
+      nil
+    end
+
+    def version_date
+      return unless File.exist?(Sass::Util.scope('VERSION_DATE'))
+      DateTime.parse(File.read(Sass::Util.scope('VERSION_DATE')).strip)
+    end
+  end
+
+  extend Sass::Version
+
+  # A string representing the version of Sass.
+  # A more fine-grained representation is available from Sass.version.
+  # @api public
+  VERSION = version[:string] unless defined?(Sass::VERSION)
+end
diff --git a/backends/css/gems/sass-3.2.12/rails/init.rb b/backends/css/gems/sass-3.4.9/rails/init.rb
similarity index 100%
rename from backends/css/gems/sass-3.2.12/rails/init.rb
rename to backends/css/gems/sass-3.4.9/rails/init.rb
diff --git a/backends/css/gems/sass-3.4.9/test/sass/cache_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/cache_test.rb
new file mode 100755
index 0000000..b03be89
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/cache_test.rb
@@ -0,0 +1,131 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../test_helper'
+require File.dirname(__FILE__) + '/test_helper'
+require 'sass/engine'
+
+class CacheTest < MiniTest::Test
+  @@cache_dir = "tmp/file_cache"
+
+  def setup
+    FileUtils.mkdir_p @@cache_dir
+  end
+
+  def teardown
+    FileUtils.rm_rf @@cache_dir
+    clean_up_sassc
+  end
+
+  def test_file_cache_writes_a_file
+    file_store = Sass::CacheStores::Filesystem.new(@@cache_dir)
+    file_store.store("asdf/foo.scssc", "fakesha1", root_node)
+    assert File.exist?("#{@@cache_dir}/asdf/foo.scssc")
+  end
+
+  def test_file_cache_reads_a_file
+    file_store = Sass::CacheStores::Filesystem.new(@@cache_dir)
+    assert !File.exist?("#{@@cache_dir}/asdf/foo.scssc")
+    file_store.store("asdf/foo.scssc", "fakesha1", root_node)
+    assert File.exist?("#{@@cache_dir}/asdf/foo.scssc")
+    assert_kind_of Sass::Tree::RootNode, file_store.retrieve("asdf/foo.scssc", "fakesha1")
+  end
+
+  def test_file_cache_miss_returns_nil
+    file_store = Sass::CacheStores::Filesystem.new(@@cache_dir)
+    assert !File.exist?("#{@@cache_dir}/asdf/foo.scssc")
+    assert_nil file_store.retrieve("asdf/foo.scssc", "fakesha1")
+  end
+
+  def test_sha_change_invalidates_cache_and_cleans_up
+    file_store = Sass::CacheStores::Filesystem.new(@@cache_dir)
+    assert !File.exist?("#{@@cache_dir}/asdf/foo.scssc")
+    file_store.store("asdf/foo.scssc", "fakesha1", root_node)
+    assert File.exist?("#{@@cache_dir}/asdf/foo.scssc")
+    assert_nil file_store.retrieve("asdf/foo.scssc", "differentsha1")
+    assert !File.exist?("#{@@cache_dir}/asdf/foo.scssc")
+  end
+
+  def test_version_change_invalidates_cache_and_cleans_up
+    file_store = Sass::CacheStores::Filesystem.new(@@cache_dir)
+    assert !File.exist?("#{@@cache_dir}/asdf/foo.scssc")
+    file_store.store("asdf/foo.scssc", "fakesha1", root_node)
+    assert File.exist?("#{@@cache_dir}/asdf/foo.scssc")
+    real_version = Sass::VERSION
+    begin
+      Sass::VERSION.replace("a different version")
+      assert_nil file_store.retrieve("asdf/foo.scssc", "fakesha1")
+      assert !File.exist?("#{@@cache_dir}/asdf/foo.scssc")
+    ensure
+      Sass::VERSION.replace(real_version)
+    end
+  end
+
+  def test_arbitrary_objects_can_go_into_cache
+    cache = Sass::CacheStores::Memory.new
+    an_object = {:foo => :bar}
+    cache.store("an_object", "", an_object)
+    assert_equal an_object, cache.retrieve("an_object", "")
+  end
+
+  def test_cache_node_with_unmarshalable_option
+    engine_with_unmarshalable_options("foo {a: b + c}").to_tree
+  end
+
+  # Regression tests
+
+  def test_cache_mixin_def_splat_sass_node_with_unmarshalable_option
+    engine_with_unmarshalable_options(<<SASS, :syntax => :sass).to_tree
+=color($args...)
+  color: red
+SASS
+  end
+
+  def test_cache_mixin_def_splat_scss_node_with_unmarshalable_option
+    engine_with_unmarshalable_options(<<SCSS, :syntax => :scss).to_tree
+ mixin color($args...) {
+  color: red;
+}
+SCSS
+  end
+
+  def test_cache_function_splat_sass_node_with_unmarshalable_option
+    engine_with_unmarshalable_options(<<SASS, :syntax => :sass).to_tree
+ function color($args...)
+  @return red
+SASS
+  end
+
+  def test_cache_function_splat_scss_node_with_unmarshalable_option
+    engine_with_unmarshalable_options(<<SCSS, :syntax => :scss).to_tree
+ function color($args...) {
+  @return red;
+}
+SCSS
+  end
+
+  def test_cache_include_splat_sass_node_with_unmarshalable_option
+    engine_with_unmarshalable_options(<<SASS, :syntax => :sass).to_tree
+ include color($args..., $kwargs...)
+SASS
+  end
+
+  def test_cache_include_splat_scss_node_with_unmarshalable_option
+    engine_with_unmarshalable_options(<<SCSS, :syntax => :scss).to_tree
+ include color($args..., $kwargs...);
+SCSS
+  end
+
+  private
+  def root_node
+    Sass::Engine.new(<<-SCSS, :syntax => :scss).to_tree
+      @mixin color($c) { color: $c}
+      div { @include color(red); }
+    SCSS
+  end
+
+  def engine_with_unmarshalable_options(src, options={})
+    Sass::Engine.new(src, {
+      :syntax => :scss, :object => Class.new.new, :filename => 'file.scss',
+      :importer => Sass::Importers::Filesystem.new(absolutize('templates'))
+    }.merge(options))
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/test/sass/callbacks_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/callbacks_test.rb
new file mode 100755
index 0000000..0e72112
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/callbacks_test.rb
@@ -0,0 +1,61 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../test_helper'
+require 'sass/callbacks'
+
+class CallerBack
+  extend Sass::Callbacks
+  define_callback :foo
+  define_callback :bar
+
+  def do_foo
+    run_foo
+  end
+
+  def do_bar
+    run_bar 12
+  end
+end
+
+module ClassLevelCallerBack
+  extend Sass::Callbacks
+  define_callback :foo
+  extend self
+
+  def do_foo
+    run_foo
+  end
+end
+
+class SassCallbacksTest < MiniTest::Test
+  def test_simple_callback
+    cb = CallerBack.new
+    there = false
+    cb.on_foo {there = true}
+    cb.do_foo
+    assert there, "Expected callback to be called."
+  end
+
+  def test_multiple_callbacks
+    cb = CallerBack.new
+    str = ""
+    cb.on_foo {str += "first"}
+    cb.on_foo {str += " second"}
+    cb.do_foo
+    assert_equal "first second", str
+  end
+
+  def test_callback_with_arg
+    cb = CallerBack.new
+    val = nil
+    cb.on_bar {|a| val = a}
+    cb.do_bar
+    assert_equal 12, val
+  end
+
+  def test_class_level_callback
+    there = false
+    ClassLevelCallerBack.on_foo {there = true}
+    ClassLevelCallerBack.do_foo
+    assert there, "Expected callback to be called."
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/test/sass/compiler_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/compiler_test.rb
new file mode 100755
index 0000000..d986f26
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/compiler_test.rb
@@ -0,0 +1,236 @@
+#!/usr/bin/env ruby
+require 'minitest/autorun'
+require File.dirname(__FILE__) + '/../test_helper'
+require 'sass/plugin'
+require 'sass/plugin/compiler'
+
+class CompilerTest < MiniTest::Test
+  class FakeListener
+    attr_accessor :options
+    attr_accessor :directories
+    attr_reader :start_called
+    attr_reader :thread
+
+    def initialize(*args, &on_filesystem_event)
+      self.options = args.last.is_a?(Hash) ? args.pop : {}
+      self.directories = args
+      @on_filesystem_event = on_filesystem_event
+      @start_called = false
+      reset_events!
+    end
+
+    def fire_events!(*args)
+      @on_filesystem_event.call(@modified, @added, @removed)
+      reset_events!
+    end
+
+    def changed(filename)
+      @modified << File.expand_path(filename)
+    end
+
+    def added(filename)
+      @added << File.expand_path(filename)
+    end
+
+    def removed(filename)
+      @removed << File.expand_path(filename)
+    end
+
+    def on_start!(&run_during_start)
+      @run_during_start = run_during_start
+    end
+
+    # used for Listen < 2.0
+    def start!
+      @run_during_start.call(self) if @run_during_start
+    end
+
+    # used for Listen >= 2.0
+    def start
+      parent = Thread.current
+      @thread = Thread.new do
+        @run_during_start.call(self) if @run_during_start
+        parent.raise Interrupt
+      end
+    end
+
+    def stop
+    end
+
+    def reset_events!
+      @modified = []
+      @added = []
+      @removed = []
+    end
+  end
+
+  module MockWatcher
+    attr_accessor :run_during_start
+    attr_accessor :update_stylesheets_times
+    attr_accessor :update_stylesheets_called_with
+    attr_accessor :deleted_css_files
+
+    def fake_listener
+      @fake_listener
+    end
+
+    def update_stylesheets(individual_files)
+      @update_stylesheets_times ||= 0
+      @update_stylesheets_times += 1
+      (@update_stylesheets_called_with ||= []) << individual_files
+    end
+
+    def try_delete_css(css_filename)
+      (@deleted_css_files ||= []) << css_filename
+    end
+
+    private
+    def create_listener(*args, &on_filesystem_event)
+      if Sass::Util.listen_geq_2?
+        options = args.pop if args.last.is_a?(Hash)
+        args.map do |dir|
+          @fake_listener = FakeListener.new(*args, &on_filesystem_event)
+          @fake_listener.on_start!(&run_during_start)
+          @fake_listener
+        end
+      else
+        @fake_listener = FakeListener.new(*args, &on_filesystem_event)
+        @fake_listener.on_start!(&run_during_start)
+        @fake_listener
+      end
+    end
+  end
+
+  def test_initialize
+    watcher
+  end
+
+  def test_watch_starts_the_listener
+    start_called = false
+    c = watcher do |listener|
+      start_called = true
+    end
+    c.watch
+    assert start_called, "start! was not called"
+  end
+
+  def test_sass_callbacks_fire_from_listener_events
+    c = watcher do |listener|
+      listener.changed "changed.scss"
+      listener.added "added.scss"
+      listener.removed "removed.scss"
+      listener.fire_events!
+    end
+
+    modified_fired = false
+    c.on_template_modified do |sass_file|
+      modified_fired = true
+      assert_equal "changed.scss", sass_file
+    end
+
+    added_fired = false
+    c.on_template_created do |sass_file|
+      added_fired = true
+      assert_equal "added.scss", sass_file
+    end
+
+    removed_fired = false
+    c.on_template_deleted do |sass_file|
+      removed_fired = true
+      assert_equal "removed.scss", sass_file
+    end
+
+    c.watch
+
+    assert_equal 2, c.update_stylesheets_times
+    assert modified_fired
+    assert added_fired
+    assert removed_fired
+  end
+
+  def test_removing_a_sass_file_removes_corresponding_css_file
+    c = watcher do |listener|
+      listener.removed "remove_me.scss"
+      listener.fire_events!
+    end
+
+    c.watch
+
+    assert_equal "./remove_me.css", c.deleted_css_files.first
+  end
+
+  def test_an_importer_can_watch_an_image
+    image_importer = Sass::Importers::Filesystem.new(".")
+    class << image_importer
+      def watched_file?(filename)
+        filename =~ /\.png$/
+      end
+    end
+    c = watcher(:load_paths => [image_importer]) do |listener|
+      listener.changed "image.png"
+      listener.fire_events!
+    end
+
+    modified_fired = false
+    c.on_template_modified do |f|
+      modified_fired = true
+      assert_equal "image.png", f
+    end
+
+    c.watch
+
+    assert_equal 2, c.update_stylesheets_times
+    assert modified_fired
+  end
+
+  def test_watching_specific_files_and_one_is_deleted
+    directories = nil
+    c = watcher do |listener|
+      directories = listener.directories
+      listener.removed File.expand_path("./foo.scss")
+      listener.fire_events!
+    end
+    c.watch([[File.expand_path("./foo.scss"), File.expand_path("./foo.css"), nil]])
+    assert directories.include?(File.expand_path(".")), directories.inspect
+    assert_equal File.expand_path("./foo.css"), c.deleted_css_files.first, "the corresponding css file was 
not deleted"
+    assert_equal [], c.update_stylesheets_called_with[1], "the sass file should not have been compiled"
+  end
+
+  def test_watched_directories_are_dedupped
+    directories = nil
+    c = watcher(:load_paths => [".", "./foo", "."]) do |listener|
+      directories = listener.directories
+    end
+    c.watch
+    assert_equal [File.expand_path(".")], directories
+  end
+
+  def test_a_changed_css_in_a_watched_directory_does_not_force_a_compile
+    c = watcher do |listener|
+      listener.changed "foo.css"
+      listener.fire_events!
+    end
+
+    c.on_template_modified do |f|
+      assert false, "Should not have been called"
+    end
+
+    c.watch
+
+    assert_equal 1, c.update_stylesheets_times
+  end
+
+  private
+
+  def default_options
+    {:template_location => [[".","."]]}
+  end
+
+  def watcher(options = {}, &run_during_start)
+    options = default_options.merge(options)
+    watcher = Sass::Plugin::Compiler.new(options)
+    watcher.extend(MockWatcher)
+    watcher.run_during_start = run_during_start
+    watcher
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/test/sass/conversion_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/conversion_test.rb
new file mode 100755
index 0000000..3c7941a
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/conversion_test.rb
@@ -0,0 +1,2069 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../test_helper'
+
+class ConversionTest < MiniTest::Test
+  def test_basic
+    assert_renders <<SASS, <<SCSS
+foo bar
+  baz: bang
+  bip: bop
+SASS
+foo bar {
+  baz: bang;
+  bip: bop;
+}
+SCSS
+    assert_renders <<SASS, <<SCSS, :old => true
+foo bar
+  :baz bang
+  :bip bop
+SASS
+foo bar {
+  baz: bang;
+  bip: bop;
+}
+SCSS
+  end
+
+  def test_empty_selector
+    assert_renders "foo bar", "foo bar {}"
+  end
+
+  def test_empty_directive
+    assert_renders "@media screen", "@media screen {}"
+  end
+
+  def test_empty_control_directive
+    assert_renders "@if false", "@if false {}"
+  end
+
+  def test_nesting
+    assert_renders <<SASS, <<SCSS
+foo bar
+  baz bang
+    baz: bang
+    bip: bop
+  blat: boo
+SASS
+foo bar {
+  baz bang {
+    baz: bang;
+    bip: bop;
+  }
+  blat: boo;
+}
+SCSS
+  end
+
+  def test_nesting_with_parent_ref
+    assert_renders <<SASS, <<SCSS
+foo bar
+  &:hover
+    baz: bang
+SASS
+foo bar {
+  &:hover {
+    baz: bang;
+  }
+}
+SCSS
+  end
+
+  def test_selector_interpolation
+    assert_renders <<SASS, <<SCSS
+foo \#{$bar + "baz"}.bip
+  baz: bang
+
+foo /\#{$bar + "baz"}/ .bip
+  baz: bang
+SASS
+foo \#{$bar + "baz"}.bip {
+  baz: bang;
+}
+
+foo /\#{$bar + "baz"}/ .bip {
+  baz: bang;
+}
+SCSS
+  end
+
+  def test_multiline_selector_with_commas
+    assert_renders <<SASS, <<SCSS
+foo bar,
+baz bang
+  baz: bang
+SASS
+foo bar,
+baz bang {
+  baz: bang;
+}
+SCSS
+
+    assert_renders <<SASS, <<SCSS
+blat
+  foo bar,
+  baz bang
+    baz: bang
+SASS
+blat {
+  foo bar,
+  baz bang {
+    baz: bang;
+  }
+}
+SCSS
+  end
+
+  def test_multiline_selector_without_commas
+    assert_scss_to_sass <<SASS, <<SCSS
+foo bar baz bang
+  baz: bang
+SASS
+foo bar
+baz bang {
+  baz: bang;
+}
+SCSS
+
+    assert_scss_to_scss <<SCSS
+foo bar
+baz bang {
+  baz: bang;
+}
+SCSS
+  end
+
+  def test_escaped_selector
+    assert_renders <<SASS, <<SCSS
+foo bar
+  \\:hover
+    baz: bang
+SASS
+foo bar {
+  :hover {
+    baz: bang;
+  }
+}
+SCSS
+  end
+
+  def test_property_name_interpolation
+    assert_renders <<SASS, <<SCSS
+foo bar
+  baz\#{$bang}bip\#{$bop}: 12
+SASS
+foo bar {
+  baz\#{$bang}bip\#{$bop}: 12;
+}
+SCSS
+  end
+
+  def test_property_value_interpolation
+    assert_renders <<SASS, <<SCSS
+foo bar
+  baz: 12 \#{$bang} bip \#{"bop"} blat
+SASS
+foo bar {
+  baz: 12 \#{$bang} bip \#{"bop"} blat;
+}
+SCSS
+  end
+
+  def test_dynamic_properties
+    assert_renders <<SASS, <<SCSS
+foo bar
+  baz: 12 $bang "bip"
+SASS
+foo bar {
+  baz: 12 $bang "bip";
+}
+SCSS
+  end
+
+  def test_dynamic_properties_with_old
+    assert_renders <<SASS, <<SCSS, :old => true
+foo bar
+  :baz 12 $bang "bip"
+SASS
+foo bar {
+  baz: 12 $bang "bip";
+}
+SCSS
+  end
+
+  def test_multiline_properties
+    assert_scss_to_sass <<SASS, <<SCSS
+foo bar
+  baz: bip bam boon
+SASS
+foo bar {
+  baz:
+    bip
+  bam
+        boon;
+}
+SCSS
+
+    assert_scss_to_scss <<OUT, <<IN
+foo bar {
+  baz: bip bam boon;
+}
+OUT
+foo bar {
+  baz:
+    bip
+  bam
+        boon;
+}
+IN
+  end
+
+  def test_multiline_dynamic_properties
+    assert_scss_to_sass <<SASS, <<SCSS
+foo bar
+  baz: $bip "bam" 12px
+SASS
+foo bar {
+  baz:
+    $bip
+  "bam"
+        12px;
+}
+SCSS
+
+    assert_scss_to_scss <<OUT, <<IN
+foo bar {
+  baz: $bip "bam" 12px;
+}
+OUT
+foo bar {
+  baz:
+    $bip
+  "bam"
+        12px;
+}
+IN
+  end
+
+  def test_silent_comments
+    assert_renders <<SASS, <<SCSS
+// foo
+
+// bar
+
+// baz
+
+foo bar
+  a: b
+SASS
+// foo
+
+// bar
+
+// baz
+
+foo bar {
+  a: b;
+}
+SCSS
+
+    assert_renders <<SASS, <<SCSS
+// foo
+// bar
+//   baz
+// bang
+
+foo bar
+  a: b
+SASS
+// foo
+// bar
+//   baz
+// bang
+
+foo bar {
+  a: b;
+}
+SCSS
+
+    assert_renders <<SASS, <<SCSS
+// foo
+// bar
+//   baz
+// bang
+
+foo bar
+  a: b
+SASS
+// foo
+// bar
+//   baz
+// bang
+
+foo bar {
+  a: b;
+}
+SCSS
+  end
+
+  def test_nested_silent_comments
+    assert_renders <<SASS, <<SCSS
+foo
+  bar: baz
+  // bip bop
+  // beep boop
+  bang: bizz
+  // bubble bubble
+  // toil trouble
+SASS
+foo {
+  bar: baz;
+  // bip bop
+  // beep boop
+  bang: bizz;
+  // bubble bubble
+  // toil trouble
+}
+SCSS
+
+    assert_sass_to_scss <<SCSS, <<SASS
+foo {
+  bar: baz;
+  // bip bop
+  // beep boop
+  //   bap blimp
+  bang: bizz;
+  // bubble bubble
+  // toil trouble
+  //    gorp
+}
+SCSS
+foo
+  bar: baz
+  // bip bop
+     beep boop
+       bap blimp
+  bang: bizz
+  // bubble bubble
+    toil trouble
+       gorp
+SASS
+  end
+
+  def test_preserves_triple_slash_comments
+    assert_renders <<SASS, <<SCSS
+/// foo
+/// bar
+foo
+  /// bip bop
+  /// beep boop
+SASS
+/// foo
+/// bar
+foo {
+  /// bip bop
+  /// beep boop
+}
+SCSS
+  end
+
+  def test_loud_comments
+    assert_renders <<SASS, <<SCSS
+/* foo
+
+/* bar
+
+/* baz
+
+foo bar
+  a: b
+SASS
+/* foo */
+
+/* bar */
+
+/* baz */
+
+foo bar {
+  a: b;
+}
+SCSS
+
+    assert_scss_to_sass <<SASS, <<SCSS
+/* foo
+ * bar
+ *   baz
+ * bang
+
+foo bar
+  a: b
+SASS
+/* foo
+   bar
+     baz
+   bang */
+
+foo bar {
+  a: b;
+}
+SCSS
+
+    assert_scss_to_scss <<SCSS
+/* foo
+   bar
+     baz
+   bang */
+
+foo bar {
+  a: b;
+}
+SCSS
+
+    assert_renders <<SASS, <<SCSS
+/* foo
+ * bar
+ *   baz
+ * bang
+
+foo bar
+  a: b
+SASS
+/* foo
+ * bar
+ *   baz
+ * bang */
+
+foo bar {
+  a: b;
+}
+SCSS
+  end
+
+  def test_nested_loud_comments
+    assert_renders <<SASS, <<SCSS
+foo
+  bar: baz
+  /* bip bop
+   * beep boop
+  bang: bizz
+  /* bubble bubble
+   * toil trouble
+SASS
+foo {
+  bar: baz;
+  /* bip bop
+   * beep boop */
+  bang: bizz;
+  /* bubble bubble
+   * toil trouble */
+}
+SCSS
+
+    assert_sass_to_scss <<SCSS, <<SASS
+foo {
+  bar: baz;
+  /* bip bop
+   * beep boop
+   *   bap blimp */
+  bang: bizz;
+  /* bubble bubble
+   * toil trouble
+   *    gorp */
+}
+SCSS
+foo
+  bar: baz
+  /* bip bop
+     beep boop
+       bap blimp
+  bang: bizz
+  /* bubble bubble
+    toil trouble
+       gorp
+SASS
+  end
+
+  def test_preserves_double_star_comments
+    assert_renders <<SASS, <<SCSS
+/** foo
+ *  bar
+foo
+  /** bip bop
+   *  beep boop
+SASS
+/** foo
+ *  bar */
+foo {
+  /** bip bop
+   *  beep boop */
+}
+SCSS
+  end
+
+  def test_loud_comments_with_weird_indentation
+    assert_scss_to_sass <<SASS, <<SCSS
+foo
+  /*      foo
+   * bar
+   *     baz
+  a: b
+SASS
+foo {
+  /* foo
+bar
+    baz */
+  a: b;
+}
+SCSS
+
+    assert_sass_to_scss <<SCSS, <<SASS
+foo {
+  /*      foo
+   * bar
+   *     baz */
+  a: b;
+}
+SCSS
+foo
+  /*      foo
+     bar
+         baz
+  a: b
+SASS
+  end
+
+  def test_loud_comment_containing_silent_comment
+    assert_scss_to_sass <<SASS, <<SCSS
+/*
+ *// foo bar
+SASS
+/*
+// foo bar
+*/
+SCSS
+  end
+
+  def test_silent_comment_containing_loud_comment
+    assert_scss_to_sass <<SASS, <<SCSS
+// /*
+//  * foo bar
+//  */
+SASS
+// /*
+//  * foo bar
+//  */
+SCSS
+  end
+
+  def test_immediately_preceding_comments
+    assert_renders <<SASS, <<SCSS
+/* Foo
+ * Bar
+ * Baz
+.foo#bar
+  a: b
+SASS
+/* Foo
+ * Bar
+ * Baz */
+.foo#bar {
+  a: b;
+}
+SCSS
+
+    assert_renders <<SASS, <<SCSS
+// Foo
+// Bar
+// Baz
+=foo
+  a: b
+SASS
+// Foo
+// Bar
+// Baz
+ mixin foo {
+  a: b;
+}
+SCSS
+  end
+
+  def test_immediately_following_comments
+    assert_sass_to_scss <<SCSS, <<SASS
+.foobar {
+  // trailing comment
+  a: 1px;
+}
+SCSS
+.foobar // trailing comment
+  a: 1px
+SASS
+
+    assert_sass_to_scss <<SCSS, <<SASS
+.foobar {
+  // trailing comment
+  a: 1px;
+}
+SCSS
+.foobar  /* trailing comment */
+  a: 1px
+SASS
+  end
+
+  def test_debug
+    assert_renders <<SASS, <<SCSS
+foo
+  @debug 12px
+  bar: baz
+SASS
+foo {
+  @debug 12px;
+  bar: baz;
+}
+SCSS
+  end
+
+  def test_error
+    assert_renders <<SASS, <<SCSS
+foo
+  @error "oh no!"
+  bar: baz
+SASS
+foo {
+  @error "oh no!";
+  bar: baz;
+}
+SCSS
+  end
+
+  def test_directive_without_children
+    assert_renders <<SASS, <<SCSS
+foo
+  @foo #bar "baz"
+  bar: baz
+SASS
+foo {
+  @foo #bar "baz";
+  bar: baz;
+}
+SCSS
+  end
+
+  def test_directive_with_prop_children
+    assert_renders <<SASS, <<SCSS
+foo
+  @foo #bar "baz"
+    a: b
+    c: d
+
+  bar: baz
+SASS
+foo {
+  @foo #bar "baz" {
+    a: b;
+    c: d;
+  }
+
+  bar: baz;
+}
+SCSS
+  end
+
+  def test_directive_with_rule_children
+    assert_renders <<SASS, <<SCSS
+foo
+  @foo #bar "baz"
+    #blat
+      a: b
+    .bang
+      c: d
+      e: f
+
+  bar: baz
+SASS
+foo {
+  @foo #bar "baz" {
+    #blat {
+      a: b;
+    }
+    .bang {
+      c: d;
+      e: f;
+    }
+  }
+
+  bar: baz;
+}
+SCSS
+  end
+
+  def test_directive_with_rule_and_prop_children
+    assert_renders <<SASS, <<SCSS
+foo
+  @foo #bar "baz"
+    g: h
+    #blat
+      a: b
+    .bang
+      c: d
+      e: f
+    i: j
+
+  bar: baz
+SASS
+foo {
+  @foo #bar "baz" {
+    g: h;
+    #blat {
+      a: b;
+    }
+    .bang {
+      c: d;
+      e: f;
+    }
+    i: j;
+  }
+
+  bar: baz;
+}
+SCSS
+  end
+
+  def test_charset
+    assert_renders <<SASS, <<SCSS
+ charset "utf-8"
+SASS
+ charset "utf-8";
+SCSS
+  end
+
+  def test_for
+    assert_renders <<SASS, <<SCSS
+foo
+  @for $a from $b to $c
+    a: b
+  @for $c from 1 to 16
+    d: e
+    f: g
+SASS
+foo {
+  @for $a from $b to $c {
+    a: b;
+  }
+  @for $c from 1 to 16 {
+    d: e;
+    f: g;
+  }
+}
+SCSS
+  end
+
+  def test_while
+    assert_renders <<SASS, <<SCSS
+foo
+  @while flaz($a + $b)
+    a: b
+  @while 1
+    d: e
+    f: g
+SASS
+foo {
+  @while flaz($a + $b) {
+    a: b;
+  }
+  @while 1 {
+    d: e;
+    f: g;
+  }
+}
+SCSS
+  end
+
+  def test_if
+    assert_renders <<SASS, <<SCSS
+foo
+  @if $foo or $bar
+    a: b
+  @if $baz
+    d: e
+  @else if $bang
+    f: g
+  @else
+    h: i
+SASS
+foo {
+  @if $foo or $bar {
+    a: b;
+  }
+  @if $baz {
+    d: e;
+  }
+  @else if $bang {
+    f: g;
+  }
+  @else {
+    h: i;
+  }
+}
+SCSS
+  end
+
+  def test_each
+    assert_renders <<SASS, <<SCSS
+a
+  @each $number in 1px 2px 3px 4px
+    b: $number
+
+c
+  @each $str in foo, bar, baz, bang
+    d: $str
+
+c
+  @each $key, $value in (foo: 1, bar: 2, baz: 3)
+    \#{$key}: $value
+SASS
+a {
+  @each $number in 1px 2px 3px 4px {
+    b: $number;
+  }
+}
+
+c {
+  @each $str in foo, bar, baz, bang {
+    d: $str;
+  }
+}
+
+c {
+  @each $key, $value in (foo: 1, bar: 2, baz: 3) {
+    \#{$key}: $value;
+  }
+}
+SCSS
+  end
+
+  def test_import
+    assert_renders <<SASS, <<SCSS
+ import foo
+
+ import url(bar.css)
+
+foo
+  bar: baz
+SASS
+ import "foo";
+
+ import url(bar.css);
+
+foo {
+  bar: baz;
+}
+SCSS
+
+    assert_renders <<SASS, <<SCSS
+ import foo.css
+
+ import url(bar.css)
+
+foo
+  bar: baz
+SASS
+ import "foo.css";
+
+ import url(bar.css);
+
+foo {
+  bar: baz;
+}
+SCSS
+  end
+
+  def test_import_as_directive_in_sass
+    assert_equal "@import foo.css\n", to_sass('@import "foo.css"')
+  end
+
+  def test_import_as_directive_in_scss
+    assert_renders <<SASS, <<SCSS
+ import "foo.css" print
+SASS
+ import "foo.css" print;
+SCSS
+
+    assert_renders <<SASS, <<SCSS
+ import url(foo.css) screen, print
+SASS
+ import url(foo.css) screen, print;
+SCSS
+  end
+
+  def test_adjacent_imports
+    assert_renders <<SASS, <<SCSS
+ import foo.sass
+ import bar.scss
+ import baz
+SASS
+ import "foo.sass";
+ import "bar.scss";
+ import "baz";
+SCSS
+  end
+
+  def test_non_adjacent_imports
+    assert_renders <<SASS, <<SCSS
+ import foo.sass
+
+ import bar.scss
+
+ import baz
+SASS
+ import "foo.sass";
+
+ import "bar.scss";
+
+ import "baz";
+SCSS
+  end
+
+  def test_import_with_interpolation
+    assert_renders <<SASS, <<SCSS
+$family: unquote("Droid+Sans")
+
+ import url("http://fonts.googleapis.com/css?family=\#{$family}";)
+SASS
+$family: unquote("Droid+Sans");
+
+ import url("http://fonts.googleapis.com/css?family=\#{$family}";);
+SCSS
+  end
+
+  def test_extend
+    assert_renders <<SASS, <<SCSS
+.foo
+  @extend .bar
+  @extend .baz:bang
+SASS
+.foo {
+  @extend .bar;
+  @extend .baz:bang;
+}
+SCSS
+  end
+
+  def test_comma_extendee
+    assert_renders <<SASS, <<SCSS
+.baz
+  @extend .foo, .bar
+SASS
+.baz {
+  @extend .foo, .bar;
+}
+SCSS
+  end
+
+  def test_argless_mixin_definition
+    assert_renders <<SASS, <<SCSS
+=foo-bar
+  baz
+    a: b
+SASS
+ mixin foo-bar {
+  baz {
+    a: b;
+  }
+}
+SCSS
+
+    assert_scss_to_sass <<SASS, <<SCSS
+=foo-bar
+  baz
+    a: b
+SASS
+ mixin foo-bar() {
+  baz {
+    a: b;
+  }
+}
+SCSS
+
+    assert_sass_to_scss <<SCSS, <<SASS
+ mixin foo-bar {
+  baz {
+    a: b;
+  }
+}
+SCSS
+=foo-bar()
+  baz
+    a: b
+SASS
+  end
+
+  def test_mixin_definition_without_defaults
+    assert_renders <<SASS, <<SCSS
+=foo-bar($baz, $bang)
+  baz
+    a: $baz $bang
+SASS
+ mixin foo-bar($baz, $bang) {
+  baz {
+    a: $baz $bang;
+  }
+}
+SCSS
+  end
+
+  def test_mixin_definition_with_defaults
+    assert_renders <<SASS, <<SCSS
+=foo-bar($baz, $bang: 12px)
+  baz
+    a: $baz $bang
+SASS
+ mixin foo-bar($baz, $bang: 12px) {
+  baz {
+    a: $baz $bang;
+  }
+}
+SCSS
+
+    assert_sass_to_scss <<SCSS, <<SASS
+ mixin foo-bar($baz, $bang: foo) {
+  baz {
+    a: $baz $bang;
+  }
+}
+SCSS
+=foo-bar($baz, $bang: foo)
+  baz
+    a: $baz $bang
+SASS
+  end
+
+  def test_argless_mixin_include
+    assert_renders <<SASS, <<SCSS
+foo
+  +foo-bar
+  a: blip
+SASS
+foo {
+  @include foo-bar;
+  a: blip;
+}
+SCSS
+  end
+
+  def test_mixin_include
+    assert_renders <<SASS, <<SCSS
+foo
+  +foo-bar(12px, "blaz")
+  a: blip
+SASS
+foo {
+  @include foo-bar(12px, "blaz");
+  a: blip;
+}
+SCSS
+  end
+
+  def test_mixin_include_with_keyword_args
+    assert_renders <<SASS, <<SCSS
+foo
+  +foo-bar(12px, "blaz", $blip: blap, $bloop: blop)
+  +foo-bar($blip: blap, $bloop: blop)
+  a: blip
+SASS
+foo {
+  @include foo-bar(12px, "blaz", $blip: blap, $bloop: blop);
+  @include foo-bar($blip: blap, $bloop: blop);
+  a: blip;
+}
+SCSS
+  end
+
+  def test_mixin_include_with_hyphen_conversion_keyword_arg
+    assert_renders <<SASS, <<SCSS
+foo
+  +foo-bar($a-b_c: val)
+  a: blip
+SASS
+foo {
+  @include foo-bar($a-b_c: val);
+  a: blip;
+}
+SCSS
+  end
+
+  def test_argless_function_definition
+    assert_renders <<SASS, <<SCSS
+ function foo()
+  $var: 1 + 1
+  @return $var
+SASS
+ function foo() {
+  $var: 1 + 1;
+  @return $var;
+}
+SCSS
+  end
+
+  def test_function_definition_without_defaults
+    assert_renders <<SASS, <<SCSS
+ function foo($var1, $var2)
+  @if $var1
+    @return $var1 + $var2
+SASS
+ function foo($var1, $var2) {
+  @if $var1 {
+    @return $var1 + $var2;
+  }
+}
+SCSS
+  end
+
+  def test_function_definition_with_defaults
+    assert_renders <<SASS, <<SCSS
+ function foo($var1, $var2: foo)
+  @if $var1
+    @return $var1 + $var2
+SASS
+ function foo($var1, $var2: foo) {
+  @if $var1 {
+    @return $var1 + $var2;
+  }
+}
+SCSS
+  end
+
+  def test_variable_definition
+    assert_renders <<SASS, <<SCSS
+$var1: 12px + 15px
+
+foo
+  $var2: flaz(#abcdef)
+  val: $var1 $var2
+SASS
+$var1: 12px + 15px;
+
+foo {
+  $var2: flaz(#abcdef);
+  val: $var1 $var2;
+}
+SCSS
+  end
+
+  def test_guarded_variable_definition
+    assert_renders <<SASS, <<SCSS
+$var1: 12px + 15px !default
+
+foo
+  $var2: flaz(#abcdef) !default
+  val: $var1 $var2
+SASS
+$var1: 12px + 15px !default;
+
+foo {
+  $var2: flaz(#abcdef) !default;
+  val: $var1 $var2;
+}
+SCSS
+  end
+
+  def test_multiple_variable_definitions
+    assert_renders <<SASS, <<SCSS
+$var1: foo
+$var2: bar
+$var3: baz
+
+$var4: bip
+$var5: bap
+SASS
+$var1: foo;
+$var2: bar;
+$var3: baz;
+
+$var4: bip;
+$var5: bap;
+SCSS
+  end
+
+  def test_division_asserted_with_parens
+    assert_renders <<SASS, <<SCSS
+foo
+  a: (1px / 2px)
+SASS
+foo {
+  a: (1px / 2px);
+}
+SCSS
+  end
+
+  def test_division_not_asserted_when_unnecessary
+    assert_renders <<SASS, <<SCSS
+$var: 1px / 2px
+
+foo
+  a: $var
+SASS
+$var: 1px / 2px;
+
+foo {
+  a: $var;
+}
+SCSS
+
+    assert_renders <<SASS, <<SCSS
+$var: 1px
+
+foo
+  a: $var / 2px
+SASS
+$var: 1px;
+
+foo {
+  a: $var / 2px;
+}
+SCSS
+
+    assert_renders <<SASS, <<SCSS
+foo
+  a: 1 + 1px / 2px
+SASS
+foo {
+  a: 1 + 1px / 2px;
+}
+SCSS
+  end
+
+  def test_literal_slash
+    assert_renders <<SASS, <<SCSS
+foo
+  a: 1px / 2px
+SASS
+foo {
+  a: 1px / 2px;
+}
+SCSS
+  end
+
+  def test_directive_with_interpolation
+    assert_renders <<SASS, <<SCSS
+$baz: 12
+
+ foo bar\#{$baz} qux
+  a: b
+SASS
+$baz: 12;
+
+ foo bar\#{$baz} qux {
+  a: b;
+}
+SCSS
+  end
+
+  def test_media_with_interpolation
+    assert_renders <<SASS, <<SCSS
+$baz: 12
+
+ media bar\#{$baz}
+  a: b
+SASS
+$baz: 12;
+
+ media bar\#{$baz} {
+  a: b;
+}
+SCSS
+  end
+
+  def test_media_with_expressions
+    assert_renders <<SASS, <<SCSS
+$media1: screen
+$media2: print
+$var: -webkit-min-device-pixel-ratio
+$val: 20
+
+ media \#{$media1} and ($var + "-foo": $val + 5), only \#{$media2}
+  a: b
+SASS
+$media1: screen;
+$media2: print;
+$var: -webkit-min-device-pixel-ratio;
+$val: 20;
+
+ media \#{$media1} and ($var + "-foo": $val + 5), only \#{$media2} {
+  a: b;
+}
+SCSS
+  end
+
+  def test_media_with_feature
+    assert_renders <<SASS, <<SCSS
+ media screen and (-webkit-transform-3d)
+  a: b
+SASS
+ media screen and (-webkit-transform-3d) {
+  a: b;
+}
+SCSS
+  end
+
+  def test_supports_with_expressions
+    assert_renders <<SASS, <<SCSS
+$query: "(feature1: val)"
+$feature: feature2
+$val: val
+
+ supports \#{$query} and ($feature: $val) or (not ($feature + 3: $val + 4))
+  foo
+    a: b
+SASS
+$query: "(feature1: val)";
+$feature: feature2;
+$val: val;
+
+ supports \#{$query} and ($feature: $val) or (not ($feature + 3: $val + 4)) {
+  foo {
+    a: b;
+  }
+}
+SCSS
+  end
+
+  # Hacks
+
+  def test_declaration_hacks
+    assert_renders <<SASS, <<SCSS
+foo
+  _name: val
+  *name: val
+  #name: val
+  .name: val
+  name/**/: val
+  name/*\\**/: val
+  name: val
+SASS
+foo {
+  _name: val;
+  *name: val;
+  #name: val;
+  .name: val;
+  name/**/: val;
+  name/*\\**/: val;
+  name: val;
+}
+SCSS
+  end
+
+  def test_old_declaration_hacks
+    assert_renders <<SASS, <<SCSS, :old => true
+foo
+  :_name val
+  :*name val
+  :#name val
+  :.name val
+  :name val
+SASS
+foo {
+  _name: val;
+  *name: val;
+  #name: val;
+  .name: val;
+  name: val;
+}
+SCSS
+  end
+
+  def test_selector_hacks
+    assert_selector_renders = lambda do |s|
+      assert_renders <<SASS, <<SCSS
+#{s}
+  a: b
+SASS
+#{s} {
+  a: b;
+}
+SCSS
+    end
+
+    assert_selector_renders['> E']
+    assert_selector_renders['+ E']
+    assert_selector_renders['~ E']
+    assert_selector_renders['> > E']
+
+    assert_selector_renders['E*']
+    assert_selector_renders['E*.foo']
+    assert_selector_renders['E*:hover']
+  end
+
+  def test_disallowed_colon_hack
+    assert_raise_message(Sass::SyntaxError, 'The ":name: val" hack is not allowed in the Sass indented 
syntax') do
+      to_sass("foo {:name: val;}", :syntax => :scss)
+    end
+  end
+
+  def test_nested_properties
+    assert_renders <<SASS, <<SCSS
+div
+  before: before
+  background:
+    color: blue
+    repeat: no-repeat
+  after: after
+SASS
+div {
+  before: before;
+  background: {
+    color: blue;
+    repeat: no-repeat;
+  };
+  after: after;
+}
+
+SCSS
+  end
+
+  def test_dasherize
+    assert_sass_to_scss(<<SCSS, <<SASS, :dasherize => true)
+ mixin under-scored-mixin($under-scored-arg: $under-scored-default) {
+  bar: $under-scored-arg;
+}
+
+div {
+  foo: under-scored-fn($under-scored-var + "before\#{$another-under-scored-var}after");
+  @include under-scored-mixin($passed-arg);
+  selector-\#{$under-scored-interp}: bold;
+}
+
+ if $under-scored {
+  @for $for-var from $from-var to $to-var {
+    @while $while-var == true {
+      $while-var: false;
+    }
+  }
+}
+SCSS
+=under_scored_mixin($under_scored_arg: $under_scored_default)
+  bar: $under_scored_arg
+div
+  foo: under_scored_fn($under_scored_var + "before\#{$another_under_scored_var}after")
+  +under_scored_mixin($passed_arg)
+  selector-\#{$under_scored_interp}: bold
+ if $under_scored
+  @for $for_var from $from_var to $to_var
+    @while $while_var == true
+      $while_var : false
+SASS
+  end
+
+  def test_loud_comment_conversion
+    assert_renders(<<SASS, <<SCSS)
+/*! \#{"interpolated"}
+SASS
+/*! \#{"interpolated"} */
+SCSS
+  end
+
+  def test_content_conversion
+    assert_renders(<<SASS, <<SCSS)
+$color: blue
+
+=context($class, $color: red)
+  .\#{$class}
+    background-color: $color
+    @content
+    border-color: $color
+
++context(parent)
+  +context(child, $color: yellow)
+    color: $color
+SASS
+$color: blue;
+
+ mixin context($class, $color: red) {
+  .\#{$class} {
+    background-color: $color;
+    @content;
+    border-color: $color;
+  }
+}
+
+ include context(parent) {
+  @include context(child, $color: yellow) {
+    color: $color;
+  }
+}
+SCSS
+
+  end
+
+  def test_empty_content
+    assert_scss_to_scss(<<SCSS)
+ mixin foo {
+  @content;
+}
+
+ include foo {}
+SCSS
+  end
+
+  def test_placeholder_conversion
+    assert_renders(<<SASS, <<SCSS)
+#content a%foo.bar
+  color: blue
+SASS
+#content a%foo.bar {
+  color: blue;
+}
+SCSS
+  end
+
+  def test_reference_selector
+    assert_renders(<<SASS, <<SCSS)
+foo /bar|baz/ bang
+  a: b
+SASS
+foo /bar|baz/ bang {
+  a: b;
+}
+SCSS
+  end
+
+  def test_subject
+    assert_renders(<<SASS, <<SCSS)
+foo bar! baz
+  a: b
+SASS
+foo bar! baz {
+  a: b;
+}
+SCSS
+  end
+
+  def test_placeholder_interoplation_conversion
+    assert_renders(<<SASS, <<SCSS)
+$foo: foo
+
+%\#{$foo}
+  color: blue
+
+.bar
+  @extend %foo
+SASS
+$foo: foo;
+
+%\#{$foo} {
+  color: blue;
+}
+
+.bar {
+  @extend %foo;
+}
+SCSS
+  end
+
+  def test_indent
+    assert_renders <<SASS, <<SCSS, :indent => "    "
+foo bar
+    baz bang
+        baz: bang
+        bip: bop
+    blat: boo
+SASS
+foo bar {
+    baz bang {
+        baz: bang;
+        bip: bop;
+    }
+    blat: boo;
+}
+SCSS
+
+    assert_renders <<SASS, <<SCSS, :indent => "\t"
+foo bar
+       baz bang
+               baz: bang
+               bip: bop
+       blat: boo
+SASS
+foo bar {
+       baz bang {
+               baz: bang;
+               bip: bop;
+       }
+       blat: boo;
+}
+SCSS
+
+    assert_sass_to_scss <<SCSS, <<SASS, :indent => "    "
+foo bar {
+    baz bang {
+        baz: bang;
+        bip: bop;
+    }
+    blat: boo;
+}
+SCSS
+foo bar
+  baz bang
+    baz: bang
+    bip: bop
+  blat: boo
+SASS
+
+    assert_sass_to_scss <<SCSS, <<SASS, :indent => "\t"
+foo bar {
+       baz bang {
+               baz: bang;
+               bip: bop;
+       }
+       blat: boo;
+}
+SCSS
+foo bar
+  baz bang
+    baz: bang
+    bip: bop
+  blat: boo
+SASS
+
+    assert_scss_to_sass <<SASS, <<SCSS, :indent => "    "
+foo bar
+    baz bang
+        baz: bang
+        bip: bop
+    blat: boo
+SASS
+foo bar {
+  baz bang {
+    baz: bang;
+    bip: bop;
+  }
+  blat: boo;
+}
+SCSS
+
+    assert_scss_to_sass <<SASS, <<SCSS, :indent => "\t"
+foo bar
+       baz bang
+               baz: bang
+               bip: bop
+       blat: boo
+SASS
+foo bar {
+  baz bang {
+    baz: bang;
+    bip: bop;
+  }
+  blat: boo;
+}
+SCSS
+  end
+
+  def test_extend_with_optional
+    assert_renders <<SASS, <<SCSS
+foo
+  @extend .bar !optional
+SASS
+foo {
+  @extend .bar !optional;
+}
+SCSS
+  end
+
+  def test_mixin_var_args
+    assert_renders <<SASS, <<SCSS
+=foo($args...)
+  a: b
+
+=bar($a, $args...)
+  a: b
+
+.foo
+  +foo($list...)
+  +bar(1, $list...)
+SASS
+ mixin foo($args...) {
+  a: b;
+}
+
+ mixin bar($a, $args...) {
+  a: b;
+}
+
+.foo {
+  @include foo($list...);
+  @include bar(1, $list...);
+}
+SCSS
+  end
+
+  def test_mixin_var_kwargs
+    assert_renders <<SASS, <<SCSS
+=foo($a: b, $c: d)
+  a: $a
+  c: $c
+
+.foo
+  +foo($list..., $map...)
+  +foo(pos, $list..., $kwd: val, $map...)
+SASS
+ mixin foo($a: b, $c: d) {
+  a: $a;
+  c: $c;
+}
+
+.foo {
+  @include foo($list..., $map...);
+  @include foo(pos, $list..., $kwd: val, $map...);
+}
+SCSS
+  end
+
+  def test_function_var_args
+    assert_renders <<SASS, <<SCSS
+ function foo($args...)
+  @return foo
+
+ function bar($a, $args...)
+  @return bar
+
+.foo
+  a: foo($list...)
+  b: bar(1, $list...)
+SASS
+ function foo($args...) {
+  @return foo;
+}
+
+ function bar($a, $args...) {
+  @return bar;
+}
+
+.foo {
+  a: foo($list...);
+  b: bar(1, $list...);
+}
+SCSS
+  end
+
+  def test_function_var_kwargs
+    assert_renders <<SASS, <<SCSS
+ function foo($a: b, $c: d)
+  @return foo
+
+.foo
+  a: foo($list..., $map...)
+  b: foo(pos, $list..., $kwd: val, $map...)
+SASS
+ function foo($a: b, $c: d) {
+  @return foo;
+}
+
+.foo {
+  a: foo($list..., $map...);
+  b: foo(pos, $list..., $kwd: val, $map...);
+}
+SCSS
+  end
+
+  def test_at_root
+    assert_renders <<SASS, <<SCSS
+.foo
+  @at-root
+    .bar
+      a: b
+    .baz
+      c: d
+SASS
+.foo {
+  @at-root {
+    .bar {
+      a: b;
+    }
+    .baz {
+      c: d;
+    }
+  }
+}
+SCSS
+  end
+
+  def test_at_root_with_selector
+    assert_renders <<SASS, <<SCSS
+.foo
+  @at-root .bar
+    a: b
+SASS
+.foo {
+  @at-root .bar {
+    a: b;
+  }
+}
+SCSS
+  end
+
+  def test_at_root_without
+    assert_renders <<SASS, <<SCSS
+.foo
+  @at-root (without: media rule)
+    a: b
+SASS
+.foo {
+  @at-root (without: media rule) {
+    a: b;
+  }
+}
+SCSS
+  end
+
+  def test_at_root_with
+    assert_renders <<SASS, <<SCSS
+.foo
+  @at-root (with: media rule)
+    a: b
+SASS
+.foo {
+  @at-root (with: media rule) {
+    a: b;
+  }
+}
+SCSS
+  end
+
+  def test_function_var_kwargs_with_list
+    assert_renders <<SASS, <<SCSS
+ function foo($a: b, $c: d)
+  @return $a, $c
+
+.foo
+  a: foo($list..., $map...)
+SASS
+ function foo($a: b, $c: d) {
+  @return $a, $c;
+}
+
+.foo {
+  a: foo($list..., $map...);
+}
+SCSS
+  end
+
+  def test_keyframes
+    assert_renders(<<SASS, <<SCSS)
+ keyframes identifier
+  0%
+    top: 0
+    left: 0
+  30%
+    top: 50px
+  68%, 72%
+    left: 50px
+  100%
+    top: 100px
+    left: 100%
+SASS
+ keyframes identifier {
+  0% {
+    top: 0;
+    left: 0;
+  }
+  30% {
+    top: 50px;
+  }
+  68%, 72% {
+    left: 50px;
+  }
+  100% {
+    top: 100px;
+    left: 100%;
+  }
+}
+SCSS
+  end
+
+  ## Regression Tests
+
+  def test_list_in_args
+    assert_renders(<<SASS, <<SCSS)
++mixin((a, b, c))
+
++mixin($arg: (a, b, c))
+
++mixin(a, b, (c, d, e)...)
+SASS
+ include mixin((a, b, c));
+
+ include mixin($arg: (a, b, c));
+
+ include mixin(a, b, (c, d, e)...);
+SCSS
+  end
+
+  def test_media_query_with_expr
+    assert_renders <<SASS, <<SCSS
+ media foo and (bar: baz)
+  a: b
+SASS
+ media foo and (bar: baz) {
+  a: b;
+}
+SCSS
+  end
+
+  def test_nested_if_statements
+    assert_renders(<<SASS, <<SCSS)
+ if $foo
+  one
+    a: b
+ else
+  @if $bar
+    two
+      a: b
+  @else
+    three
+      a: b
+SASS
+ if $foo {
+  one {
+    a: b;
+  }
+}
+ else {
+  @if $bar {
+    two {
+      a: b;
+    }
+  }
+  @else {
+    three {
+      a: b;
+    }
+  }
+}
+SCSS
+  end
+
+  def test_comment_indentation
+    assert_renders(<<SASS, <<SCSS, :indent => '    ')
+foo
+    // bar
+    /* baz
+    a: b
+SASS
+foo {
+    // bar
+    /* baz */
+    a: b;
+}
+SCSS
+  end
+
+  def test_keyword_arguments
+    assert_renders(<<SASS, <<SCSS, :dasherize => true)
+$foo: foo($dash-ed: 2px)
+SASS
+$foo: foo($dash-ed: 2px);
+SCSS
+    assert_scss_to_sass(<<SASS, <<SCSS, :dasherize => true)
+$foo: foo($dash-ed: 2px)
+SASS
+$foo: foo($dash_ed: 2px);
+SCSS
+    assert_sass_to_scss(<<SCSS, <<SASS, :dasherize => true)
+$foo: foo($dash-ed: 2px);
+SCSS
+$foo: foo($dash_ed: 2px)
+SASS
+    assert_renders(<<SASS, <<SCSS)
+$foo: foo($under_scored: 1px)
+SASS
+$foo: foo($under_scored: 1px);
+SCSS
+    assert_renders(<<SASS, <<SCSS)
+$foo: foo($dash-ed: 2px, $under_scored: 1px)
+SASS
+$foo: foo($dash-ed: 2px, $under_scored: 1px);
+SCSS
+  end
+
+  def test_ambiguous_negation
+    assert_renders(<<SASS, <<SCSS, :indent => '    ')
+foo
+    ok: -$foo
+    comma: 10px, -$foo
+    needs-parens: 10px (-$foo)
+    no-parens: a 50px + 60px b
+SASS
+foo {
+    ok: -$foo;
+    comma: 10px, -$foo;
+    needs-parens: 10px (-$foo);
+    no-parens: a 50px + 60px b;
+}
+SCSS
+  end
+
+  def test_variable_with_global
+    assert_renders(<<SASS, <<SCSS)
+$var: 1
+
+foo
+  $var: 2 !global
+  $var: 3 !global !default
+SASS
+$var: 1;
+
+foo {
+  $var: 2 !global;
+  $var: 3 !global !default;
+}
+SCSS
+  end
+
+  private
+
+  def assert_sass_to_sass(sass, options = {})
+    assert_equal(sass.rstrip, to_sass(sass, options).rstrip,
+      "Expected Sass to transform to itself")
+  end
+
+  def assert_scss_to_sass(sass, scss, options = {})
+    assert_equal(sass.rstrip, to_sass(scss, options.merge(:syntax => :scss)).rstrip,
+      "Expected SCSS to transform to Sass")
+  end
+
+  def assert_scss_to_scss(scss, in_scss = nil, options = nil)
+    if in_scss.is_a?(Hash)
+      options = in_scss
+      in_scss = nil
+    end
+
+    in_scss ||= scss
+    options ||= {}
+
+    assert_equal(scss.rstrip, to_scss(in_scss, options.merge(:syntax => :scss)).rstrip,
+      "Expected SCSS to transform to #{scss == in_scss ? 'itself' : 'SCSS'}")
+  end
+
+  def assert_sass_to_scss(scss, sass, options = {})
+    assert_equal(scss.rstrip, to_scss(sass, options).rstrip,
+      "Expected Sass to transform to SCSS")
+  end
+
+  def assert_renders(sass, scss, options = {})
+    assert_sass_to_sass(sass, options)
+    assert_scss_to_sass(sass, scss, options)
+    assert_scss_to_scss(scss, options)
+    assert_sass_to_scss(scss, sass, options)
+  end
+
+  def to_sass(scss, options = {})
+    Sass::Util.silence_sass_warnings do
+      Sass::Engine.new(scss, options).to_tree.to_sass(options)
+    end
+  end
+
+  def to_scss(sass, options = {})
+    Sass::Util.silence_sass_warnings do
+      Sass::Engine.new(sass, options).to_tree.to_scss(options)
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/test/sass/css2sass_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/css2sass_test.rb
new file mode 100755
index 0000000..b8cd1f6
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/css2sass_test.rb
@@ -0,0 +1,477 @@
+#!/usr/bin/env ruby
+require 'minitest/autorun'
+require File.dirname(__FILE__) + '/../test_helper'
+require 'sass/css'
+
+class CSS2SassTest < MiniTest::Test
+  def test_basic
+    css = <<CSS
+h1 {
+  color: red;
+}
+CSS
+    assert_equal(<<SASS, css2sass(css))
+h1
+  color: red
+SASS
+    assert_equal(<<SASS, css2sass(css, :old => true))
+h1
+  :color red
+SASS
+  end
+
+  def test_nesting
+    assert_equal(<<SASS, css2sass(<<CSS))
+li
+  display: none
+  a
+    text-decoration: none
+    span
+      color: yellow
+    &:hover
+      text-decoration: underline
+SASS
+li {
+  display: none;
+}
+
+li a {
+  text-decoration: none;
+}
+
+li a span {
+  color: yellow;
+}
+
+li a:hover {
+  text-decoration: underline;
+}
+CSS
+  end
+
+  def test_no_nesting_around_rules
+    assert_equal(<<SASS, css2sass(<<CSS))
+div .warning
+  color: #d21a19
+
+span .debug
+  cursor: crosshair
+
+div .debug
+  cursor: default
+SASS
+div .warning {
+  color: #d21a19; }
+span .debug {
+  cursor: crosshair;}
+div .debug {
+  cursor: default; }
+CSS
+  end
+
+  def test_comments_multiline
+    css = <<CSS
+/* comment */
+elephant.rawr {
+  rampages: excessively;
+}
+
+/* actual multiline
+  comment */
+span.turkey {
+  isdinner: true;
+}
+
+.turducken {
+  /* Sounds funny
+     doesn't it */
+  chimera: not_really;
+}
+
+#overhere {
+  bored: sorta; /* it's for a good
+  cause */
+  better_than: thread_pools;
+}
+
+#one_more {
+  finally: srsly;
+} /* just a line here */
+CSS
+    sass = <<SASS
+/* comment
+
+elephant.rawr
+  rampages: excessively
+
+/* actual multiline
+ *comment
+
+span.turkey
+  isdinner: true
+
+.turducken
+  /* Sounds funny
+   * doesn't it
+  chimera: not_really
+
+#overhere
+  bored: sorta
+  /*                  it's for a good
+   * cause
+  better_than: thread_pools
+
+#one_more
+  finally: srsly
+
+/* just a line here
+SASS
+    assert_equal(sass, css2sass(css))
+  end
+
+  def test_fold_commas
+    assert_equal(<<SASS, css2sass(<<CSS))
+li
+  .one, .two
+    color: red
+SASS
+li .one {
+  color: red;
+}
+li .two {
+  color: red;
+}
+CSS
+
+    assert_equal(<<SASS, css2sass(<<CSS))
+.one
+  color: green
+
+.two
+  color: green
+  color: red
+
+.three
+  color: red
+SASS
+.one, .two {
+  color: green;
+}
+
+.two, .three {
+  color: red;
+}
+CSS
+  end
+
+  def test_bad_formatting
+    assert_equal(<<SASS, css2sass(<<CSS))
+hello
+  parent: true
+  there
+    parent: false
+  who
+    hoo: false
+  why
+    y: true
+  when
+    wen: nao
+
+down_here
+  yeah: true
+SASS
+hello {
+  parent: true;
+}
+
+hello  there {
+  parent: false;
+}
+hello who  {
+  hoo: false;
+}
+hello why {
+   y: true;
+}
+hello when {
+  wen:  nao;
+}
+
+
+
+down_here { yeah: true; }
+CSS
+  end
+
+  def test_comments_in_selectors
+    assert_equal(<<SASS, css2sass(<<CSS))
+.js
+  #location-navigation-form .form-submit, #business-listing-form .form-submit, #detailTabs ul, 
#detailsEnhanced #addTags, #locationSearchList, #moreHoods
+    display: none
+
+#navListLeft
+  display: none
+SASS
+.js #location-navigation-form .form-submit,
+.js #business-listing-form .form-submit,
+.js #detailTabs ul,
+/* .js #addReview, */
+/* .js #addTags, */
+.js #detailsEnhanced #addTags,
+.js #locationSearchList,
+.js #moreHoods,
+#navListLeft
+  { display: none; }
+CSS
+  end
+
+  def test_pseudo_classes_are_escaped
+    assert_equal(<<SASS, css2sass(<<CSS))
+\\:focus
+  a: b
+  \\:foo
+    bar: baz
+SASS
+:focus {a: b;}
+:focus :foo {bar: baz;}
+CSS
+  end
+
+  def test_subject
+    silence_warnings {assert_equal(<<SASS, css2sass(<<CSS))}
+.foo
+  .bar!
+    .baz
+      a: b
+    .bip
+      c: d
+  .bar .bonk
+    e: f
+
+.flip!
+  &.bar
+    a: b
+  &.baz
+    c: d
+SASS
+.foo .bar! .baz {a: b;}
+.foo .bar! .bip {c: d;}
+.foo .bar .bonk {e: f;}
+
+.flip.bar! {a: b;}
+.flip.baz! {c: d;}
+CSS
+  end
+
+  # Regressions
+
+  def test_nesting_with_matching_property
+    assert_equal(<<SASS, css2sass(<<CSS))
+ul
+  width: 10px
+  div
+    width: 20px
+
+article
+  width: 10px
+  p
+    width: 20px
+SASS
+ul {width: 10px}
+ul div {width: 20px}
+article {width: 10px}
+article p {width: 20px}
+CSS
+  end
+
+  def test_empty_rule
+    assert_equal(<<SASS, css2sass(<<CSS))
+a
+SASS
+a {}
+CSS
+  end
+
+  def test_empty_rule_with_selector_combinator
+    assert_equal(<<SASS, css2sass(<<CSS))
+a
+  color: red
+  > b
+SASS
+a {color: red}
+a > b {}
+CSS
+  end
+
+  def test_nesting_within_media
+    assert_equal(<<SASS, css2sass(<<CSS))
+ media all
+  .next .vevent
+    padding-left: 0
+    padding-right: 0
+SASS
+ media all {
+  .next .vevent {
+    padding-left: 0;
+    padding-right: 0; } }
+CSS
+  end
+
+  def test_multiline_selector_within_media_and_with_child_selector
+    assert_equal(<<SASS, css2sass(<<CSS))
+ media all
+  foo bar, baz
+    padding-left: 0
+    padding-right: 0
+SASS
+ media all {
+  foo bar,
+  baz {
+    padding-left: 0;
+    padding-right: 0; } }
+CSS
+  end
+
+  def test_double_comma
+    assert_equal(<<SASS, css2sass(<<CSS))
+foo, bar
+  a: b
+SASS
+foo, , bar { a: b }
+CSS
+  end
+
+  def test_selector_splitting
+    assert_equal(<<SASS, css2sass(<<CSS))
+.foo >
+  .bar
+    a: b
+  .baz
+    c: d
+SASS
+.foo>.bar {a: b}
+.foo>.baz {c: d}
+CSS
+
+    assert_equal(<<SASS, css2sass(<<CSS))
+.foo
+  &::bar
+    a: b
+  &::baz
+    c: d
+SASS
+.foo::bar {a: b}
+.foo::baz {c: d}
+CSS
+  end
+
+  def test_triple_nesting
+    assert_equal(<<SASS, css2sass(<<CSS))
+.foo .bar .baz
+  a: b
+SASS
+.foo .bar .baz {a: b}
+CSS
+
+    assert_equal(<<SASS, css2sass(<<CSS))
+.bar > .baz
+  c: d
+SASS
+.bar > .baz {c: d}
+CSS
+  end
+
+  # Error reporting
+
+  def test_error_reporting
+    css2sass("foo")
+    assert(false, "Expected exception")
+  rescue Sass::SyntaxError => err
+    assert_equal(1, err.sass_line)
+    assert_equal('Invalid CSS after "foo": expected "{", was ""', err.message)
+  end
+
+  def test_error_reporting_in_line
+    css2sass("foo\nbar }\nbaz")
+    assert(false, "Expected exception")
+  rescue Sass::SyntaxError => err
+    assert_equal(2, err.sass_line)
+    assert_equal('Invalid CSS after "bar ": expected "{", was "}"', err.message)
+  end
+
+  def test_error_truncate_after
+    css2sass("#{"a" * 16}foo")
+    assert(false, "Expected exception")
+  rescue Sass::SyntaxError => err
+    assert_equal(1, err.sass_line)
+    assert_equal('Invalid CSS after "...aaaaaaaaaaaafoo": expected "{", was ""', err.message)
+  end
+
+  def test_error_truncate_was
+    css2sass("foo }foo#{"a" * 15}")
+    assert(false, "Expected exception")
+  rescue Sass::SyntaxError => err
+    assert_equal(1, err.sass_line)
+    assert_equal('Invalid CSS after "foo ": expected "{", was "}fooaaaaaaaaaaa..."', err.message)
+  end
+
+  def test_error_doesnt_truncate_after_when_elipsis_would_add_length
+    css2sass("#{"a" * 15}foo")
+    assert(false, "Expected exception")
+  rescue Sass::SyntaxError => err
+    assert_equal(1, err.sass_line)
+    assert_equal('Invalid CSS after "aaaaaaaaaaaaaaafoo": expected "{", was ""', err.message)
+  end
+
+  def test_error_doesnt_truncate_was_when_elipsis_would_add_length
+    css2sass("foo }foo#{"a" * 14}")
+    assert(false, "Expected exception")
+  rescue Sass::SyntaxError => err
+    assert_equal(1, err.sass_line)
+    assert_equal('Invalid CSS after "foo ": expected "{", was "}fooaaaaaaaaaaaaaa"', err.message)
+  end
+
+  def test_error_gets_rid_of_trailing_newline_for_after
+    css2sass("foo  \n  ")
+    assert(false, "Expected exception")
+  rescue Sass::SyntaxError => err
+    assert_equal(2, err.sass_line)
+    assert_equal('Invalid CSS after "foo": expected "{", was ""', err.message)
+  end
+
+  def test_error_gets_rid_of_trailing_newline_for_was
+    css2sass("foo \n  }foo")
+    assert(false, "Expected exception")
+  rescue Sass::SyntaxError => err
+    assert_equal(2, err.sass_line)
+    assert_equal('Invalid CSS after "foo": expected "{", was "}foo"', err.message)
+  end
+
+  # Encodings
+
+  unless Sass::Util.ruby1_8?
+    def test_encoding_error
+      css2sass("foo\nbar\nb\xFEaz".force_encoding("utf-8"))
+      assert(false, "Expected exception")
+    rescue Sass::SyntaxError => e
+      assert_equal(3, e.sass_line)
+      assert_equal('Invalid UTF-8 character "\xFE"', e.message)
+    end
+
+    def test_ascii_incompatible_encoding_error
+      template = "foo\nbar\nb_z".encode("utf-16le")
+      template[9] = "\xFE".force_encoding("utf-16le")
+      css2sass(template)
+      assert(false, "Expected exception")
+    rescue Sass::SyntaxError => e
+      assert_equal(3, e.sass_line)
+      assert_equal('Invalid UTF-16LE character "\xFE"', e.message)
+    end
+  end
+
+  private
+
+  def css2sass(string, opts={})
+    Sass::CSS.new(string, opts).render
+  end
+end
diff --git a/backends/css/gems/sass-3.2.12/test/sass/data/hsl-rgb.txt 
b/backends/css/gems/sass-3.4.9/test/sass/data/hsl-rgb.txt
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/data/hsl-rgb.txt
rename to backends/css/gems/sass-3.4.9/test/sass/data/hsl-rgb.txt
diff --git a/backends/css/gems/sass-3.4.9/test/sass/encoding_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/encoding_test.rb
new file mode 100755
index 0000000..f2f1b93
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/encoding_test.rb
@@ -0,0 +1,219 @@
+#!/usr/bin/env ruby
+# -*- coding: utf-8 -*-
+require File.dirname(__FILE__) + '/../test_helper'
+require File.dirname(__FILE__) + '/test_helper'
+require 'sass/util/test'
+
+class EncodingTest < MiniTest::Test
+  include Sass::Util::Test
+
+  def test_encoding_error
+    return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
+
+    render("foo\nbar\nb\xFEaz".force_encoding("utf-8"))
+    assert(false, "Expected exception")
+  rescue Sass::SyntaxError => e
+    assert_equal(3, e.sass_line)
+    assert_equal('Invalid UTF-8 character "\xFE"', e.message)
+  end
+
+  def test_ascii_incompatible_encoding_error
+    return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
+
+    template = "foo\nbar\nb_z".encode("utf-16le")
+    template[9] = "\xFE".force_encoding("utf-16le")
+    render(template)
+    assert(false, "Expected exception")
+  rescue Sass::SyntaxError => e
+    assert_equal(3, e.sass_line)
+    assert_equal('Invalid UTF-16LE character "\xFE"', e.message)
+  end
+
+  def test_prefers_charset_to_ruby_encoding
+    return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
+
+    assert_renders_encoded(<<CSS, <<SASS.encode("IBM866").force_encoding("UTF-8"))
+ charset "UTF-8";
+fЖЖ {
+  a: b; }
+CSS
+ charset "ibm866"
+fЖЖ
+  a: b
+SASS
+  end
+
+  def test_uses_ruby_encoding_without_charset
+    return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
+
+    assert_renders_encoded(<<CSS, <<SASS.encode("IBM866"))
+ charset "UTF-8";
+тАЬ {
+  a: b; }
+CSS
+тАЬ
+  a: b
+SASS
+  end
+
+  def test_multibyte_charset_without_bom_declared_as_binary
+    return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
+
+    engine = Sass::Engine.new(<<SASS.encode("UTF-16LE").force_encoding("BINARY"))
+ charset "utf-16le"
+fóó
+  a: b
+SASS
+    # Since multibyte encodings' @charset declarations aren't
+    # ASCII-compatible, we have to interpret the files as UTF-8 which will
+    # inevitably fail.
+    assert_raise_message(Sass::SyntaxError, "Invalid UTF-8 character \"\\xF3\"") {engine.render}
+  end
+
+  def test_multibyte_charset_without_bom_declared_as_utf_8
+    return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
+
+    engine = Sass::Engine.new(<<SASS.encode("UTF-16LE").force_encoding("UTF-8"))
+ charset "utf-16le"
+fóó
+  a: b
+SASS
+    # Since multibyte encodings' @charset declarations aren't
+    # ASCII-compatible, we have to interpret the files as UTF-8 which will
+    # inevitably fail.
+    assert_raise_message(Sass::SyntaxError, "Invalid UTF-8 character \"\\xF3\"") {engine.render}
+  end
+
+  def test_utf_16le_with_bom
+    return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
+
+    assert_renders_encoded(<<CSS, <<SASS.encode("UTF-16LE").force_encoding("BINARY"))
+ charset "UTF-8";
+fóó {
+  a: b; }
+CSS
+\uFEFFfóó
+  a: b
+SASS
+  end
+
+  def test_utf_16be_with_bom
+    return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
+
+    assert_renders_encoded(<<CSS, <<SASS.encode("UTF-16BE").force_encoding("BINARY"))
+ charset "UTF-8";
+fóó {
+  a: b; }
+CSS
+\uFEFFfóó
+  a: b
+SASS
+  end
+
+  def test_utf_8_with_bom
+    return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
+
+    assert_renders_encoded(<<CSS, <<SASS.force_encoding("BINARY"))
+ charset "UTF-8";
+fóó {
+  a: b; }
+CSS
+\uFEFFfóó
+  a: b
+SASS
+  end
+
+  def test_charset_with_multibyte_encoding
+    return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
+
+    engine = Sass::Engine.new(<<SASS)
+ charset "utf-32be"
+fóó
+  a: b
+SASS
+    # The charset declaration is just false here, so we should get an
+    # encoding error.
+    assert_raise_message(Sass::SyntaxError, "Invalid UTF-32BE character \"\\xC3\"") {engine.render}
+  end
+
+  def test_charset_with_special_case_encoding
+    return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
+
+    # For some reason, a file with an ASCII-compatible UTF-16 charset
+    # declaration is specced to be parsed as UTF-8.
+    assert_renders_encoded(<<CSS, <<SASS.force_encoding("BINARY"))
+ charset "UTF-8";
+fóó {
+  a: b; }
+CSS
+ charset "utf-16"
+fóó
+  a: b
+SASS
+  end
+
+  def test_compressed_output_uses_bom
+    return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
+
+    assert_equal("\uFEFFfóó{a:b}\n", render(<<SASS, :style => :compressed))
+fóó
+  a: b
+SASS
+  end
+
+  def test_newline_normalization
+    assert_equal("/* foo\nbar\nbaz\nbang\nqux */\n",
+      render("/* foo\nbar\r\nbaz\fbang\rqux */", :syntax => :scss))
+  end
+
+  def test_null_normalization
+    return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
+    
+    assert_equal(<<CSS, render("/* foo\x00bar\x00baz */", :syntax => :scss))
+#{"@charset \"UTF-8\";\n" unless Sass::Util.ruby1_8?
+}/* foo�bar�baz */
+CSS
+  end
+
+  # Regression
+
+  def test_multibyte_prop_name
+    return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
+
+    assert_equal(<<CSS, render(<<SASS))
+ charset "UTF-8";
+#bar {
+  cölor: blue; }
+CSS
+#bar
+  cölor: blue
+SASS
+  end
+
+  def test_multibyte_and_interpolation
+    return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
+
+    assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))
+#bar {
+  background: a 0%; }
+CSS
+#bar {
+  // 
+  background: \#{a} 0%;
+}
+SCSS
+  end
+
+  private
+
+  def assert_renders_encoded(css, sass)
+    result = render(sass)
+    assert_equal css.encoding, result.encoding
+    assert_equal css, result
+  end
+
+  def render(sass, options = {})
+    munge_filename options
+    Sass::Engine.new(sass, options).render
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/test/sass/engine_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/engine_test.rb
new file mode 100755
index 0000000..f39ed0a
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/engine_test.rb
@@ -0,0 +1,3301 @@
+#!/usr/bin/env ruby
+# -*- coding: utf-8 -*-
+require File.dirname(__FILE__) + '/../test_helper'
+require File.dirname(__FILE__) + '/test_helper'
+require 'sass/engine'
+require 'stringio'
+require 'mock_importer'
+require 'pathname'
+
+module Sass::Script::Functions::UserFunctions
+  def option(name)
+    Sass::Script::Value::String.new(@options[name.value.to_sym].to_s)
+  end
+
+  def set_a_variable(name, value)
+    environment.set_var(name.value, value)
+    return Sass::Script::Value::Null.new
+  end
+
+  def set_a_global_variable(name, value)
+    environment.set_global_var(name.value, value)
+    return Sass::Script::Value::Null.new
+  end
+
+  def get_a_variable(name)
+    environment.var(name.value) || Sass::Script::Value::String.new("undefined")
+  end
+end
+
+module Sass::Script::Functions
+  include Sass::Script::Functions::UserFunctions
+end
+
+class SassEngineTest < MiniTest::Test
+  FAKE_FILE_NAME = __FILE__.gsub(/rb$/,"sass")
+  # A map of erroneous Sass documents to the error messages they should produce.
+  # The error messages may be arrays;
+  # if so, the second element should be the line number that should be reported for the error.
+  # If this isn't provided, the tests will assume the line number should be the last line of the document.
+  EXCEPTION_MAP = {
+    "$a: 1 + " => 'Invalid CSS after "1 +": expected expression (e.g. 1px, bold), was ""',
+    "$a: 1 + 2 +" => 'Invalid CSS after "1 + 2 +": expected expression (e.g. 1px, bold), was ""',
+    "$a: 1 + 2 + %" => 'Invalid CSS after "1 + 2 + ": expected expression (e.g. 1px, bold), was "%"',
+    "$a: foo(\"bar\"" => 'Invalid CSS after "foo("bar"": expected ")", was ""',
+    "$a: 1 }" => 'Invalid CSS after "1 ": expected expression (e.g. 1px, bold), was "}"',
+    "$a: 1 }foo\"" => 'Invalid CSS after "1 ": expected expression (e.g. 1px, bold), was "}foo""',
+    ":" => 'Invalid property: ":".',
+    ": a" => 'Invalid property: ": a".',
+    "a\n  :b" => <<MSG,
+Invalid property: ":b" (no value).
+If ":b" should be a selector, use "\\:b" instead.
+MSG
+    "a\n  b:" => 'Invalid property: "b:" (no value).',
+    "a\n  :b: c" => 'Invalid property: ":b: c".',
+    "a\n  :b:c d" => 'Invalid property: ":b:c d".',
+    "a\n  :b c;" => 'Invalid CSS after "c": expected expression (e.g. 1px, bold), was ";"',
+    "a\n  b: c;" => 'Invalid CSS after "c": expected expression (e.g. 1px, bold), was ";"',
+    ".foo ^bar\n  a: b" => ['Invalid CSS after ".foo ": expected selector, was "^bar"', 1],
+    "a\n  @extend .foo ^bar" => 'Invalid CSS after ".foo ": expected selector, was "^bar"',
+    "a\n  @extend .foo .bar" => "Can't extend .foo .bar: can't extend nested selectors",
+    "a\n  @extend >" => "Can't extend >: invalid selector",
+    "a\n  @extend &.foo" => "Can't extend &.foo: can't extend parent selectors",
+    "a: b" => 'Properties are only allowed within rules, directives, mixin includes, or other properties.',
+    ":a b" => 'Properties are only allowed within rules, directives, mixin includes, or other properties.',
+    "$" => 'Invalid variable: "$".',
+    "$a" => 'Invalid variable: "$a".',
+    "$ a" => 'Invalid variable: "$ a".',
+    "$a b" => 'Invalid variable: "$a b".',
+    "$a: 1b + 2c" => "Incompatible units: 'c' and 'b'.",
+    "$a: 1b < 2c" => "Incompatible units: 'c' and 'b'.",
+    "$a: 1b > 2c" => "Incompatible units: 'c' and 'b'.",
+    "$a: 1b <= 2c" => "Incompatible units: 'c' and 'b'.",
+    "$a: 1b >= 2c" => "Incompatible units: 'c' and 'b'.",
+    "a\n  b: 1b * 2c" => "2b*c isn't a valid CSS value.",
+    "a\n  b: 1b % 2c" => "Incompatible units: 'c' and 'b'.",
+    "$a: 2px + #ccc" => "Cannot add a number with units (2px) to a color (#ccc).",
+    "$a: #ccc + 2px" => "Cannot add a number with units (2px) to a color (#ccc).",
+    "& a\n  :b c" => ["Base-level rules cannot contain the parent-selector-referencing character '&'.", 1],
+    "a\n  :b\n    c" => "Illegal nesting: Only properties may be nested beneath properties.",
+    "$a: b\n  :c d\n" => "Illegal nesting: Nothing may be nested beneath variable declarations.",
+    "$a: b\n  :c d\n" => "Illegal nesting: Nothing may be nested beneath variable declarations.",
+    "@import templates/basic\n  foo" => "Illegal nesting: Nothing may be nested beneath import directives.",
+    "foo\n  @import foo.css" => "CSS import directives may only be used at the root of a document.",
+    "@if true\n  @import foo" => "Import directives may not be used within control directives or mixins.",
+    "@if true\n  .foo\n    @import foo" => "Import directives may not be used within control directives or 
mixins.",
+    "@mixin foo\n  @import foo" => "Import directives may not be used within control directives or mixins.",
+    "@mixin foo\n  .foo\n    @import foo" => "Import directives may not be used within control directives or 
mixins.",
+    "@import foo;" => "Invalid @import: expected end of line, was \";\".",
+    '$foo: "bar" "baz" !' => %Q{Invalid CSS after ""bar" "baz" ": expected expression (e.g. 1px, bold), was 
"!"},
+    '$foo: "bar" "baz" $' => %Q{Invalid CSS after ""bar" "baz" ": expected expression (e.g. 1px, bold), was 
"$"}, #'
+    "=foo\n  :color red\n.bar\n  +bang" => "Undefined mixin 'bang'.",
+    "=foo\n  :color red\n.bar\n  +bang_bop" => "Undefined mixin 'bang_bop'.",
+    "=foo\n  :color red\n.bar\n  +bang-bop" => "Undefined mixin 'bang-bop'.",
+    ".foo\n  =foo\n    :color red\n.bar\n  +foo" => "Undefined mixin 'foo'.",
+    "    a\n  b: c" => ["Indenting at the beginning of the document is illegal.", 1],
+    " \n   \n\t\n  a\n  b: c" => ["Indenting at the beginning of the document is illegal.", 4],
+    "a\n  b: c\n b: c" => ["Inconsistent indentation: 1 space was used for indentation, but the rest of the 
document was indented using 2 spaces.", 3],
+    "a\n  b: c\na\n b: c" => ["Inconsistent indentation: 1 space was used for indentation, but the rest of 
the document was indented using 2 spaces.", 4],
+    "a\n\t\tb: c\n\tb: c" => ["Inconsistent indentation: 1 tab was used for indentation, but the rest of the 
document was indented using 2 tabs.", 3],
+    "a\n  b: c\n   b: c" => ["Inconsistent indentation: 3 spaces were used for indentation, but the rest of 
the document was indented using 2 spaces.", 3],
+    "a\n  b: c\n  a\n   d: e" => ["Inconsistent indentation: 3 spaces were used for indentation, but the 
rest of the document was indented using 2 spaces.", 4],
+    "a\n  b: c\na\n    d: e" => ["The line was indented 2 levels deeper than the previous line.", 4],
+    "a\n  b: c\n  a\n        d: e" => ["The line was indented 3 levels deeper than the previous line.", 4],
+    "a\n \tb: c" => ["Indentation can't use both tabs and spaces.", 2],
+    "=a(" => 'Invalid CSS after "(": expected variable (e.g. $foo), was ""',
+    "=a(b)" => 'Invalid CSS after "(": expected variable (e.g. $foo), was "b)"',
+    "=a(,)" => 'Invalid CSS after "(": expected variable (e.g. $foo), was ",)"',
+    "=a($)" => 'Invalid CSS after "(": expected variable (e.g. $foo), was "$)"',
+    "=a($foo bar)" => 'Invalid CSS after "($foo ": expected ")", was "bar)"',
+    "=foo\n  bar: baz\n+foo" => ["Properties are only allowed within rules, directives, mixin includes, or 
other properties.", 2],
+    "a-\#{$b\n  c: d" => ['Invalid CSS after "a-#{$b": expected "}", was ""', 1],
+    "=a($b: 1, $c)" => "Required argument $c must come before any optional arguments.",
+    "=a($b: 1)\n  a: $b\ndiv\n  +a(1,2)" => "Mixin a takes 1 argument but 2 were passed.",
+    "=a($b: 1)\n  a: $b\ndiv\n  +a(1,$c: 3)" => "Mixin a doesn't have an argument named $c.",
+    "=a($b)\n  a: $b\ndiv\n  +a" => "Mixin a is missing argument $b.",
+    "@function foo()\n  1 + 2" => "Functions can only contain variable declarations and control directives.",
+    "@function foo()\n  foo: bar" => "Functions can only contain variable declarations and control 
directives.",
+    "@function foo()\n  foo: bar\n  @return 3" => ["Functions can only contain variable declarations and 
control directives.", 2],
+    "@function foo\n  @return 1" => ['Invalid CSS after "": expected "(", was ""', 1],
+    "@function foo(\n  @return 1" => ['Invalid CSS after "(": expected variable (e.g. $foo), was ""', 1],
+    "@function foo(b)\n  @return 1" => ['Invalid CSS after "(": expected variable (e.g. $foo), was "b)"', 1],
+    "@function foo(,)\n  @return 1" => ['Invalid CSS after "(": expected variable (e.g. $foo), was ",)"', 1],
+    "@function foo($)\n  @return 1" => ['Invalid CSS after "(": expected variable (e.g. $foo), was "$)"', 1],
+    "@function foo()\n  @return" => 'Invalid @return: expected expression.',
+    "@function foo()\n  @return 1\n    $var: val" => 'Illegal nesting: Nothing may be nested beneath return 
directives.',
+    "@function foo($a)\n  @return 1\na\n  b: foo()" => 'Function foo is missing argument $a.',
+    "@function foo()\n  @return 1\na\n  b: foo(2)" => 'Function foo takes 0 arguments but 1 was passed.',
+    "@function foo()\n  @return 1\na\n  b: foo($a: 1)" => "Function foo doesn't have an argument named $a.",
+    "@function foo()\n  @return 1\na\n  b: foo($a: 1, $b: 2)" => "Function foo doesn't have the following 
arguments: $a, $b.",
+    "@return 1" => '@return may only be used within a function.',
+    "@if true\n  @return 1" => '@return may only be used within a function.',
+    "@mixin foo\n  @return 1\n include foo" => ['@return may only be used within a function.', 2],
+    "@else\n  a\n    b: c" => ["@else must come after @if.", 1],
+    "@if false\n else foo" => "Invalid else directive '@else foo': expected 'if <expr>'.",
+    "@if false\n else if " => "Invalid else directive '@else if': expected 'if <expr>'.",
+    "a\n  $b: 12\nc\n  d: $b" => 'Undefined variable: "$b".',
+    "=foo\n  $b: 12\nc\n  +foo\n  d: $b" => 'Undefined variable: "$b".',
+    "c\n  d: $b-foo" => 'Undefined variable: "$b-foo".',
+    "c\n  d: $b_foo" => 'Undefined variable: "$b_foo".',
+    '@for $a from "foo" to 1' => '"foo" is not an integer.',
+    '@for $a from 1 to "2"' => '"2" is not an integer.',
+    '@for $a from 1 to "foo"' => '"foo" is not an integer.',
+    '@for $a from 1 to 1.232323' => '1.23232 is not an integer.',
+    '@for $a from 1px to 3em' => "Incompatible units: 'em' and 'px'.",
+    '@if' => "Invalid if directive '@if': expected expression.",
+    '@while' => "Invalid while directive '@while': expected expression.",
+    '@debug' => "Invalid debug directive '@debug': expected expression.",
+    %Q{ debug "a message"\n  "nested message"} => "Illegal nesting: Nothing may be nested beneath debug 
directives.",
+    '@error' => "Invalid error directive '@error': expected expression.",
+    %Q{ error "a message"\n  "nested message"} => "Illegal nesting: Nothing may be nested beneath error 
directives.",
+    '@warn' => "Invalid warn directive '@warn': expected expression.",
+    %Q{ warn "a message"\n  "nested message"} => "Illegal nesting: Nothing may be nested beneath warn 
directives.",
+    "/* foo\n    bar\n  baz" => "Inconsistent indentation: previous line was indented by 4 spaces, but this 
line was indented by 2 spaces.",
+    '+foo(1 + 1: 2)' => 'Invalid CSS after "(1 + 1": expected comma, was ": 2)"',
+    '+foo($var: )' => 'Invalid CSS after "($var: ": expected mixin argument, was ")"',
+    '+foo($var: a, $var: b)' => 'Keyword argument "$var" passed more than once',
+    '+foo($var-var: a, $var_var: b)' => 'Keyword argument "$var_var" passed more than once',
+    '+foo($var_var: a, $var-var: b)' => 'Keyword argument "$var-var" passed more than once',
+    "a\n  b: foo(1 + 1: 2)" => 'Invalid CSS after "foo(1 + 1": expected comma, was ": 2)"',
+    "a\n  b: foo($var: )" => 'Invalid CSS after "foo($var: ": expected function argument, was ")"',
+    "a\n  b: foo($var: a, $var: b)" => 'Keyword argument "$var" passed more than once',
+    "a\n  b: foo($var-var: a, $var_var: b)" => 'Keyword argument "$var_var" passed more than once',
+    "a\n  b: foo($var_var: a, $var-var: b)" => 'Keyword argument "$var-var" passed more than once',
+    "@if foo\n  @extend .bar" => ["Extend directives may only be used within rules.", 2],
+    "$var: true\n while $var\n  @extend .bar\n  $var: false" => ["Extend directives may only be used within 
rules.", 3],
+    "@for $i from 0 to 1\n  @extend .bar" => ["Extend directives may only be used within rules.", 2],
+    "@mixin foo\n  @extend  bar\n include foo" => ["Extend directives may only be used within rules.", 2],
+    "foo %\n  a: b" => ['Invalid CSS after "foo %": expected placeholder name, was ""', 1],
+    "=foo\n  @content error" => "Invalid content directive. Trailing characters found: \"error\".",
+    "=foo\n  @content\n    b: c" => "Illegal nesting: Nothing may be nested beneath @content directives.",
+    "@content" => '@content may only be used within a mixin.',
+    "=simple\n  .simple\n    color: red\n+simple\n  color: blue" => ['Mixin "simple" does not accept a 
content block.', 4],
+    "@import \"foo\" // bar" => "Invalid CSS after \"\"foo\" \": expected media query list, was \"// bar\"",
+    "@at-root\n  a: b" => "Properties are only allowed within rules, directives, mixin includes, or other 
properties.",
+
+    # Regression tests
+    "a\n  b:\n    c\n    d" => ["Illegal nesting: Only properties may be nested beneath properties.", 3],
+    "& foo\n  bar: baz\n  blat: bang" => ["Base-level rules cannot contain the parent-selector-referencing 
character '&'.", 1],
+    "a\n  b: c\n& foo\n  bar: baz\n  blat: bang" => ["Base-level rules cannot contain the 
parent-selector-referencing character '&'.", 3],
+    "@" => "Invalid directive: '@'.",
+  }
+
+  def teardown
+    clean_up_sassc
+  end
+
+  def test_basic_render
+    renders_correctly "basic", { :style => :compact }
+  end
+
+  def test_empty_render
+    assert_equal "", render("")
+  end
+
+  def test_multiple_calls_to_render
+    sass = Sass::Engine.new("a\n  b: c")
+    assert_equal sass.render, sass.render
+  end
+
+  def test_alternate_styles
+    renders_correctly "expanded", { :style => :expanded }
+    renders_correctly "compact", { :style => :compact }
+    renders_correctly "nested", { :style => :nested }
+    renders_correctly "compressed", { :style => :compressed }
+  end
+
+  def test_compile
+    assert_equal "div { hello: world; }\n", Sass.compile("$who: world\ndiv\n  hello: $who", :syntax => 
:sass, :style => :compact)
+    assert_equal "div { hello: world; }\n", Sass.compile("$who: world; div { hello: $who }", :style => 
:compact)
+  end
+
+  def test_compile_file
+    FileUtils.mkdir_p(absolutize("tmp"))
+    open(absolutize("tmp/test_compile_file.sass"), "w") {|f| f.write("$who: world\ndiv\n  hello: $who")}
+    open(absolutize("tmp/test_compile_file.scss"), "w") {|f| f.write("$who: world; div { hello: $who }")}
+    assert_equal "div { hello: world; }\n", Sass.compile_file(absolutize("tmp/test_compile_file.sass"), 
:style => :compact)
+    assert_equal "div { hello: world; }\n", Sass.compile_file(absolutize("tmp/test_compile_file.scss"), 
:style => :compact)
+  ensure
+    FileUtils.rm_rf(absolutize("tmp"))
+  end
+
+  def test_compile_file_to_css_file
+    FileUtils.mkdir_p(absolutize("tmp"))
+    open(absolutize("tmp/test_compile_file.sass"), "w") {|f| f.write("$who: world\ndiv\n  hello: $who")}
+    open(absolutize("tmp/test_compile_file.scss"), "w") {|f| f.write("$who: world; div { hello: $who }")}
+    Sass.compile_file(absolutize("tmp/test_compile_file.sass"), 
absolutize("tmp/test_compile_file_sass.css"), :style => :compact)
+    Sass.compile_file(absolutize("tmp/test_compile_file.scss"), 
absolutize("tmp/test_compile_file_scss.css"), :style => :compact)
+    assert_equal "div { hello: world; }\n", File.read(absolutize("tmp/test_compile_file_sass.css"))
+    assert_equal "div { hello: world; }\n", File.read(absolutize("tmp/test_compile_file_scss.css"))
+  ensure
+    FileUtils.rm_rf(absolutize("tmp"))
+  end
+  
+  def test_flexible_tabulation
+    assert_equal("p {\n  a: b; }\n  p q {\n    c: d; }\n",
+                 render("p\n a: b\n q\n  c: d\n"))
+    assert_equal("p {\n  a: b; }\n  p q {\n    c: d; }\n",
+                 render("p\n\ta: b\n\tq\n\t\tc: d\n"))
+  end
+
+  def test_import_same_name_different_ext
+    assert_raise_message Sass::SyntaxError, <<ERROR do
+It's not clear which file to import for '@import "same_name_different_ext"'.
+Candidates:
+  same_name_different_ext.sass
+  same_name_different_ext.scss
+Please delete or rename all but one of these files.
+ERROR
+      options = {:load_paths => [File.dirname(__FILE__) + '/templates/']}
+      munge_filename options
+      Sass::Engine.new("@import 'same_name_different_ext'", options).render
+    end
+  end
+
+  def test_import_same_name_different_partiality
+    assert_raise_message Sass::SyntaxError, <<ERROR do
+It's not clear which file to import for '@import "same_name_different_partiality"'.
+Candidates:
+  _same_name_different_partiality.scss
+  same_name_different_partiality.scss
+Please delete or rename all but one of these files.
+ERROR
+      options = {:load_paths => [File.dirname(__FILE__) + '/templates/']}
+      munge_filename options
+      Sass::Engine.new("@import 'same_name_different_partiality'", options).render
+    end
+  end
+
+  EXCEPTION_MAP.each do |key, value|
+    define_method("test_exception (#{key.inspect})") do
+      line = 10
+      begin
+        silence_warnings {Sass::Engine.new(key, :filename => FAKE_FILE_NAME, :line => line).render}
+      rescue Sass::SyntaxError => err
+        value = [value] unless value.is_a?(Array)
+
+        assert_equal(value.first.rstrip, err.message, "Line: #{key}")
+        assert_equal(FAKE_FILE_NAME, err.sass_filename)
+        assert_equal((value[1] || key.split("\n").length) + line - 1, err.sass_line, "Line: #{key}")
+        assert_match(/#{Regexp.escape(FAKE_FILE_NAME)}:[0-9]+/, err.backtrace[0], "Line: #{key}")
+      else
+        assert(false, "Exception not raised for\n#{key}")
+      end
+    end
+  end
+
+  def test_exception_line
+    to_render = <<SASS
+rule
+  :prop val
+  // comment!
+
+  :broken
+SASS
+    begin
+      Sass::Engine.new(to_render).render
+    rescue Sass::SyntaxError => err
+      assert_equal(5, err.sass_line)
+    else
+      assert(false, "Exception not raised for '#{to_render}'!")
+    end
+  end
+
+  def test_exception_location
+    to_render = <<SASS
+rule
+  :prop val
+  // comment!
+
+  :broken
+SASS
+    begin
+      Sass::Engine.new(to_render, :filename => FAKE_FILE_NAME, :line => (__LINE__-7)).render
+    rescue Sass::SyntaxError => err
+      assert_equal(FAKE_FILE_NAME, err.sass_filename)
+      assert_equal((__LINE__-6), err.sass_line)
+    else
+      assert(false, "Exception not raised for '#{to_render}'!")
+    end
+  end
+
+  def test_imported_exception
+    [1, 2, 3, 4].each do |i|
+      begin
+        Sass::Engine.new("@import bork#{i}", :load_paths => [File.dirname(__FILE__) + '/templates/']).render
+      rescue Sass::SyntaxError => err
+        assert_equal(2, err.sass_line)
+        assert_match(/(\/|^)bork#{i}\.sass$/, err.sass_filename)
+
+        assert_hash_has(err.sass_backtrace.first,
+          :filename => err.sass_filename, :line => err.sass_line)
+
+        assert_nil(err.sass_backtrace[1][:filename])
+        assert_equal(1, err.sass_backtrace[1][:line])
+
+        assert_match(/(\/|^)bork#{i}\.sass:2$/, err.backtrace.first)
+        assert_equal("(sass):1", err.backtrace[1])
+      else
+        assert(false, "Exception not raised for imported template: bork#{i}")
+      end
+    end
+  end
+
+  def test_double_imported_exception
+    [1, 2, 3, 4].each do |i|
+      begin
+        Sass::Engine.new("@import nested_bork#{i}", :load_paths => [File.dirname(__FILE__) + 
'/templates/']).render
+      rescue Sass::SyntaxError => err
+        assert_equal(2, err.sass_line)
+        assert_match(/(\/|^)bork#{i}\.sass$/, err.sass_filename)
+
+        assert_hash_has(err.sass_backtrace.first,
+          :filename => err.sass_filename, :line => err.sass_line)
+
+        assert_match(/(\/|^)nested_bork#{i}\.sass$/, err.sass_backtrace[1][:filename])
+        assert_equal(2, err.sass_backtrace[1][:line])
+
+        assert_nil(err.sass_backtrace[2][:filename])
+        assert_equal(1, err.sass_backtrace[2][:line])
+
+        assert_match(/(\/|^)bork#{i}\.sass:2$/, err.backtrace.first)
+        assert_match(/(\/|^)nested_bork#{i}\.sass:2$/, err.backtrace[1])
+        assert_equal("(sass):1", err.backtrace[2])
+      else
+        assert(false, "Exception not raised for imported template: bork#{i}")
+      end
+    end
+  end
+
+  def test_selector_tracing
+    actual_css = render(<<-SCSS, :syntax => :scss, :trace_selectors => true)
+      @mixin mixed {
+        .mixed { color: red; }
+      }
+      .context {
+        @include mixed;
+      }
+    SCSS
+    assert_equal(<<CSS,actual_css)
+/* on line 2 of test_selector_tracing_inline.scss, in `mixed'
+   from line 5 of test_selector_tracing_inline.scss */
+.context .mixed {
+  color: red; }
+CSS
+  end
+
+  def test_mixin_exception
+    render(<<SASS)
+=error-mixin($a)
+  color: $a * 1em * 1px
+
+=outer-mixin($a)
+  +error-mixin($a)
+
+.error
+  +outer-mixin(12)
+SASS
+    assert(false, "Exception not raised")
+  rescue Sass::SyntaxError => err
+    assert_equal(2, err.sass_line)
+    assert_equal(filename_for_test, err.sass_filename)
+    assert_equal("error-mixin", err.sass_mixin)
+
+    assert_hash_has(err.sass_backtrace.first, :line => err.sass_line,
+      :filename => err.sass_filename, :mixin => err.sass_mixin)
+    assert_hash_has(err.sass_backtrace[1], :line => 5,
+      :filename => filename_for_test, :mixin => "outer-mixin")
+    assert_hash_has(err.sass_backtrace[2], :line => 8,
+      :filename => filename_for_test, :mixin => nil)
+
+    assert_equal("#{filename_for_test}:2:in `error-mixin'", err.backtrace.first)
+    assert_equal("#{filename_for_test}:5:in `outer-mixin'", err.backtrace[1])
+    assert_equal("#{filename_for_test}:8", err.backtrace[2])
+  end
+
+  def test_mixin_callsite_exception
+    render(<<SASS)
+=one-arg-mixin($a)
+  color: $a
+
+=outer-mixin($a)
+  +one-arg-mixin($a, 12)
+
+.error
+  +outer-mixin(12)
+SASS
+    assert(false, "Exception not raised")
+  rescue Sass::SyntaxError => err
+    assert_hash_has(err.sass_backtrace.first, :line => 5,
+      :filename => filename_for_test, :mixin => "one-arg-mixin")
+    assert_hash_has(err.sass_backtrace[1], :line => 5,
+      :filename => filename_for_test, :mixin => "outer-mixin")
+    assert_hash_has(err.sass_backtrace[2], :line => 8,
+      :filename => filename_for_test, :mixin => nil)
+  end
+
+  def test_mixin_exception_cssize
+    render(<<SASS)
+=parent-ref-mixin
+  & foo
+    a: b
+
+=outer-mixin
+  +parent-ref-mixin
+
++outer-mixin
+SASS
+    assert(false, "Exception not raised")
+  rescue Sass::SyntaxError => err
+    assert_hash_has(err.sass_backtrace.first, :line => 2,
+      :filename => filename_for_test, :mixin => "parent-ref-mixin")
+    assert_hash_has(err.sass_backtrace[1], :line => 6,
+      :filename => filename_for_test, :mixin => "outer-mixin")
+    assert_hash_has(err.sass_backtrace[2], :line => 8,
+      :filename => filename_for_test, :mixin => nil)
+  end
+
+  def test_mixin_and_import_exception
+    Sass::Engine.new("@import nested_mixin_bork", :load_paths => [File.dirname(__FILE__) + 
'/templates/']).render
+    assert(false, "Exception not raised")
+  rescue Sass::SyntaxError => err
+    assert_match(/(\/|^)nested_mixin_bork\.sass$/, err.sass_backtrace.first[:filename])
+    assert_hash_has(err.sass_backtrace.first, :mixin => "error-mixin", :line => 4)
+
+    assert_match(/(\/|^)mixin_bork\.sass$/, err.sass_backtrace[1][:filename])
+    assert_hash_has(err.sass_backtrace[1], :mixin => "outer-mixin", :line => 2)
+
+    assert_match(/(\/|^)mixin_bork\.sass$/, err.sass_backtrace[2][:filename])
+    assert_hash_has(err.sass_backtrace[2], :mixin => nil, :line => 5)
+
+    assert_match(/(\/|^)nested_mixin_bork\.sass$/, err.sass_backtrace[3][:filename])
+    assert_hash_has(err.sass_backtrace[3], :mixin => nil, :line => 6)
+
+    assert_hash_has(err.sass_backtrace[4], :filename => nil, :mixin => nil, :line => 1)
+  end
+
+  def test_recursive_mixin
+    assert_equal <<CSS, render(<<SASS)
+.foo .bar .baz {
+  color: blue; }
+.foo .bar .qux {
+  color: red; }
+.foo .zap {
+  color: green; }
+CSS
+ mixin map-to-rule($map-or-color)
+  @if type-of($map-or-color) == map
+    @each $key, $value in $map-or-color
+      .\#{$key}
+        @include map-to-rule($value)
+  @else
+    color: $map-or-color
+
+ include map-to-rule((foo: (bar: (baz: blue, qux: red), zap: green)))
+SASS
+  end
+
+  def test_double_import_loop_exception
+    importer = MockImporter.new
+    importer.add_import("foo", "@import 'bar'")
+    importer.add_import("bar", "@import 'foo'")
+
+    engine = Sass::Engine.new('@import "foo"', :filename => filename_for_test,
+      :load_paths => [importer], :importer => importer)
+
+    assert_raise_message(Sass::SyntaxError, <<ERR.rstrip) {engine.render}
+An @import loop has been found:
+    #{filename_for_test} imports foo
+    foo imports bar
+    bar imports foo
+ERR
+  end
+
+  def test_deep_import_loop_exception
+    importer = MockImporter.new
+    importer.add_import("foo", "@import 'bar'")
+    importer.add_import("bar", "@import 'baz'")
+    importer.add_import("baz", "@import 'foo'")
+
+    engine = Sass::Engine.new('@import "foo"', :filename => filename_for_test,
+      :load_paths => [importer], :importer => importer)
+
+    assert_raise_message(Sass::SyntaxError, <<ERR.rstrip) {engine.render}
+An @import loop has been found:
+    #{filename_for_test} imports foo
+    foo imports bar
+    bar imports baz
+    baz imports foo
+ERR
+  end
+
+  def test_exception_css_with_offset
+    opts = {:full_exception => true, :line => 362}
+    render(("a\n  b: c\n" * 10) + "d\n  e:\n" + ("f\n  g: h\n" * 10), opts)
+  rescue Sass::SyntaxError => e
+    assert_equal(<<CSS, Sass::SyntaxError.exception_to_css(e, opts[:line]).split("\n")[0..15].join("\n"))
+/*
+Error: Invalid property: "e:" (no value).
+        on line 383 of test_exception_css_with_offset_inline.sass
+
+378: a
+379:   b: c
+380: a
+381:   b: c
+382: d
+383:   e:
+384: f
+385:   g: h
+386: f
+387:   g: h
+388: f
+CSS
+  else
+    assert(false, "Exception not raised for test_exception_css_with_offset")
+  end
+
+  def test_exception_css_with_mixins
+    render(<<SASS, :full_exception => true)
+=error-mixin($a)
+  color: $a * 1em * 1px
+
+=outer-mixin($a)
+  +error-mixin($a)
+
+.error
+  +outer-mixin(12)
+SASS
+  rescue Sass::SyntaxError => e
+    assert_equal(<<CSS, Sass::SyntaxError.exception_to_css(e).split("\n")[0..13].join("\n"))
+/*
+Error: 12em*px isn't a valid CSS value.
+        on line 2 of test_exception_css_with_mixins_inline.sass, in `error-mixin'
+        from line 5 of test_exception_css_with_mixins_inline.sass, in `outer-mixin'
+        from line 8 of test_exception_css_with_mixins_inline.sass
+
+1: =error-mixin($a)
+2:   color: $a * 1em * 1px
+3: 
+4: =outer-mixin($a)
+5:   +error-mixin($a)
+6: 
+7: .error
+CSS
+  else
+    assert(false, "Exception not raised")
+  end
+
+  def test_cssize_exception_css
+    render(<<SASS, :full_exception => true)
+.filler
+  stuff: "stuff!"
+
+a: b
+
+.more.filler
+  a: b
+SASS
+  rescue Sass::SyntaxError => e
+    assert_equal(<<CSS, Sass::SyntaxError.exception_to_css(e).split("\n")[0..11].join("\n"))
+/*
+Error: Properties are only allowed within rules, directives, mixin includes, or other properties.
+        on line 4 of test_cssize_exception_css_inline.sass
+
+1: .filler
+2:   stuff: "stuff!"
+3: 
+4: a: b
+5: 
+6: .more.filler
+7:   a: b
+CSS
+  else
+    assert(false, "Exception not raised")
+  end
+
+  def test_css_import
+    assert_equal("@import url(./fonts.css);\n", render("@import \"./fonts.css\""))
+  end
+
+  def test_http_import
+    assert_equal("@import \"http://fonts.googleapis.com/css?family=Droid+Sans\";\n";,
+      render("@import \"http://fonts.googleapis.com/css?family=Droid+Sans\"";))
+  end
+
+  def test_protocol_relative_import
+    assert_equal("@import \"//fonts.googleapis.com/css?family=Droid+Sans\";\n",
+      render("@import \"//fonts.googleapis.com/css?family=Droid+Sans\""))
+  end
+
+  def test_import_with_interpolation
+    assert_equal(<<CSS, render(<<SASS))
+ import url("http://fonts.googleapis.com/css?family=Droid+Sans";);
+CSS
+$family: unquote("Droid+Sans")
+ import url("http://fonts.googleapis.com/css?family=\#{$family}";)
+SASS
+  end
+
+  def test_import_with_dynamic_media_query
+    assert_equal(<<CSS, render(<<SASS))
+ import "foo" print and (-webkit-min-device-pixel-ratio-foo: 25);
+CSS
+$media: print
+$key: -webkit-min-device-pixel-ratio
+$value: 20
+ import "foo" \#{$media} and ($key + "-foo": $value + 5)
+SASS
+  end
+
+  def test_url_import
+    assert_equal("@import url(fonts.sass);\n", render("@import url(fonts.sass)"))
+  end
+
+  def test_sass_import
+    sassc_file = sassc_path("importee")
+    assert !File.exist?(sassc_file)
+    renders_correctly "import", { :style => :compact, :load_paths => [File.dirname(__FILE__) + "/templates"] 
}
+    assert File.exist?(sassc_file)
+  end
+
+  def test_sass_pathname_import
+    sassc_file = sassc_path("importee")
+    assert !File.exist?(sassc_file)
+    renders_correctly("import",
+      :style => :compact,
+      :load_paths => [Pathname.new(File.dirname(__FILE__) + "/templates")])
+    assert File.exist?(sassc_file)
+  end
+
+  def test_import_from_global_load_paths
+    importer = MockImporter.new
+    importer.add_import("imported", "div{color:red}")
+    Sass.load_paths << importer
+
+    assert_equal "div {\n  color: red; }\n", Sass::Engine.new('@import "imported"', :importer => 
importer).render
+  ensure
+    Sass.load_paths.clear
+  end
+
+  def test_nonexistent_import
+    assert_raise_message(Sass::SyntaxError, <<ERR.rstrip) do
+File to import not found or unreadable: nonexistent.sass.
+Load path: #{Dir.pwd}
+ERR
+      render("@import nonexistent.sass")
+    end
+  end
+
+  def test_nonexistent_extensionless_import
+    assert_raise_message(Sass::SyntaxError, <<ERR.rstrip) do
+File to import not found or unreadable: nonexistent.
+Load path: #{Dir.pwd}
+ERR
+      render("@import nonexistent")
+    end
+  end
+
+  def test_no_cache
+    assert !File.exist?(sassc_path("importee"))
+    renders_correctly("import", {
+        :style => :compact, :cache => false,
+        :load_paths => [File.dirname(__FILE__) + "/templates"],
+      })
+    assert !File.exist?(sassc_path("importee"))
+  end
+
+  def test_import_in_rule
+    assert_equal(<<CSS, render(<<SASS, :load_paths => [File.dirname(__FILE__) + '/templates/']))
+.foo #foo {
+  background-color: #baf; }
+
+.bar {
+  a: b; }
+  .bar #foo {
+    background-color: #baf; }
+CSS
+.foo
+  @import partial
+
+.bar
+  a: b
+  @import partial
+SASS
+  end
+
+  def test_units
+    renders_correctly "units"
+  end
+
+  def test_default_function
+    assert_equal(<<CSS, render(<<SASS))
+foo {
+  bar: url("foo.png"); }
+CSS
+foo
+  bar: url("foo.png")
+SASS
+    assert_equal("foo {\n  bar: url(); }\n", render("foo\n  bar: url()\n"));
+  end
+
+  def test_string_minus
+    assert_equal("foo {\n  bar: baz-boom-bat; }\n", render(%Q{foo\n  bar: baz-boom-bat}))
+    assert_equal("foo {\n  bar: -baz-boom; }\n", render(%Q{foo\n  bar: -baz-boom}))
+  end
+
+  def test_string_div
+    assert_equal("foo {\n  bar: baz/boom/bat; }\n", render(%Q{foo\n  bar: baz/boom/bat}))
+    assert_equal("foo {\n  bar: /baz/boom; }\n", render(%Q{foo\n  bar: /baz/boom}))
+  end
+
+  def test_basic_multiline_selector
+    assert_equal("#foo #bar,\n#baz #boom {\n  foo: bar; }\n",
+                 render("#foo #bar,\n#baz #boom\n  :foo bar"))
+    assert_equal("#foo #bar,\n#foo #baz {\n  foo: bar; }\n",
+                 render("#foo\n  #bar,\n  #baz\n    :foo bar"))
+    assert_equal("#foo,\n#bar {\n  foo: bar; }\n  #foo #baz,\n  #bar #baz {\n    foo: bar; }\n",
+                 render("#foo,\n#bar\n  :foo bar\n  #baz\n    :foo bar"))
+    assert_equal("#foo #bar, #baz #boom { foo: bar; }\n",
+                 render("#foo #bar,\n#baz #boom\n  :foo bar", :style => :compact))
+                 
+    assert_equal("#foo #bar,#baz #boom{foo:bar}\n",
+                 render("#foo #bar,\n#baz #boom\n  :foo bar", :style => :compressed))
+
+    assert_equal("#foo #bar,\n#baz #boom {\n  foo: bar; }\n",
+                 render("#foo #bar,,\n,#baz #boom,\n  :foo bar"))
+
+    assert_equal("#bip #bop {\n  foo: bar; }\n",
+                 render("#bip #bop,, ,\n  :foo bar"))
+  end
+
+  def test_complex_multiline_selector
+    renders_correctly "multiline"
+  end
+
+  def test_colon_only
+    begin
+      render("a\n  b: c", :property_syntax => :old)
+    rescue Sass::SyntaxError => e
+      assert_equal("Illegal property syntax: can't use new syntax when :property_syntax => :old is set.",
+                   e.message)
+      assert_equal(2, e.sass_line)
+    else
+      assert(false, "SyntaxError not raised for :property_syntax => :old")
+    end
+
+    begin
+      render("a\n  :b c", :property_syntax => :new)
+      assert_equal(2, e.sass_line)
+    rescue Sass::SyntaxError => e
+      assert_equal("Illegal property syntax: can't use old syntax when :property_syntax => :new is set.",
+                   e.message)
+    else
+      assert(false, "SyntaxError not raised for :property_syntax => :new")
+    end
+  end
+
+  def test_pseudo_elements
+    assert_equal(<<CSS, render(<<SASS))
+::first-line {
+  size: 10em; }
+CSS
+::first-line
+  size: 10em
+SASS
+  end
+
+  def test_directive
+    assert_equal("@a b;\n", render("@a b"))
+
+    assert_equal("@a {\n  b: c; }\n", render("@a\n  :b c"))
+    assert_equal("@a { b: c; }\n", render("@a\n  :b c", :style => :compact))
+    assert_equal("@a {\n  b: c;\n}\n", render("@a\n  :b c", :style => :expanded))
+    assert_equal("@a{b:c}\n", render("@a\n  :b c", :style => :compressed))
+
+    assert_equal("@a {\n  b: c;\n  d: e; }\n",
+                 render("@a\n  :b c\n  :d e"))
+    assert_equal("@a { b: c; d: e; }\n",
+                 render("@a\n  :b c\n  :d e", :style => :compact))
+    assert_equal("@a {\n  b: c;\n  d: e;\n}\n",
+                 render("@a\n  :b c\n  :d e", :style => :expanded))
+    assert_equal("@a{b:c;d:e}\n",
+                 render("@a\n  :b c\n  :d e", :style => :compressed))
+
+    assert_equal("@a {\n  #b {\n    c: d; } }\n",
+                 render("@a\n  #b\n    :c d"))
+    assert_equal("@a { #b { c: d; } }\n",
+                 render("@a\n  #b\n    :c d", :style => :compact))
+    assert_equal("@a {\n  #b {\n    c: d;\n  }\n}\n",
+                 render("@a\n  #b\n    :c d", :style => :expanded))
+    assert_equal("@a{#b{c:d}}\n",
+                 render("@a\n  #b\n    :c d", :style => :compressed))
+
+    assert_equal("@a {\n  #b {\n    a: b; }\n    #b #c {\n      d: e; } }\n",
+                 render("@a\n  #b\n    :a b\n    #c\n      :d e"))
+    assert_equal("@a { #b { a: b; }\n  #b #c { d: e; } }\n",
+                 render("@a\n  #b\n    :a b\n    #c\n      :d e", :style => :compact))
+    assert_equal("@a {\n  #b {\n    a: b;\n  }\n  #b #c {\n    d: e;\n  }\n}\n",
+                 render("@a\n  #b\n    :a b\n    #c\n      :d e", :style => :expanded))
+    assert_equal("@a{#b{a:b}#b #c{d:e}}\n",
+                 render("@a\n  #b\n    :a b\n    #c\n      :d e", :style => :compressed))
+                 
+    assert_equal("@a {\n  #foo,\n  #bar {\n    b: c; } }\n",
+                 render("@a\n  #foo, \n  #bar\n    :b c"))
+    assert_equal("@a { #foo, #bar { b: c; } }\n",
+                 render("@a\n  #foo, \n  #bar\n    :b c", :style => :compact))
+    assert_equal("@a {\n  #foo,\n  #bar {\n    b: c;\n  }\n}\n",
+                 render("@a\n  #foo, \n  #bar\n    :b c", :style => :expanded))
+    assert_equal("@a{#foo,#bar{b:c}}\n",
+                 render("@a\n  #foo, \n  #bar\n    :b c", :style => :compressed))
+
+    to_render = <<END
+ a
+  :b c
+  #d
+    :e f
+  :g h
+END
+    rendered = <<END
+ a { b: c;
+  #d { e: f; }
+  g: h; }
+END
+    assert_equal(rendered, render(to_render, :style => :compact))
+    
+    assert_equal("@a{b:c;#d{e:f}g:h}\n", render(to_render, :style => :compressed))
+  end
+
+  def test_property_hacks
+    assert_equal(<<CSS, render(<<SASS))
+foo {
+  _name: val;
+  *name: val;
+  #name: val;
+  .name: val;
+  name/**/: val;
+  name/*\\**/: val;
+  name: val; }
+CSS
+foo
+  _name: val
+  *name: val
+  #name: val
+  .name: val
+  name/**/: val
+  name/*\\**/: val
+  name: val
+SASS
+  end
+
+  def test_properties_with_space_after_colon
+    assert_equal <<CSS, render(<<SASS)
+foo {
+  bar: baz;
+  bizz: bap; }
+CSS
+foo
+  bar : baz
+  bizz : bap
+SASS
+  end
+
+  def test_line_annotations
+    assert_equal(<<CSS, render(<<SASS, :line_comments => true, :style => :compact))
+/* line 2, test_line_annotations_inline.sass */
+foo bar { foo: bar; }
+/* line 5, test_line_annotations_inline.sass */
+foo baz { blip: blop; }
+
+/* line 9, test_line_annotations_inline.sass */
+floodle { flop: blop; }
+
+/* line 18, test_line_annotations_inline.sass */
+bup { mix: on; }
+/* line 15, test_line_annotations_inline.sass */
+bup mixin { moop: mup; }
+
+/* line 22, test_line_annotations_inline.sass */
+bip hop, skip hop { a: b; }
+CSS
+foo
+  bar
+    foo: bar
+
+  baz
+    blip: blop
+
+
+floodle
+
+  flop: blop
+
+=mxn
+  mix: on
+  mixin
+    moop: mup
+
+bup
+  +mxn
+
+bip, skip
+  hop
+    a: b
+SASS
+  end
+
+  def test_line_annotations_with_filename
+    renders_correctly "line_numbers", :line_comments => true, :load_paths => [File.dirname(__FILE__) + 
"/templates"]
+  end
+
+  def test_debug_info
+    esc_file_name = Sass::SCSS::RX.escape_ident(Sass::Util.scope("test_debug_info_inline.sass"))
+
+    assert_equal(<<CSS, render(<<SASS, :debug_info => true, :style => :compact))
+ media -sass-debug-info{filename{font-family:file\\:\\/\\/#{esc_file_name}}line{font-family:\\000032}}
+foo bar { foo: bar; }
+ media -sass-debug-info{filename{font-family:file\\:\\/\\/#{esc_file_name}}line{font-family:\\000035}}
+foo baz { blip: blop; }
+
+ media -sass-debug-info{filename{font-family:file\\:\\/\\/#{esc_file_name}}line{font-family:\\000039}}
+floodle { flop: blop; }
+
+ media -sass-debug-info{filename{font-family:file\\:\\/\\/#{esc_file_name}}line{font-family:\\0000318}}
+bup { mix: on; }
+ media -sass-debug-info{filename{font-family:file\\:\\/\\/#{esc_file_name}}line{font-family:\\0000315}}
+bup mixin { moop: mup; }
+
+ media -sass-debug-info{filename{font-family:file\\:\\/\\/#{esc_file_name}}line{font-family:\\0000322}}
+bip hop, skip hop { a: b; }
+CSS
+foo
+  bar
+    foo: bar
+
+  baz
+    blip: blop
+
+
+floodle
+
+  flop: blop
+
+=mxn
+  mix: on
+  mixin
+    moop: mup
+
+bup
+  +mxn
+
+bip, skip
+  hop
+    a: b
+SASS
+  end
+
+  def test_debug_info_without_filename
+    assert_equal(<<CSS, Sass::Engine.new(<<SASS, :debug_info => true).render)
+ media -sass-debug-info{filename{}line{font-family:\\000031}}
+foo {
+  a: b; }
+CSS
+foo
+  a: b
+SASS
+  end
+
+  def test_debug_info_with_compressed
+    assert_equal(<<CSS, render(<<SASS, :debug_info => true, :style => :compressed))
+foo{a:b}
+CSS
+foo
+  a: b
+SASS
+  end
+
+  def test_debug_info_with_line_annotations
+    esc_file_name = 
Sass::SCSS::RX.escape_ident(Sass::Util.scope("test_debug_info_with_line_annotations_inline.sass"))
+
+    assert_equal(<<CSS, render(<<SASS, :debug_info => true, :line_comments => true))
+ media -sass-debug-info{filename{font-family:file\\:\\/\\/#{esc_file_name}}line{font-family:\\000031}}
+foo {
+  a: b; }
+CSS
+foo
+  a: b
+SASS
+  end
+
+  def test_debug_info_in_keyframes
+    assert_equal(<<CSS, render(<<SASS, :debug_info => true))
+ -webkit-keyframes warm {
+  from {
+    color: black; }
+  to {
+    color: red; } }
+CSS
+ -webkit-keyframes warm
+  from
+    color: black
+  to
+    color: red
+SASS
+  end
+
+  def test_empty_first_line
+    assert_equal("#a {\n  b: c; }\n", render("#a\n\n  b: c"))
+  end
+
+  def test_escaped_rule
+    assert_equal(":focus {\n  a: b; }\n", render("\\:focus\n  a: b"))
+    assert_equal("a {\n  b: c; }\n  a :focus {\n    d: e; }\n", render("\\a\n  b: c\n  \\:focus\n    d: e"))
+  end
+
+  def test_cr_newline
+    assert_equal("foo {\n  a: b;\n  c: d;\n  e: f; }\n", render("foo\r  a: b\r\n  c: d\n\r  e: f"))
+  end
+
+  def test_property_with_content_and_nested_props
+    assert_equal(<<CSS, render(<<SASS))
+foo {
+  a: b;
+    a-c: d;
+      a-c-e: f; }
+CSS
+foo
+  a: b
+    c: d
+      e: f
+SASS
+
+    assert_equal(<<CSS, render(<<SASS))
+foo {
+  a: b;
+    a-c-e: f; }
+CSS
+foo
+  a: b
+    c:
+      e: f
+SASS
+  end
+
+  def test_guarded_assign
+    assert_equal("foo {\n  a: b; }\n", render(%Q{$foo: b\n$foo: c !default\nfoo\n  a: $foo}))
+    assert_equal("foo {\n  a: b; }\n", render(%Q{$foo: b !default\nfoo\n  a: $foo}))
+    assert_equal("foo {\n  a: b; }\n", render(%Q{$foo: null\n$foo: b !default\nfoo\n  a: $foo}))
+  end
+  
+  def test_mixins
+    renders_correctly "mixins", { :style => :expanded }
+  end
+
+  def test_directive_style_mixins
+    assert_equal <<CSS, render(<<SASS)
+bar {
+  prop: baz; }
+CSS
+ mixin foo($arg)
+  prop: $arg
+
+bar
+  @include foo(baz)
+SASS
+  end
+
+  def test_mixins_dont_interfere_with_sibling_combinator
+    assert_equal("foo + bar {\n  a: b; }\nfoo + baz {\n  c: d; }\n",
+                 render("foo\n  +\n    bar\n      a: b\n    baz\n      c: d"))
+  end
+
+  def test_mixin_args
+    assert_equal("blat {\n  baz: hi; }\n", render(<<SASS))
+=foo($bar)
+  baz: $bar
+blat
+  +foo(hi)
+SASS
+    assert_equal("blat {\n  baz: 3; }\n", render(<<SASS))
+=foo($a, $b)
+  baz: $a + $b
+blat
+  +foo(1, 2)
+SASS
+    assert_equal("blat {\n  baz: 4;\n  baz: 3;\n  baz: 5;\n  bang: 3; }\n", render(<<SASS))
+=foo($c: (6 + 4) / 2)
+  baz: $c
+$c: 3
+blat
+  +foo($c + 1)
+  +foo(($c + 3)/2)
+  +foo
+  bang: $c
+SASS
+  end
+
+  def test_default_values_for_mixin_arguments
+    assert_equal(<<CSS, render(<<SASS))
+white {
+  color: #FFF; }
+
+black {
+  color: #000; }
+CSS
+=foo($a: #FFF)
+  :color $a
+white
+  +foo
+black
+  +foo(#000)
+SASS
+    assert_equal(<<CSS, render(<<SASS))
+one {
+  color: #fff;
+  padding: 1px;
+  margin: 4px; }
+
+two {
+  color: #fff;
+  padding: 2px;
+  margin: 5px; }
+
+three {
+  color: #fff;
+  padding: 2px;
+  margin: 3px; }
+CSS
+$a: 5px
+=foo($a, $b: 1px, $c: 3px + $b)
+  :color $a
+  :padding $b
+  :margin $c
+one
+  +foo(#fff)
+two
+  +foo(#fff, 2px)
+three
+  +foo(#fff, 2px, 3px)
+SASS
+    assert_equal(<<CSS, render(<<SASS))
+one {
+  color: #fff;
+  padding: 1px;
+  margin: 4px; }
+
+two {
+  color: #fff;
+  padding: 2px;
+  margin: 5px; }
+
+three {
+  color: #fff;
+  padding: 2px;
+  margin: 3px; }
+CSS
+$a: 5px
+=foo($a, $b: 1px, $c: null)
+  $c: 3px + $b !default
+  color: $a
+  padding: $b
+  margin: $c
+one
+  +foo(#fff)
+two
+  +foo(#fff, 2px)
+three
+  +foo(#fff, 2px, 3px)
+SASS
+  end
+
+  def test_hyphen_underscore_insensitive_mixins
+    assert_equal(<<CSS, render(<<SASS))
+a {
+  b: 12;
+  c: foo; }
+CSS
+=mixin-hyphen
+  b: 12
+
+=mixin_under
+  c: foo
+
+a
+  +mixin_hyphen
+  +mixin-under
+SASS
+  end
+
+  def test_css_identifier_mixin
+    assert_equal(<<CSS, render(<<SASS))
+a {
+  foo: 12; }
+CSS
+=\\{foo\\(12\\)($a)
+  foo: $a
+
+a
+  +\\{foo\\(12\\)(12)
+SASS
+  end
+
+  def test_basic_function
+    assert_equal(<<CSS, render(<<SASS))
+bar {
+  a: 3; }
+CSS
+ function foo()
+  @return 1 + 2
+
+bar
+  a: foo()
+SASS
+  end
+
+  def test_function_args
+    assert_equal(<<CSS, render(<<SASS))
+bar {
+  a: 3; }
+CSS
+ function plus($var1, $var2)
+  @return $var1 + $var2
+
+bar
+  a: plus(1, 2)
+SASS
+  end
+
+  def test_function_arg_default
+    assert_equal(<<CSS, render(<<SASS))
+bar {
+  a: 3; }
+CSS
+ function plus($var1, $var2: 2)
+  @return $var1 + $var2
+
+bar
+  a: plus(1)
+SASS
+  end
+
+  def test_function_arg_keyword
+    assert_equal(<<CSS, render(<<SASS))
+bar {
+  a: 1bar; }
+CSS
+ function plus($var1: 1, $var2: 2)
+  @return $var1 + $var2
+
+bar
+  a: plus($var2: bar)
+SASS
+  end
+
+  def test_function_with_missing_argument
+    render(<<SASS)
+ function plus($var1, $var2)
+  @return $var1 + $var2
+
+bar
+  a: plus($var2: bar)
+SASS
+    flunk("Expected exception")
+  rescue Sass::SyntaxError => e
+    assert_equal("Function plus is missing argument $var1.", e.message)
+  end
+
+  def test_function_with_extra_argument
+    render(<<SASS)
+ function plus($var1, $var2)
+  @return $var1 + $var2
+
+bar
+  a: plus($var1: foo, $var2: bar, $var3: baz)
+SASS
+    flunk("Expected exception")
+  rescue Sass::SyntaxError => e
+    assert_equal("Function plus doesn't have an argument named $var3.", e.message)
+  end
+
+  def test_function_with_positional_and_keyword_argument
+    render(<<SASS)
+ function plus($var1, $var2)
+  @return $var1 + $var2
+
+bar
+  a: plus(foo, bar, $var2: baz)
+SASS
+    flunk("Expected exception")
+  rescue Sass::SyntaxError => e
+    assert_equal("Function plus was passed argument $var2 both by position and by name.", e.message)
+  end
+
+  def test_function_with_keyword_before_positional_argument
+    render(<<SASS)
+ function plus($var1, $var2)
+  @return $var1 + $var2
+
+bar
+  a: plus($var2: foo, bar)
+SASS
+    flunk("Expected exception")
+  rescue Sass::SyntaxError => e
+    assert_equal("Positional arguments must come before keyword arguments.", e.message)
+  end
+
+  def test_function_with_if
+    assert_equal(<<CSS, render(<<SASS))
+bar {
+  a: foo;
+  b: bar; }
+CSS
+ function my-if($cond, $val1, $val2)
+  @if $cond
+    @return $val1
+  @else
+    @return $val2
+
+bar
+  a: my-if(true, foo, bar)
+  b: my-if(false, foo, bar)
+SASS
+  end
+
+  def test_function_with_var
+    assert_equal(<<CSS, render(<<SASS))
+bar {
+  a: 1; }
+CSS
+ function foo($val1, $val2)
+  $intermediate: $val1 + $val2
+  @return $intermediate/3
+
+bar
+  a: foo(1, 2)
+SASS
+  end
+
+  def test_user_defined_function_variable_scope
+    render(<<SASS)
+bar
+  -no-op: set-a-variable(variable, 5)
+  a: $variable
+SASS
+    flunk("Exception not raised for test_user_defined_function_variable_scope")
+  rescue Sass::SyntaxError => e
+    assert_equal('Undefined variable: "$variable".', e.message)
+  end
+
+  def test_user_defined_function_can_change_global_variable
+    assert_equal(<<CSS, render(<<SASS))
+bar {
+  a: 5; }
+CSS
+$variable: 0
+bar
+  $local: 10
+  -no-op: set-a-global-variable(variable, 5)
+  a: $variable
+SASS
+  end
+
+  def test_user_defined_function_cannot_read_local_variable
+    assert_equal(<<CSS, render(<<SASS))
+bar {
+  global: 0;
+  local: undefined; }
+CSS
+$global: 0
+bar
+  $local: 10
+  global: get-a-variable(global)
+  local: get-a-variable(local)
+SASS
+  end
+
+  def test_control_directive_in_nested_property
+    assert_equal(<<CSS, render(<<SASS))
+foo {
+  a-b: c; }
+CSS
+foo
+  a:
+    @if true
+      b: c
+SASS
+  end
+
+  def test_interpolation
+    assert_equal("a-1 {\n  b-2-3: c-3; }\n", render(<<SASS))
+$a: 1
+$b: 2
+$c: 3
+a-\#{$a}
+  b-\#{$b}-\#{$c}: c-\#{$a + $b}
+SASS
+  end
+
+  def test_complex_property_interpolation
+    assert_equal(<<CSS, render(<<SASS))
+a-1 {
+  b-2 3-fizzap18: c-3; }
+CSS
+$a: 1
+$b: 2
+$c: 3
+a-\#{$a}
+  b-\#{$b $c}-\#{fizzap + ($c + 15)}: c-\#{$a + $b}
+SASS
+  end
+
+  def test_if_directive
+    assert_equal("a {\n  b: 1; }\n", render(<<SASS))
+$var: true
+a
+  @if $var
+    b: 1
+  @if not $var
+    b: 2
+SASS
+
+    assert_equal("a {\n  b: 2; }\n", render(<<SASS))
+$var: null
+a
+  @if $var
+    b: 1
+  @if not $var
+    b: 2
+SASS
+  end
+
+  def test_for
+    assert_equal(<<CSS, render(<<SASS))
+a-0 {
+  two-i: 0; }
+
+a-1 {
+  two-i: 2; }
+
+a-2 {
+  two-i: 4; }
+
+a-3 {
+  two-i: 6; }
+
+b-1 {
+  j-1: 0; }
+
+b-2 {
+  j-1: 1; }
+
+b-3 {
+  j-1: 2; }
+
+b-4 {
+  j-1: 3; }
+CSS
+$a: 3
+ for $i from 0 to $a + 1
+  a-\#{$i}
+    two-i: 2 * $i
+
+ for $j from 1 through 4
+  b-\#{$j}
+    j-1: $j - 1
+SASS
+  end
+
+  def test_while
+    assert_equal(<<CSS, render(<<SASS))
+a-5 {
+  blooble: gloop; }
+
+a-4 {
+  blooble: gloop; }
+
+a-3 {
+  blooble: gloop; }
+
+a-2 {
+  blooble: gloop; }
+
+a-1 {
+  blooble: gloop; }
+CSS
+$a: 5
+ while $a != 0
+  a-\#{$a}
+    blooble: gloop
+  $a: $a - 1 !global
+SASS
+  end
+
+  def test_else
+    assert_equal(<<CSS, render(<<SASS))
+a {
+  t1: t;
+  t2: t;
+  t3: t;
+  t4: t; }
+CSS
+a
+  @if true
+    t1: t
+  @else
+    f1: f
+
+  @if false
+    f2: f
+  @else
+    t2: t
+
+  @if false
+    f3: f1
+  @else if 1 + 1 == 3
+    f3: f2
+  @else
+    t3: t
+
+  @if false
+    f4: f1
+  @else if 1 + 1 == 2
+    t4: t
+  @else
+    f4: f2
+
+  @if false
+    f5: f1
+  @else if false
+    f5: f2
+SASS
+  end
+
+  def test_each
+    assert_equal(<<CSS, render(<<SASS))
+a {
+  b: 1px;
+  b: 2px;
+  b: 3px;
+  b: 4px;
+  c: foo;
+  c: bar;
+  c: baz;
+  c: bang;
+  d: blue; }
+CSS
+a
+  @each $number in 1px 2px 3px 4px
+    b: $number
+  @each $str in foo, bar, baz, bang
+    c: $str
+  @each $single in blue
+    d: $single
+SASS
+  end
+
+  def test_destructuring_each
+    assert_equal <<CSS, render(<<SCSS)
+a {
+  foo: 1px;
+  bar: 2px;
+  baz: 3px; }
+
+c {
+  foo: "Value is bar";
+  bar: "Value is baz";
+  bang: "Value is "; }
+CSS
+a
+  @each $name, $number in (foo: 1px, bar: 2px, baz: 3px)
+    \#{$name}: $number
+c
+  @each $key, $value in (foo bar) (bar, baz) bang
+    \#{$key}: "Value is \#{$value}"
+SCSS
+  end
+
+  def test_variable_reassignment
+    assert_equal(<<CSS, render(<<SASS))
+a {
+  b: 1;
+  c: 2; }
+CSS
+a
+  $a: 1
+  b: $a
+  $a: 2
+  c: $a
+SASS
+  end
+
+  def test_hyphen_underscore_insensitive_variables
+    assert_equal(<<CSS, render(<<SASS))
+d {
+  e: 13;
+  f: foobar; }
+CSS
+$var-hyphen: 12
+$var_under: foo
+
+$var_hyphen: 1 + $var_hyphen
+$var-under: $var-under + bar
+
+d
+  e: $var-hyphen
+  f: $var_under
+SASS
+  end
+
+  def test_css_identifier_variable
+    assert_equal(<<CSS, render(<<SASS))
+a {
+  b: 12; }
+CSS
+$\\{foo\\(12\\): 12
+
+a
+  b: $\\{foo\\(12\\)
+SASS
+  end
+
+  def test_important
+    assert_equal(<<CSS, render(<<SASS))
+a {
+  b: 12px !important; }
+CSS
+$foo: 12px
+a
+  b: $foo !important
+SASS
+  end
+
+  def test_argument_error
+    assert_raises(Sass::SyntaxError) { render("a\n  b: hsl(1)") }
+  end
+
+  def test_comments_at_the_top_of_a_document
+    render(<<SASS)
+//
+  This is a comment that
+  continues to the second line.
+foo
+  bar: baz
+SASS
+  end
+
+  def test_loud_comments_containing_a_comment_close
+    actual_css = render(<<SASS)
+/*
+  This is a comment that
+  continues to the second line. */
+foo
+  bar: baz
+SASS
+assert_equal(<<CSS, actual_css)
+/* This is a comment that
+ * continues to the second line. */
+foo {
+  bar: baz; }
+CSS
+  end
+
+  def test_loud_comments_with_starred_lines
+    assert_equal(<<CSS, render(<<SASS))
+/* This is a comment that
+ * continues to the second line.
+ * And even to the third! */
+CSS
+/* This is a comment that
+ * continues to the second line.
+ * And even to the third!
+SASS
+  end
+
+  def test_loud_comments_with_no_space_after_starred_lines
+    assert_equal(<<CSS, render(<<SASS))
+/*bip bop
+ *beep boop
+ *bap blimp */
+CSS
+/*bip bop
+ *beep boop
+ *bap blimp
+SASS
+  end
+
+  def test_comment_indentation_at_beginning_of_doc
+    assert_equal <<CSS, render(<<SASS)
+/* foo
+ * bar
+ *   baz */
+foo {
+  a: b; }
+CSS
+/* foo
+   bar
+     baz
+foo
+  a: b
+SASS
+  end
+
+  def test_unusual_comment_indentation
+    assert_equal <<CSS, render(<<SASS)
+foo {
+  /* foo
+   * bar
+   *   baz */ }
+CSS
+foo
+  /* foo
+     bar
+       baz
+SASS
+  end
+
+  def test_loud_comment_with_close
+    assert_equal <<CSS, render(<<SASS)
+foo {
+  /* foo
+   * bar */ }
+CSS
+foo
+  /* foo
+     bar */
+SASS
+  end
+
+  def test_loud_comment_with_separate_line_close
+    assert_equal <<CSS, render(<<SASS)
+foo {
+  /* foo
+   * bar
+   */ }
+CSS
+foo
+  /* foo
+   * bar
+   */
+SASS
+  end
+
+  def test_loud_comment_in_compressed_mode
+    assert_equal <<CSS, render(<<SASS, :style => :compressed)
+foo{color:blue;/*! foo
+ * bar
+ */}
+CSS
+foo
+  color: blue
+  /*! foo
+   * bar
+   */
+SASS
+  end
+
+  def test_loud_comment_is_evaluated
+    assert_equal <<CSS, render(<<SASS)
+/*! Hue: 327.21649deg */
+CSS
+/*! Hue: \#{hue(#f836a0)}
+SASS
+  end
+
+  def test_attribute_selector_with_spaces
+    assert_equal(<<CSS, render(<<SASS))
+a b[foo=bar] {
+  c: d; }
+CSS
+a
+  b[foo = bar]
+    c: d
+SASS
+  end
+
+  def test_quoted_colon
+    assert_equal(<<CSS, render(<<SASS))
+a b[foo="bar: baz"] {
+  c: d; }
+CSS
+a
+  b[foo="bar: baz"]
+    c: d
+SASS
+  end
+
+  def test_quoted_comma
+    assert_equal(<<CSS, render(<<SASS))
+a b[foo="bar, baz"] {
+  c: d; }
+CSS
+a
+  b[foo="bar, baz"]
+    c: d
+SASS
+  end
+
+  def test_quoted_ampersand
+    assert_equal(<<CSS, render(<<SASS))
+a b[foo="bar & baz"] {
+  c: d; }
+CSS
+a
+  b[foo="bar & baz"]
+    c: d
+SASS
+  end
+
+  def test_empty_selector_warning
+    assert_warning(<<END) {render("foo bar")}
+WARNING on line 1 of test_empty_selector_warning_inline.sass:
+This selector doesn't have any properties and will not be rendered.
+END
+  end
+
+  def test_nonprinting_empty_property
+    assert_equal(<<CSS, render(<<SASS))
+a {
+  c: "";
+  e: f; }
+CSS
+$null-value: null
+$empty-string: ''
+$empty-list: (null)
+a
+  b: $null-value
+  c: $empty-string
+  d: $empty-list
+  e: f
+
+g
+  h: null
+SASS
+  end
+
+  def test_root_level_pseudo_class_with_new_properties
+    assert_equal(<<CSS, render(<<SASS, :property_syntax => :new))
+:focus {
+  outline: 0; }
+CSS
+:focus
+  outline: 0
+SASS
+  end
+
+  def test_pseudo_class_with_new_properties
+    assert_equal(<<CSS, render(<<SASS, :property_syntax => :new))
+p :focus {
+  outline: 0; }
+CSS
+p
+  :focus
+    outline: 0
+SASS
+  end
+
+  def test_nil_option
+    assert_equal(<<CSS, render(<<SASS, :format => nil))
+foo {
+  a: b; }
+CSS
+foo
+  a: b
+SASS
+  end
+
+  def test_interpolation_in_raw_functions
+    assert_equal(<<CSS, render(<<SASS))
+foo {
+  filter: progid:Microsoft.foo.bar.Baz(flip=foobar, bang=#00ff00cc); }
+CSS
+foo
+  filter: progid:Microsoft.foo.bar.Baz(flip=\#{foo + bar}, bang=#00ff00cc)
+SASS
+  end
+
+  # SassScript string behavior
+
+  def test_plus_preserves_quotedness
+    assert_equal(<<CSS, render(<<SASS))
+foo {
+  a: "foo1";
+  b: "1foo";
+  c: foo1;
+  d: 1foo;
+  e: "foobar";
+  f: foobar; }
+CSS
+foo
+  a: "foo" + 1
+  b: 1 + "foo"
+  c: foo + 1
+  d: 1 + foo
+  e: "foo" + bar
+  f: foo + "bar"
+SASS
+  end
+
+  def test_colon_properties_preserve_quotedness
+    assert_equal(<<CSS, render(<<SASS))
+foo {
+  a: "foo";
+  b: bar;
+  c: "foo" bar;
+  d: foo, "bar"; }
+CSS
+foo
+  a: "foo"
+  b: bar
+  c: "foo" bar
+  d: foo, "bar"
+SASS
+  end
+
+  def test_colon_variables_preserve_quotedness
+    assert_equal(<<CSS, render(<<SASS))
+foo {
+  a: "foo";
+  b: bar; }
+CSS
+$a: "foo"
+$b: bar
+
+foo
+  a: $a
+  b: $b
+SASS
+  end
+
+  def test_colon_args_preserve_quotedness
+    assert_equal(<<CSS, render(<<SASS))
+foo {
+  a: "foo";
+  b: bar;
+  c: "foo" bar;
+  d: foo, "bar"; }
+CSS
+=foo($a: "foo", $b: bar, $c: "foo" bar, $d: (foo, "bar"))
+  foo
+    a: $a
+    b: $b
+    c: $c
+    d: $d
+
++foo
+SASS
+  end
+
+  def test_interpolation_unquotes_strings
+    assert_equal(<<CSS, render(<<SASS))
+.foo-bar {
+  a: b; }
+CSS
+.foo-\#{"bar"}
+  a: b
+SASS
+
+    assert_equal(<<CSS, render(<<SASS))
+.foo {
+  a: b c; }
+CSS
+.foo
+  a: b \#{"c"}
+SASS
+  end
+
+  def test_interpolation_unquotes_strings_in_vars
+    assert_equal(<<CSS, render(<<SASS))
+.foo-bar {
+  a: b; }
+CSS
+$var: "bar"
+
+.foo-\#{$var}
+  a: b
+SASS
+  end
+
+  def test_interpolation_deep_unquotes_strings
+    assert_equal(<<CSS, render(<<SASS))
+.foo {
+  a: bar baz; }
+CSS
+.foo
+  a: \#{"bar" "baz"}
+SASS
+  end
+
+  def test_warn_directive
+  expected_warning = <<EXPECTATION
+WARNING: this is a warning
+         on line 4 of test_warn_directive_inline.sass
+
+WARNING: this is a mixin warning
+         on line 2 of test_warn_directive_inline.sass, in `foo'
+         from line 7 of test_warn_directive_inline.sass
+EXPECTATION
+    assert_warning expected_warning do
+      assert_equal <<CSS, render(<<SASS)
+bar {
+  c: d; }
+CSS
+=foo
+  @warn "this is a mixin warning"
+
+ warn "this is a warning"
+bar
+  c: d
+  +foo
+SASS
+    end
+  end
+
+  def test_warn_directive_when_quiet
+    assert_warning "" do
+      assert_equal <<CSS, render(<<SASS, :quiet => true)
+CSS
+ warn "this is a warning"
+SASS
+    end
+  end
+
+  def test_warn_with_imports
+    expected_warning = <<WARN
+WARNING: In the main file
+         on line 1 of #{File.dirname(__FILE__)}/templates/warn.sass
+
+WARNING: Imported
+         on line 1 of #{File.dirname(__FILE__)}/templates/warn_imported.sass
+         from line 2 of #{File.dirname(__FILE__)}/templates/warn.sass
+
+WARNING: In an imported mixin
+         on line 4 of #{File.dirname(__FILE__)}/templates/warn_imported.sass, in `emits-a-warning'
+         from line 3 of #{File.dirname(__FILE__)}/templates/warn.sass
+WARN
+    assert_warning expected_warning do
+      renders_correctly "warn", :style => :compact, :load_paths => [File.dirname(__FILE__) + "/templates"]
+    end
+  end
+
+  def test_media_bubbling
+    assert_equal <<CSS, render(<<SASS)
+.foo {
+  a: b; }
+  @media bar {
+    .foo {
+      c: d; } }
+  .foo .baz {
+    e: f; }
+    @media bip {
+      .foo .baz {
+        g: h; } }
+
+.other {
+  i: j; }
+CSS
+.foo
+  a: b
+  @media bar
+    c: d
+  .baz
+    e: f
+    @media bip
+      g: h
+
+.other
+  i: j
+SASS
+
+    assert_equal <<CSS, render(<<SASS, :style => :compact)
+.foo { a: b; }
+ media bar { .foo { c: d; } }
+.foo .baz { e: f; }
+ media bip { .foo .baz { g: h; } }
+
+.other { i: j; }
+CSS
+.foo
+  a: b
+  @media bar
+    c: d
+  .baz
+    e: f
+    @media bip
+      g: h
+
+.other
+  i: j
+SASS
+
+    assert_equal <<CSS, render(<<SASS, :style => :expanded)
+.foo {
+  a: b;
+}
+ media bar {
+  .foo {
+    c: d;
+  }
+}
+.foo .baz {
+  e: f;
+}
+ media bip {
+  .foo .baz {
+    g: h;
+  }
+}
+
+.other {
+  i: j;
+}
+CSS
+.foo
+  a: b
+  @media bar
+    c: d
+  .baz
+    e: f
+    @media bip
+      g: h
+
+.other
+  i: j
+SASS
+  end
+
+  def test_double_media_bubbling
+    assert_equal <<CSS, render(<<SASS)
+ media bar and (a: b) {
+  .foo {
+    c: d; } }
+CSS
+ media bar
+  @media (a: b)
+    .foo
+      c: d
+SASS
+
+    assert_equal <<CSS, render(<<SASS)
+ media bar {
+  .foo {
+    a: b; } }
+  @media bar and (a: b) {
+    .foo {
+      c: d; } }
+CSS
+.foo
+  @media bar
+    a: b
+    @media (a: b)
+      c: d
+SASS
+  end
+
+  def test_double_media_bubbling_with_commas
+    assert_equal <<CSS, render(<<SASS)
+ media (a: b) and (e: f), (c: d) and (e: f), (a: b) and (g: h), (c: d) and (g: h) {
+  .foo {
+    c: d; } }
+CSS
+ media (a: b), (c: d)
+  @media (e: f), (g: h)
+    .foo
+      c: d
+SASS
+  end
+
+  def test_double_media_bubbling_with_surrounding_rules
+    assert_equal <<CSS, render(<<SASS)
+ media (min-width: 0) {
+  a {
+    a: a; }
+
+  b {
+    before: b;
+    after: b; } }
+  @media (min-width: 0) and (max-width: 5000px) {
+    b {
+      x: x; } }
+
+ media (min-width: 0) {
+  c {
+    c: c; } }
+CSS
+ media (min-width: 0)
+  a
+    a: a
+  b
+    before: b
+    @media (max-width: 5000px)
+      x: x
+    after: b
+  c
+    c: c
+SASS
+  end
+
+  def test_rule_media_rule_bubbling
+    assert_equal <<CSS, render(<<SASS)
+ media bar {
+  .foo {
+    a: b;
+    e: f; }
+    .foo .baz {
+      c: d; } }
+CSS
+.foo
+  @media bar
+    a: b
+    .baz
+      c: d
+    e: f
+SASS
+  end
+
+  def test_nested_media_around_properties
+    assert_equal <<CSS, render(<<SASS)
+.outside {
+  color: red;
+  background: blue; }
+  @media print {
+    .outside {
+      color: black; } }
+  @media print and (a: b) {
+    .outside .inside {
+      border: 1px solid black; } }
+
+  .outside .middle {
+    display: block; }
+CSS
+.outside
+  color: red
+  @media print
+    color: black
+    .inside
+      @media (a: b)
+        border: 1px solid black
+  background: blue
+  .middle
+    display: block
+SASS
+  end
+
+  def test_media_with_parent_references
+    sass_str = <<SASS
+.outside
+  @media print
+    &.inside
+      border: 1px solid black
+SASS
+    css_str = <<CSS
+ media print {
+  .outside.inside {
+    border: 1px solid black; } }
+CSS
+    assert_equal css_str, render(sass_str)
+  end
+
+  def test_eliminated_media_bubbling
+    assert_equal <<CSS, render(<<SASS)
+ media screen {
+  a: b; }
+CSS
+ media screen
+  a: b
+  @media print
+    c: d
+SASS
+
+    assert_equal <<CSS, render(<<SASS)
+ media not print {
+  a: b; }
+CSS
+ media not print
+  a: b
+  @media print
+    c: d
+SASS
+
+    assert_equal <<CSS, render(<<SASS)
+ media not print {
+  a: b; }
+CSS
+ media not print
+  a: b
+  @media not screen
+    c: d
+SASS
+  end
+
+  def test_non_eliminated_media_bubbling
+    assert_equal <<CSS, render(<<SASS)
+ media screen {
+  a: b; }
+ media screen and (a: b) {
+  c: d; }
+CSS
+ media screen
+  a: b
+  @media screen and (a: b)
+    c: d
+SASS
+
+    assert_equal <<CSS, render(<<SASS)
+ media not print {
+  a: b; }
+ media screen {
+  c: d; }
+CSS
+ media not print
+  a: b
+  @media screen
+    c: d
+SASS
+
+    assert_equal <<CSS, render(<<SASS)
+ media only screen {
+  a: b; }
+ media only screen and (a: b) {
+  c: d; }
+CSS
+ media only screen
+  a: b
+  @media screen and (a: b)
+    c: d
+SASS
+  end
+
+  def test_directive_interpolation
+    assert_equal <<CSS, render(<<SASS)
+ foo bar12 qux {
+  a: b; }
+CSS
+$baz: 12
+ foo bar\#{$baz} qux
+  a: b
+SASS
+  end
+
+  def test_media_interpolation
+    assert_equal <<CSS, render(<<SASS)
+ media bar12 {
+  a: b; }
+CSS
+$baz: 12
+ media bar\#{$baz}
+  a: b
+SASS
+  end
+
+  def test_variables_in_media
+    assert_equal <<CSS, render(<<SASS)
+ media screen and (-webkit-min-device-pixel-ratio-foo: 25), only print {
+  a: b; }
+CSS
+$media1: screen
+$media2: print
+$var: -webkit-min-device-pixel-ratio
+$val: 20
+ media \#{$media1} and ($var + "-foo": $val + 5), only \#{$media2}
+  a: b
+SASS
+  end
+
+  def test_at_root
+    assert_equal <<CSS, render(<<SASS)
+.bar {
+  a: b; }
+CSS
+.foo
+  @at-root
+    .bar
+      a: b
+SASS
+  end
+
+  def test_at_root_with_selector
+    assert_equal <<CSS, render(<<SASS)
+.bar {
+  a: b; }
+CSS
+.foo
+  @at-root .bar
+    a: b
+SASS
+  end
+
+  def test_at_root_with_query
+    assert_equal <<CSS, render(<<SASS)
+.foo .bar {
+  a: b; }
+CSS
+.foo
+  @media screen
+    @at-root (without: media)
+      .bar
+        a: b
+SASS
+  end
+
+  def test_variable_assignment_with_global
+    assert_no_warning {assert_equal(<<CSS, render(<<SASS))}
+.foo {
+  a: x; }
+
+.bar {
+  b: x; }
+CSS
+$var: 1
+
+.foo
+  $var: x !global
+  a: $var
+
+.bar
+  b: $var
+SASS
+  end
+
+  # Regression tests
+
+  def test_list_separator_with_arg_list
+    assert_equal(<<CSS, render(<<SASS))
+.test {
+  separator: comma; }
+CSS
+ mixin arglist-test($args...)
+  separator: list-separator($args)
+
+.test
+  @include arglist-test(this, is, comma, separated)
+SASS
+  end
+
+  def test_parent_mixin_in_content_nested
+    assert_equal(<<CSS, render(<<SASS))
+a {
+  b: c; }
+CSS
+=foo
+  @content
+
+=bar
+  +foo
+    +foo
+      a
+        b: c
+
++bar
+SASS
+  end
+
+  def test_supports_bubbles
+    assert_equal <<CSS, render(<<SASS)
+parent {
+  background: orange; }
+  @supports (perspective: 10px) or (-moz-perspective: 10px) {
+    parent child {
+      background: blue; } }
+CSS
+parent
+  background: orange
+  @supports (perspective: 10px) or (-moz-perspective: 10px)
+    child
+      background: blue
+SASS
+  end
+
+  def test_line_numbers_with_dos_line_endings
+    assert_equal <<CSS, render(<<SASS, :line_comments => true)
+/* line 5, test_line_numbers_with_dos_line_endings_inline.sass */
+.foo {
+  a: b; }
+CSS
+\r
+\r
+\r
+\r
+.foo
+  a: b
+SASS
+  end
+
+  def test_variable_in_media_in_mixin
+    assert_equal <<CSS, render(<<SASS)
+ media screen and (min-width: 10px) {
+  body {
+    background: red; } }
+ media screen and (min-width: 20px) {
+  body {
+    background: blue; } }
+CSS
+ mixin respond-to($width)
+  @media screen and (min-width: $width)
+    @content
+
+body
+  @include respond-to(10px)
+    background: red
+  @include respond-to(20px)
+    background: blue
+SASS
+  end
+
+  def test_interpolated_comment_in_mixin
+    assert_equal <<CSS, render(<<SASS)
+/*! color: red */
+.foo {
+  color: red; }
+
+/*! color: blue */
+.foo {
+  color: blue; }
+
+/*! color: green */
+.foo {
+  color: green; }
+CSS
+=foo($var)
+  /*! color: \#{$var}
+  .foo
+    color: $var
+
++foo(red)
++foo(blue)
++foo(green)
+SASS
+  end
+
+  def test_parens_in_mixins
+    assert_equal(<<CSS, render(<<SASS))
+.foo {
+  color: #01ff7f;
+  background-color: #000102; }
+CSS
+=foo($c1, $c2: rgb(0, 1, 2))
+  color: $c1
+  background-color: $c2
+
+.foo
+  +foo(rgb(1,255,127))
+SASS
+  end
+
+  def test_comment_beneath_prop
+    assert_equal(<<RESULT, render(<<SOURCE))
+.box {
+  border-style: solid; }
+RESULT
+.box
+  :border
+    //:color black
+    :style solid
+SOURCE
+
+    assert_equal(<<RESULT, render(<<SOURCE))
+.box {
+  /* :color black */
+  border-style: solid; }
+RESULT
+.box
+  :border
+    /* :color black
+    :style solid
+SOURCE
+
+    assert_equal(<<RESULT, render(<<SOURCE, :style => :compressed))
+.box{border-style:solid}
+RESULT
+.box
+  :border
+    /*:color black
+    :style solid
+SOURCE
+  end
+
+  def test_compressed_comment_beneath_directive
+    assert_equal(<<RESULT, render(<<SOURCE, :style => :compressed))
+ foo{a:b}
+RESULT
+ foo
+  a: b
+  /*b: c
+SOURCE
+  end
+
+  def test_comment_with_crazy_indentation
+    assert_equal(<<CSS, render(<<SASS))
+/* This is a loud comment:
+ *          Where the indentation is wonky. */
+.comment {
+  width: 1px; }
+CSS
+/*
+  This is a loud comment:
+           Where the indentation is wonky.
+//
+  This is a silent comment:
+           Where the indentation is wonky.
+.comment
+  width: 1px
+SASS
+  end
+
+  def test_plus_with_space
+    assert_equal(<<CSS, render(<<SASS))
+a + b {
+  color: green; }
+CSS
+a
+  + b
+    color: green
+SASS
+  end
+
+  def test_empty_line_comment
+    assert_equal(<<CSS, render(<<SASS))
+/* Foo
+ *
+ * Bar */
+CSS
+/*
+  Foo
+
+  Bar
+SASS
+  end
+
+  def test_empty_comment
+    assert_equal(<<CSS, render(<<SASS))
+/* */
+a {
+  /* */
+  b: c; }
+CSS
+/*
+a
+  /*
+  b: c
+SASS
+  end
+
+  def test_options_available_in_environment
+    assert_equal(<<CSS, render(<<SASS))
+a {
+  b: nested; }
+CSS
+a
+  b: option("style")
+SASS
+  end
+
+  def test_mixin_no_arg_error
+    assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "($bar,": expected variable (e.g. $foo), was 
")"') do
+      render(<<SASS)
+=foo($bar,)
+  bip: bap
+SASS
+    end
+  end
+
+  def test_import_with_commas_in_url
+    assert_equal <<CSS, render(<<SASS)
+ import url(foo.css?bar,baz);
+CSS
+ import url(foo.css?bar,baz)
+SASS
+  end
+
+  def test_silent_comment_in_prop_val_after_important
+    assert_equal(<<CSS, render(<<SASS))
+.advanced {
+  display: none !important; }
+CSS
+.advanced
+  display: none !important // yeah, yeah. it's not really a style anyway.
+SASS
+  end
+
+  def test_mixin_with_keyword_args
+    assert_equal <<CSS, render(<<SASS)
+.mixed {
+  required: foo;
+  arg1: default-val1;
+  arg2: non-default-val2; }
+CSS
+=a-mixin($required, $arg1: default-val1, $arg2: default-val2)
+  required: $required
+  arg1: $arg1
+  arg2: $arg2
+.mixed
+  +a-mixin(foo, $arg2: non-default-val2)
+SASS
+  end
+
+  def test_mixin_with_keyword_arg_variable_value
+    assert_equal <<CSS, render(<<SASS)
+.mixed {
+  required: foo;
+  arg1: default-val1;
+  arg2: a-value; }
+CSS
+=a-mixin($required, $arg1: default-val1, $arg2: default-val2)
+  required: $required
+  arg1: $arg1
+  arg2: $arg2
+.mixed
+  $a-value: a-value
+  +a-mixin(foo, $arg2: $a-value)
+SASS
+  end
+
+  def test_mixin_keyword_args_handle_variable_underscore_dash_equivalence
+    assert_equal <<CSS, render(<<SASS)
+.mixed {
+  required: foo;
+  arg1: non-default-val1;
+  arg2: non-default-val2; }
+CSS
+=a-mixin($required, $arg-1: default-val1, $arg_2: default-val2)
+  required: $required
+  arg1: $arg_1
+  arg2: $arg-2
+.mixed
+  +a-mixin(foo, $arg-2: non-default-val2, $arg_1: non-default-val1)
+SASS
+  end
+
+  def test_passing_required_args_as_a_keyword_arg
+    assert_equal <<CSS, render(<<SASS)
+.mixed {
+  required: foo;
+  arg1: default-val1;
+  arg2: default-val2; }
+CSS
+=a-mixin($required, $arg1: default-val1, $arg2: default-val2)
+  required: $required
+  arg1: $arg1
+  arg2: $arg2
+.mixed
+  +a-mixin($required: foo)
+SASS
+  end
+
+  def test_passing_all_as_keyword_args_in_opposite_order
+    assert_equal <<CSS, render(<<SASS)
+.mixed {
+  required: foo;
+  arg1: non-default-val1;
+  arg2: non-default-val2; }
+CSS
+=a-mixin($required, $arg1: default-val1, $arg2: default-val2)
+  required: $required
+  arg1: $arg1
+  arg2: $arg2
+.mixed
+  +a-mixin($arg2: non-default-val2, $arg1: non-default-val1, $required: foo)
+SASS
+  end
+
+  def test_function_output_with_comma
+    assert_equal <<CSS, render(<<SASS)
+foo {
+  a: b(c), d(e); }
+CSS
+foo
+  a: b(c), d(e)
+SASS
+  end
+
+  def test_interpolation_with_comma
+    assert_equal <<CSS, render(<<SASS)
+foo {
+  a: foo, bar; }
+CSS
+$foo: foo
+foo
+  a: \#{$foo}, bar
+SASS
+  end
+
+  def test_string_interpolation_with_comma
+    assert_equal <<CSS, render(<<SASS)
+foo {
+  a: "bip foo bap", bar; }
+CSS
+$foo: foo
+foo
+  a: "bip \#{$foo} bap", bar
+SASS
+  end
+
+  def test_unknown_directive
+    assert_equal <<CSS, render(<<SASS)
+ baz {
+  c: d; }
+CSS
+ baz
+  c: d
+SASS
+  end
+
+  def test_loud_comment_interpolations_can_be_escaped
+    assert_equal <<CSS, render(<<SASS)
+/* \#{foo} */
+CSS
+/* \\\#{foo}
+SASS
+    assert_equal <<CSS, render(<<SASS)
+/*! \#{foo} */
+CSS
+/*! \\\#{foo}
+SASS
+  end
+
+  def test_selector_compression
+    assert_equal <<CSS, render(<<SASS, :style => :compressed)
+a>b,c+d,:-moz-any(e,f,g){h:i}
+CSS
+a > b, c + d, :-moz-any(e, f, g)
+  h: i
+SASS
+  end
+
+  def test_comment_like_selector
+    assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "/": expected identifier, was " foo"') 
{render(<<SASS)}
+/ foo
+  a: b
+SASS
+  end
+
+  def test_nested_empty_directive
+    assert_equal <<CSS, render(<<SASS)
+ media screen {
+  .foo {
+    a: b; }
+
+  @unknown-directive; }
+CSS
+ media screen
+  .foo
+    a: b
+
+  @unknown-directive
+SASS
+  end
+
+  def test_original_filename_set
+    importer = MockImporter.new
+    importer.add_import("imported", "div{color:red}")
+
+    original_filename = filename_for_test
+    engine = Sass::Engine.new('@import "imported"; div{color:blue}',
+      :filename => original_filename, :load_paths => [importer], :syntax => :scss, :importer => importer)
+    engine.render
+
+    assert_equal original_filename, engine.options[:original_filename]
+    assert_equal original_filename, importer.engine("imported").options[:original_filename]
+  end
+
+  def test_changing_precision
+    old_precision = Sass::Script::Value::Number.precision
+    begin
+      Sass::Script::Value::Number.precision = 8
+      assert_equal <<CSS, render(<<SASS)
+div {
+  maximum: 1.00000001;
+  too-much: 1.0; }
+CSS
+div
+  maximum : 1.00000001
+  too-much: 1.000000001
+SASS
+    ensure
+      Sass::Script::Value::Number.precision = old_precision
+    end
+  end
+
+  def test_content
+    assert_equal <<CSS, render(<<SASS)
+.children {
+  background-color: red;
+  color: blue;
+  border-color: red; }
+CSS
+$color: blue
+=context($class, $color: red)
+  .\#{$class}
+    background-color: $color
+    @content
+    border-color: $color
++context(children)
+  color: $color
+SASS
+  end
+
+  def test_selector_in_content
+    assert_equal <<CSS, render(<<SASS)
+.parent {
+  background-color: red;
+  border-color: red; }
+  .parent .children {
+    color: blue; }
+CSS
+$color: blue
+=context($class, $color: red)
+  .\#{$class}
+    background-color: $color
+    @content
+    border-color: $color
++context(parent)
+  .children
+    color: $color
+SASS
+  end
+
+  def test_using_parent_mixin_in_content
+    assert_equal <<CSS, render(<<SASS)
+.parent {
+  before-color: red;
+  after-color: red; }
+  .parent .sibling {
+    before-color: yellow;
+    after-color: yellow; }
+    .parent .sibling .child {
+      before-color: green;
+      color: blue;
+      after-color: green; }
+CSS
+$color: blue
+=context($class, $color: red)
+  .\#{$class}
+    before-color: $color
+    @content
+    after-color: $color
++context(parent)
+  +context(sibling, $color: yellow)
+    +context(child, $color: green)
+      color: $color
+SASS
+  end
+
+  def test_content_more_than_once
+    assert_equal <<CSS, render(<<SASS)
+.once {
+  color: blue; }
+
+.twice {
+  color: blue; }
+CSS
+$color: blue
+=context($class, $color: red)
+  .once
+    @content
+  .twice
+    @content
++context(parent)
+  color: $color
+SASS
+  end
+
+  def test_content_with_variable
+    assert_equal <<CSS, render(<<SASS)
+.foo {
+  a: 1px; }
+CSS
+=foo
+  .foo
+    @content
++foo
+  $a: 1px
+  a: $a
+SASS
+  end
+
+  def test_nested_content_blocks
+    assert_equal <<CSS, render(<<SASS)
+.foo {
+  a: foo; }
+  .foo .bar {
+    a: bar; }
+    .foo .bar .baz {
+      a: baz; }
+      .foo .bar .baz .outside {
+        a: outside;
+        color: red; }
+CSS
+$a: outside
+=baz($a: baz)
+  .baz
+    a: $a
+    @content
+=bar($a: bar)
+  .bar
+    a: $a
+    +baz
+      @content
+=foo($a: foo)
+  .foo
+    a: $a
+    +bar
+      @content
++foo
+  .outside
+    a: $a
+    color: red
+SASS
+  end
+
+  def test_content_not_seen_through_mixin
+    assert_equal <<CSS, render(<<SASS)
+a foo {
+  mixin: foo;
+  a: b; }
+  a foo bar {
+    mixin: bar; }
+CSS
+=foo
+  foo
+    mixin: foo
+    @content
+    +bar
+=bar
+  bar
+    mixin: bar
+    @content
+a
+  +foo
+    a: b
+SASS
+  end
+
+  def test_content_backtrace_for_perform
+    render(<<SASS)
+=foo
+  @content
+
+a
+  +foo
+    b: 1em + 2px
+SASS
+    assert(false, "Expected exception")
+  rescue Sass::SyntaxError => e
+    assert_equal([
+        {:mixin => '@content', :line => 6, :filename => 'test_content_backtrace_for_perform_inline.sass'},
+        {:mixin => 'foo', :line => 2, :filename => 'test_content_backtrace_for_perform_inline.sass'},
+        {:line => 5, :filename => 'test_content_backtrace_for_perform_inline.sass'},
+      ], e.sass_backtrace)
+  end
+
+  def test_content_backtrace_for_cssize
+    render(<<SASS)
+=foo
+  @content
+
+a
+  +foo
+    @extend foo bar baz
+SASS
+    assert(false, "Expected exception")
+  rescue Sass::SyntaxError => e
+    assert_equal([
+        {:mixin => '@content', :line => 6, :filename => 'test_content_backtrace_for_cssize_inline.sass'},
+        {:mixin => 'foo', :line => 2, :filename => 'test_content_backtrace_for_cssize_inline.sass'},
+        {:line => 5, :filename => 'test_content_backtrace_for_cssize_inline.sass'},
+      ], e.sass_backtrace)
+  end
+
+  def test_mixin_with_args_and_varargs_passed_no_var_args
+    assert_equal <<CSS, render(<<SASS, :syntax => :scss)
+.foo {
+  a: 1;
+  b: 2;
+  c: 3; }
+CSS
+ mixin three-or-more-args($a, $b, $c, $rest...) {
+  a: $a;
+  b: $b;
+  c: $c;
+}
+
+.foo {
+  @include three-or-more-args($a: 1, $b: 2, $c: 3);
+}
+SASS
+
+  end
+
+  def test_debug_inspects_sass_objects
+    assert_warning(<<END) {render("@debug (a: 1, b: 2)")}
+test_debug_inspects_sass_objects_inline.sass:1 DEBUG: (a: 1, b: 2)
+END
+    assert_warning(<<END) {render("$map: (a: 1, b: 2); @debug $map", :syntax => :scss)}
+test_debug_inspects_sass_objects_inline.scss:1 DEBUG: (a: 1, b: 2)
+END
+  end
+
+  def test_error_throws_sass_objects
+    assert_raise_message(Sass::SyntaxError, "(a: 1, b: 2)") {render("@error (a: 1, b: 2)")}
+    assert_raise_message(Sass::SyntaxError, "(a: 1, b: 2)") do
+      render("$map: (a: 1, b: 2); @error $map", :syntax => :scss)
+    end
+  end
+
+  def test_default_arg_before_splat
+    assert_equal <<CSS, render(<<SASS, :syntax => :scss)
+.foo-positional {
+  a: 1;
+  b: 2;
+  positional-arguments: 3, 4;
+  keyword-arguments: (); }
+
+.foo-keywords {
+  a: true;
+  positional-arguments: ();
+  keyword-arguments: (c: c, d: d); }
+CSS
+ mixin foo($a: true, $b: null, $arguments...) {
+  a: $a;
+  b: $b;
+  positional-arguments: inspect($arguments);
+  keyword-arguments: inspect(keywords($arguments));
+}
+.foo-positional {
+  @include foo(1, 2, 3, 4);
+}
+.foo-keywords {
+  @include foo($c: c, $d: d);
+}
+SASS
+  end
+
+  def test_keyframes
+    assert_equal <<CSS, render(<<SASS)
+ keyframes identifier {
+  0% {
+    top: 0;
+    left: 0; }
+  30% {
+    top: 50px; }
+  68%, 72% {
+    left: 50px; }
+  100% {
+    top: 100px;
+    left: 100%; } }
+CSS
+ keyframes identifier
+  0%
+    top: 0
+    left: 0
+  \#{"30%"}
+    top: 50px
+  68%, 72%
+    left: 50px
+  100%
+    top: 100px
+    left: 100%
+SASS
+  end
+
+  def test_prefixed_keyframes
+    assert_equal <<CSS, render(<<SASS)
+ -moz-keyframes identifier {
+  0% {
+    top: 0;
+    left: 0; }
+  30% {
+    top: 50px; }
+  68%, 72% {
+    left: 50px; }
+  100% {
+    top: 100px;
+    left: 100%; } }
+CSS
+ -moz-keyframes identifier
+  0%
+    top: 0
+    left: 0
+  \#{"30%"}
+    top: 50px
+  68%, 72%
+    left: 50px
+  100%
+    top: 100px
+    left: 100%
+SASS
+  end
+
+  def test_uppercase_keyframes
+    assert_equal <<CSS, render(<<SASS)
+ KEYFRAMES identifier {
+  0% {
+    top: 0;
+    left: 0; }
+  30% {
+    top: 50px; }
+  68%, 72% {
+    left: 50px; }
+  100% {
+    top: 100px;
+    left: 100%; } }
+CSS
+ KEYFRAMES identifier
+  0%
+    top: 0
+    left: 0
+  \#{"30%"}
+    top: 50px
+  68%, 72%
+    left: 50px
+  100%
+    top: 100px
+    left: 100%
+SASS
+  end
+
+  private
+
+  def assert_hash_has(hash, expected)
+    expected.each {|k, v| assert_equal(v, hash[k])}
+  end
+
+  def assert_renders_encoded(css, sass)
+    result = render(sass)
+    assert_equal css.encoding, result.encoding
+    assert_equal css, result
+  end
+
+  def render(sass, options = {})
+    munge_filename options
+    options[:importer] ||= MockImporter.new
+    Sass::Engine.new(sass, options).render
+  end
+
+  def renders_correctly(name, options={})
+    sass_file  = load_file(name, "sass")
+    css_file   = load_file(name, "css")
+    options[:filename] ||= filename(name, "sass")
+    options[:syntax] ||= :sass
+    options[:css_filename] ||= filename(name, "css")
+    css_result = Sass::Engine.new(sass_file, options).render
+    assert_equal css_file, css_result
+  end
+
+  def load_file(name, type = "sass")
+    @result = ''
+    File.new(filename(name, type)).each_line { |l| @result += l }
+    @result
+  end
+
+  def filename(name, type)
+    File.dirname(__FILE__) + "/#{type == 'sass' ? 'templates' : 'results'}/#{name}.#{type}"
+  end
+
+  def sassc_path(template)
+    sassc_path = File.join(File.dirname(__FILE__) + "/templates/#{template}.sass")
+    engine = Sass::Engine.new("", :filename => sassc_path,
+      :importer => Sass::Importers::Filesystem.new("."))
+    key = engine.send(:sassc_key)
+    File.join(engine.options[:cache_location], key)
+  end
+end
+ 
diff --git a/backends/css/gems/sass-3.4.9/test/sass/exec_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/exec_test.rb
new file mode 100755
index 0000000..c606b6a
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/exec_test.rb
@@ -0,0 +1,86 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../test_helper'
+require 'sass/util/test'
+require 'tmpdir'
+
+class ExecTest < MiniTest::Test
+  include Sass::Util::Test
+
+  def setup
+    @dir = Dir.mktmpdir
+  end
+
+  def teardown
+    FileUtils.rm_rf(@dir)
+    clean_up_sassc
+  end
+
+  def test_scss_t_expanded
+    src = get_path("src.scss")
+    dest = get_path("dest.css")
+    write(src, ".ruleset { margin: 0 }")
+    assert(exec(*%w[scss --sourcemap=none -t expanded --unix-newlines].push(src, dest)))
+    assert_equal(".ruleset {\n  margin: 0;\n}\n", read(dest))
+  end
+
+  def test_sass_convert_T_sass
+    src = get_path("src.scss")
+    dest = get_path("dest.css")
+    write(src, ".ruleset { margin: 0 }")
+    assert(exec(*%w[sass-convert -T sass --unix-newlines].push(src, dest)))
+    assert_equal(".ruleset\n  margin: 0\n", read(dest))
+  end
+
+  def test_sass_convert_T_sass_in_place
+    src = get_path("src.scss")
+    write(src, ".ruleset { margin: 0 }")
+    assert(exec(*%w[sass-convert -T sass --in-place --unix-newlines].push(src)))
+    assert_equal(".ruleset\n  margin: 0\n", read(src))
+  end
+
+  def test_scss_t_expanded_no_unix_newlines
+    return skip "Can be run on Windows only" unless Sass::Util.windows?
+    src = get_path("src.scss")
+    dest = get_path("dest.css")
+    write(src, ".ruleset { margin: 0 }")
+    assert(exec(*%w[scss -t expanded].push(src, dest)))
+    assert_equal(".ruleset {\r\n  margin: 0;\r\n}\r\n", read(dest))
+  end
+
+  def test_sass_convert_T_sass_no_unix_newlines
+    return skip "Can be run on Windows only" unless Sass::Util.windows?
+    src = get_path("src.scss")
+    dest = get_path("dest.sass")
+    write(src, ".ruleset { margin: 0 }")
+    assert(exec(*%w[sass-convert -T sass].push(src, dest)))
+    assert_equal(".ruleset\r\n  margin: 0\r\n", read(dest))
+  end
+
+  def test_sass_convert_T_sass_in_place_no_unix_newlines
+    return skip "Can be run on Windows only" unless Sass::Util.windows?
+    src = get_path("src.scss")
+    write(src, ".ruleset { margin: 0 }")
+    assert(exec(*%w[sass-convert -T sass --in-place].push(src)))
+    assert_equal(".ruleset\r\n  margin: 0\r\n", read(src))
+  end
+
+  private
+
+  def get_path(name)
+    File.join(@dir, name)
+  end
+
+  def read(file)
+    open(file, 'rb') {|f| f.read}
+  end
+
+  def write(file, content)
+    open(file, 'wb') {|f| f.write(content)}
+  end
+
+  def exec(script, *args)
+    script = File.dirname(__FILE__) + '/../../bin/' + script
+    ruby = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'] + 
RbConfig::CONFIG['EXEEXT'])
+    system(ruby, script, *args)
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/test/sass/extend_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/extend_test.rb
new file mode 100755
index 0000000..48a73d2
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/extend_test.rb
@@ -0,0 +1,1687 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../test_helper'
+
+class ExtendTest < MiniTest::Test
+  def test_basic
+    assert_equal <<CSS, render(<<SCSS)
+.foo, .bar {
+  a: b; }
+CSS
+.foo {a: b}
+.bar { extend .foo}
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+.foo, .bar {
+  a: b; }
+CSS
+.bar { extend .foo}
+.foo {a: b}
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+.foo, .bar {
+  a: b; }
+
+.bar {
+  c: d; }
+CSS
+.foo {a: b}
+.bar {c: d; @extend .foo}
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+.foo, .bar {
+  a: b; }
+
+.bar {
+  c: d; }
+CSS
+.foo {a: b}
+.bar { extend .foo; c: d}
+SCSS
+  end
+
+  def test_indented_syntax
+    assert_equal <<CSS, render(<<SASS, :syntax => :sass)
+.foo, .bar {
+  a: b; }
+CSS
+.foo
+  a: b
+.bar
+  @extend .foo
+SASS
+
+    assert_equal <<CSS, render(<<SASS, :syntax => :sass)
+.foo, .bar {
+  a: b; }
+CSS
+.foo
+  a: b
+.bar
+  @extend \#{".foo"}
+SASS
+  end
+
+  def test_multiple_targets
+    assert_equal <<CSS, render(<<SCSS)
+.foo, .bar {
+  a: b; }
+
+.blip .foo, .blip .bar {
+  c: d; }
+CSS
+.foo {a: b}
+.bar { extend .foo}
+.blip .foo {c: d}
+SCSS
+  end
+
+  def test_multiple_extendees
+    assert_equal <<CSS, render(<<SCSS)
+.foo, .baz {
+  a: b; }
+
+.bar, .baz {
+  c: d; }
+CSS
+.foo {a: b}
+.bar {c: d}
+.baz { extend .foo; @extend .bar}
+SCSS
+  end
+
+  def test_multiple_extends_with_single_extender_and_single_target
+    assert_extends('.foo .bar', '.baz { extend .foo; @extend .bar}',
+      '.foo .bar, .baz .bar, .foo .baz, .baz .baz')
+    assert_extends '.foo.bar', '.baz { extend .foo; @extend .bar}', '.foo.bar, .baz'
+  end
+
+  def test_multiple_extends_with_multiple_extenders_and_single_target
+    assert_equal <<CSS, render(<<SCSS)
+.foo .bar, .baz .bar, .foo .bang, .baz .bang {
+  a: b; }
+CSS
+.foo .bar {a: b}
+.baz { extend .foo}
+.bang { extend .bar}
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+.foo.bar, .bar.baz, .baz.bang, .foo.bang {
+  a: b; }
+CSS
+.foo.bar {a: b}
+.baz { extend .foo}
+.bang { extend .bar}
+SCSS
+  end
+
+  def test_chained_extends
+    assert_equal <<CSS, render(<<SCSS)
+.foo, .bar, .baz, .bip {
+  a: b; }
+CSS
+.foo {a: b}
+.bar { extend .foo}
+.baz { extend .bar}
+.bip { extend .bar}
+SCSS
+  end
+
+  def test_dynamic_extendee
+    assert_extends '.foo', '.bar { extend #{".foo"}}', '.foo, .bar'
+    assert_extends('[baz^="blip12px"]', '.bar { extend [baz^="blip#{12px}"]}',
+      '[baz^="blip12px"], .bar')
+  end
+
+  def test_nested_target
+    assert_extends '.foo .bar', '.baz { extend .bar}', '.foo .bar, .foo .baz'
+  end
+
+  def test_target_with_child
+    assert_extends '.foo .bar', '.baz { extend .foo}', '.foo .bar, .baz .bar'
+  end
+
+  def test_class_unification
+    assert_unification '.foo.bar', '.baz { extend .foo}', '.foo.bar, .bar.baz'
+    assert_unification '.foo.baz', '.baz { extend .foo}', '.baz'
+  end
+
+  def test_id_unification
+    assert_unification '.foo.bar', '#baz { extend .foo}', '.foo.bar, .bar#baz'
+    assert_unification '.foo#baz', '#baz { extend .foo}', '#baz'
+
+    assert_extend_doesnt_match('#bar', '.foo', :failed_to_unify, 2) do
+      render_unification '.foo#baz', '#bar { extend .foo}'
+    end
+  end
+
+  def test_universal_unification_with_simple_target
+    assert_unification '.foo', '* { extend .foo}', '.foo, *'
+    assert_unification '.foo', '*|* { extend .foo}', '.foo, *|*'
+    assert_unification '.foo.bar', '* { extend .foo}', '.bar'
+    assert_unification '.foo.bar', '*|* { extend .foo}', '.bar'
+    assert_unification '.foo.bar', 'ns|* { extend .foo}', '.foo.bar, ns|*.bar'
+  end
+
+  def test_universal_unification_with_namespaceless_universal_target
+    assert_unification '*.foo', '* { extend .foo}', '*'
+    assert_unification '*.foo', '*|* { extend .foo}', '*'
+    assert_unification '*|*.foo', '* { extend .foo}', '*|*.foo, *'
+    assert_unification '*|*.foo', '*|* { extend .foo}', '*|*'
+    assert_unification '*.foo', 'ns|* { extend .foo}', '*.foo, ns|*'
+    assert_unification '*|*.foo', 'ns|* { extend .foo}', '*|*.foo, ns|*'
+  end
+
+  def test_universal_unification_with_namespaced_universal_target
+    assert_unification 'ns|*.foo', '* { extend .foo}', 'ns|*'
+    assert_unification 'ns|*.foo', '*|* { extend .foo}', 'ns|*'
+
+    assert_extend_doesnt_match('ns2|*', '.foo', :failed_to_unify, 2) do
+      render_unification 'ns1|*.foo', 'ns2|* { extend .foo}'
+    end
+
+    assert_unification 'ns|*.foo', 'ns|* { extend .foo}', 'ns|*'
+  end
+
+  def test_universal_unification_with_namespaceless_element_target
+    assert_unification 'a.foo', '* { extend .foo}', 'a'
+    assert_unification 'a.foo', '*|* { extend .foo}', 'a'
+    assert_unification '*|a.foo', '* { extend .foo}', '*|a.foo, a'
+    assert_unification '*|a.foo', '*|* { extend .foo}', '*|a'
+    assert_unification 'a.foo', 'ns|* { extend .foo}', 'a.foo, ns|a'
+    assert_unification '*|a.foo', 'ns|* { extend .foo}', '*|a.foo, ns|a'
+  end
+
+  def test_universal_unification_with_namespaced_element_target
+    assert_unification 'ns|a.foo', '* { extend .foo}', 'ns|a'
+    assert_unification 'ns|a.foo', '*|* { extend .foo}', 'ns|a'
+
+    assert_extend_doesnt_match('ns2|*', '.foo', :failed_to_unify, 2) do
+      render_unification 'ns1|a.foo', 'ns2|* { extend .foo}'
+    end
+
+    assert_unification 'ns|a.foo', 'ns|* { extend .foo}', 'ns|a'
+  end
+
+  def test_element_unification_with_simple_target
+    assert_unification '.foo', 'a { extend .foo}', '.foo, a'
+    assert_unification '.foo.bar', 'a { extend .foo}', '.foo.bar, a.bar'
+    assert_unification '.foo.bar', '*|a { extend .foo}', '.foo.bar, *|a.bar'
+    assert_unification '.foo.bar', 'ns|a { extend .foo}', '.foo.bar, ns|a.bar'
+  end
+
+  def test_element_unification_with_namespaceless_universal_target
+    assert_unification '*.foo', 'a { extend .foo}', '*.foo, a'
+    assert_unification '*.foo', '*|a { extend .foo}', '*.foo, a'
+    assert_unification '*|*.foo', 'a { extend .foo}', '*|*.foo, a'
+    assert_unification '*|*.foo', '*|a { extend .foo}', '*|*.foo, *|a'
+    assert_unification '*.foo', 'ns|a { extend .foo}', '*.foo, ns|a'
+    assert_unification '*|*.foo', 'ns|a { extend .foo}', '*|*.foo, ns|a'
+  end
+
+  def test_element_unification_with_namespaced_universal_target
+    assert_unification 'ns|*.foo', 'a { extend .foo}', 'ns|*.foo, ns|a'
+    assert_unification 'ns|*.foo', '*|a { extend .foo}', 'ns|*.foo, ns|a'
+
+    assert_extend_doesnt_match('ns2|a', '.foo', :failed_to_unify, 2) do
+      render_unification 'ns1|*.foo', 'ns2|a { extend .foo}'
+    end
+
+    assert_unification 'ns|*.foo', 'ns|a { extend .foo}', 'ns|*.foo, ns|a'
+  end
+
+  def test_element_unification_with_namespaceless_element_target
+    assert_unification 'a.foo', 'a { extend .foo}', 'a'
+    assert_unification 'a.foo', '*|a { extend .foo}', 'a'
+    assert_unification '*|a.foo', 'a { extend .foo}', '*|a.foo, a'
+    assert_unification '*|a.foo', '*|a { extend .foo}', '*|a'
+    assert_unification 'a.foo', 'ns|a { extend .foo}', 'a.foo, ns|a'
+    assert_unification '*|a.foo', 'ns|a { extend .foo}', '*|a.foo, ns|a'
+
+    assert_extend_doesnt_match('h1', '.foo', :failed_to_unify, 2) do
+      render_unification 'a.foo', 'h1 { extend .foo}'
+    end
+  end
+
+  def test_element_unification_with_namespaced_element_target
+    assert_unification 'ns|a.foo', 'a { extend .foo}', 'ns|a'
+    assert_unification 'ns|a.foo', '*|a { extend .foo}', 'ns|a'
+
+    assert_extend_doesnt_match('ns2|a', '.foo', :failed_to_unify, 2) do
+      render_unification 'ns1|a.foo', 'ns2|a { extend .foo}'
+    end
+
+    assert_unification 'ns|a.foo', 'ns|a { extend .foo}', 'ns|a'
+  end
+
+  def test_attribute_unification
+    assert_unification '[foo=bar].baz', '[foo=baz] { extend .baz}', '[foo=bar].baz, [foo=bar][foo=baz]'
+    assert_unification '[foo=bar].baz', '[foo^=bar] { extend .baz}', '[foo=bar].baz, [foo=bar][foo^=bar]'
+    assert_unification '[foo=bar].baz', '[foot=bar] { extend .baz}', '[foo=bar].baz, [foo=bar][foot=bar]'
+    assert_unification '[foo=bar].baz', '[ns|foo=bar] { extend .baz}', '[foo=bar].baz, [foo=bar][ns|foo=bar]'
+    assert_unification '%-a [foo=bar].bar', '[foo=bar] { extend .bar}', '-a [foo=bar]'
+  end
+
+  def test_pseudo_unification
+    assert_unification ':foo.baz', ':foo(2n+1) { extend .baz}', ':foo.baz, :foo:foo(2n+1)'
+    assert_unification ':foo.baz', '::foo { extend .baz}', ':foo.baz, :foo::foo'
+
+    assert_extend_doesnt_match('::bar', '.baz', :failed_to_unify, 2) do
+      render_unification '::foo.baz', '::bar { extend .baz}'
+    end
+
+    assert_extend_doesnt_match('::foo(2n+1)', '.baz', :failed_to_unify, 2) do
+      render_unification '::foo.baz', '::foo(2n+1) { extend .baz}'
+    end
+
+    assert_unification '::foo.baz', '::foo { extend .baz}', '::foo'
+    assert_unification '::foo(2n+1).baz', '::foo(2n+1) { extend .baz}', '::foo(2n+1)'
+    assert_unification ':foo.baz', ':bar { extend .baz}', ':foo.baz, :foo:bar'
+    assert_unification '.baz:foo', ':after { extend .baz}', '.baz:foo, :foo:after'
+    assert_unification '.baz:after', ':foo { extend .baz}', '.baz:after, :foo:after'
+    assert_unification ':foo.baz', ':foo { extend .baz}', ':foo'
+  end
+
+  def test_pseudoelement_remains_at_end_of_selector
+    assert_extends '.foo::bar', '.baz { extend .foo}', '.foo::bar, .baz::bar'
+    assert_extends 'a.foo::bar', '.baz { extend .foo}', 'a.foo::bar, a.baz::bar'
+  end
+
+  def test_pseudoclass_remains_at_end_of_selector
+    assert_extends '.foo:bar', '.baz { extend .foo}', '.foo:bar, .baz:bar'
+    assert_extends 'a.foo:bar', '.baz { extend .foo}', 'a.foo:bar, a.baz:bar'
+  end
+
+  def test_not_remains_at_end_of_selector
+    assert_extends '.foo:not(.bar)', '.baz { extend .foo}', '.foo:not(.bar), .baz:not(.bar)'
+  end
+
+  def test_pseudoelement_goes_lefter_than_pseudoclass
+    assert_extends '.foo::bar', '.baz:bang { extend .foo}', '.foo::bar, .baz:bang::bar'
+    assert_extends '.foo:bar', '.baz::bang { extend .foo}', '.foo:bar, .baz:bar::bang'
+  end
+
+  def test_pseudoelement_goes_lefter_than_not
+    assert_extends '.foo::bar', '.baz:not(.bang) { extend .foo}', '.foo::bar, .baz:not(.bang)::bar'
+    assert_extends '.foo:not(.bang)', '.baz::bar { extend .foo}', '.foo:not(.bang), .baz:not(.bang)::bar'
+  end
+
+  def test_negation_unification
+    assert_extends ':not(.foo).baz', ':not(.bar) { extend .baz}', ':not(.foo).baz, :not(.foo):not(.bar)'
+    # Unifying to :not(.foo) here would reduce the specificity of the original selector.
+    assert_extends ':not(.foo).baz', ':not(.foo) { extend .baz}', ':not(.foo).baz, :not(.foo)'
+  end
+
+  def test_prefixed_pseudoclass_unification
+    assert_unification(
+      ':nth-child(2n+1 of .foo).baz',
+      ':nth-child(2n of .foo) { extend .baz}',
+      ':nth-child(2n+1 of .foo).baz, :nth-child(2n+1 of .foo):nth-child(2n of .foo)')
+
+    assert_unification(
+      ':nth-child(2n+1 of .foo).baz',
+      ':nth-child(2n+1 of .bar) { extend .baz}',
+      ':nth-child(2n+1 of .foo).baz, :nth-child(2n+1 of .foo):nth-child(2n+1 of .bar)')
+
+    assert_unification(
+      ':nth-child(2n+1 of .foo).baz',
+      ':nth-child(2n+1 of .foo) { extend .baz}',
+      ':nth-child(2n+1 of .foo)')
+  end
+
+  def test_extend_into_not
+    assert_extends(':not(.foo)', '.x { extend .foo}', ':not(.foo):not(.x)')
+    assert_extends(':not(.foo.bar)', '.x { extend .bar}', ':not(.foo.bar):not(.foo.x)')
+    assert_extends(
+      ':not(.foo.bar, .baz.bar)',
+      '.x { extend .bar}',
+      ':not(.foo.bar, .foo.x, .baz.bar, .baz.x)')
+  end
+
+  def test_extend_into_mergeable_pseudoclasses
+    assert_extends(':matches(.foo)', '.x { extend .foo}', ':matches(.foo, .x)')
+    assert_extends(':matches(.foo.bar)', '.x { extend .bar}', ':matches(.foo.bar, .foo.x)')
+    assert_extends(
+      ':matches(.foo.bar, .baz.bar)',
+      '.x { extend .bar}',
+      ':matches(.foo.bar, .foo.x, .baz.bar, .baz.x)')
+
+    assert_extends(':-moz-any(.foo)', '.x { extend .foo}', ':-moz-any(.foo, .x)')
+    assert_extends(':current(.foo)', '.x { extend .foo}', ':current(.foo, .x)')
+    assert_extends(':has(.foo)', '.x { extend .foo}', ':has(.foo, .x)')
+    assert_extends(':host(.foo)', '.x { extend .foo}', ':host(.foo, .x)')
+    assert_extends(':host-context(.foo)', '.x { extend .foo}', ':host-context(.foo, .x)')
+    assert_extends(':nth-child(n of .foo)', '.x { extend .foo}', ':nth-child(n of .foo, .x)')
+    assert_extends(
+      ':nth-last-child(n of .foo)',
+      '.x { extend .foo}',
+      ':nth-last-child(n of .foo, .x)')
+  end
+
+  def test_complex_extend_into_pseudoclass
+    # Unlike other selectors, we don't allow complex selectors to be
+    # added to `:not` if they weren't there before. At time of
+    # writing, most browsers don't support that and will throw away
+    # the entire selector if it exists.
+    #assert_extends(':not(.bar)', '.x .y { extend .bar}', ':not(.bar)')
+
+    # If the `:not()` already has a complex selector, we won't break
+    # anything by adding a new one.
+    assert_extends(':not(.baz .bar)', '.x .y { extend .bar}',
+      ':not(.baz .bar):not(.baz .x .y):not(.x .baz .y)')
+
+    # If the `:not()` would only contain complex selectors, there's no
+    # harm in letting it continue to exist.
+    assert_extends(':not(%bar)', '.x .y { extend %bar}', ':not(.x .y)')
+
+    assert_extends(':matches(.bar)', '.x .y { extend .bar}', ':matches(.bar, .x .y)')
+    assert_extends(':current(.bar)', '.x .y { extend .bar}', ':current(.bar, .x .y)')
+    assert_extends(':has(.bar)', '.x .y { extend .bar}', ':has(.bar, .x .y)')
+    assert_extends(':host(.bar)', '.x .y { extend .bar}', ':host(.bar, .x .y)')
+    assert_extends(':host-context(.bar)', '.x .y { extend .bar}', ':host-context(.bar, .x .y)')
+    assert_extends(
+      ':-moz-any(.bar)',
+      '.x .y { extend .bar}',
+      ':-moz-any(.bar, .x .y)')
+    assert_extends(
+      ':nth-child(n of .bar)',
+      '.x .y { extend .bar}',
+      ':nth-child(n of .bar, .x .y)')
+    assert_extends(
+      ':nth-last-child(n of .bar)',
+      '.x .y { extend .bar}',
+      ':nth-last-child(n of .bar, .x .y)')
+  end
+
+  def test_extend_over_selector_pseudoclass
+    assert_extends(':not(.foo)', '.x { extend :not(.foo)}', ':not(.foo), .x')
+    assert_extends(
+      ':matches(.foo, .bar)',
+      '.x { extend :matches(.foo, .bar)}',
+      ':matches(.foo, .bar), .x')
+  end
+
+  def test_matches_within_not
+    assert_extends(
+      ':not(.foo, .bar)',
+      ':matches(.x, .y) { extend .foo}',
+      ':not(.foo, .x, .y, .bar)')
+  end
+
+  def test_pseudoclasses_merge
+    assert_extends(':matches(.foo)', ':matches(.bar) { extend .foo}', ':matches(.foo, .bar)')
+    assert_extends(':-moz-any(.foo)', ':-moz-any(.bar) { extend .foo}', ':-moz-any(.foo, .bar)')
+    assert_extends(':current(.foo)', ':current(.bar) { extend .foo}', ':current(.foo, .bar)')
+    assert_extends(
+      ':nth-child(n of .foo)',
+      ':nth-child(n of .bar) { extend .foo}',
+      ':nth-child(n of .foo, .bar)')
+    assert_extends(
+      ':nth-last-child(n of .foo)',
+      ':nth-last-child(n of .bar) { extend .foo}',
+      ':nth-last-child(n of .foo, .bar)')
+  end
+
+  def test_nesting_pseudoclasses_merge
+    assert_extends(':has(.foo)', ':has(.bar) { extend .foo}', ':has(.foo, :has(.bar))')
+    assert_extends(':host(.foo)', ':host(.bar) { extend .foo}', ':host(.foo, :host(.bar))')
+    assert_extends(
+      ':host-context(.foo)',
+      ':host-context(.bar) { extend .foo}',
+      ':host-context(.foo, :host-context(.bar))')
+  end
+
+  def test_not_unifies_with_unique_values
+    assert_unification('foo', ':not(bar) { extend foo}', ':not(bar)')
+    assert_unification('#foo', ':not(#bar) { extend #foo}', ':not(#bar)')
+  end
+
+  def test_not_adds_no_specificity
+    assert_specificity_equals(':not(.foo)', '.foo')
+  end
+
+  def test_matches_has_a_specificity_range
+    # `:matches(.foo, #bar)` has minimum specificity equal to that of `.foo`,
+    # which means `:matches(.foo, #bar) .a` can have less specificity than
+    # `#b.a`. Thus the selector generated by `#b.a` should be preserved.
+    assert_equal <<CSS, render(<<SCSS)
+:matches(.foo, #bar) .a, :matches(.foo, #bar) #b.a {
+  a: b; }
+CSS
+:matches(.foo, #bar) %x {a: b}
+.a { extend %x}
+#b.a { extend %x}
+SCSS
+
+    # `:matches(.foo, #bar)` has maximum specificity equal to that of `#bar`,
+    # which means `:matches(.foo, #bar).b` can have greater specificity than `.a
+    # .b`. Thus the selector generated by `:matches(.foo, #bar).b` should be
+    # preserved.
+    assert_equal <<CSS, render(<<SCSS)
+.a .b, .a .b:matches(.foo, #bar) {
+  a: b; }
+CSS
+.a %x {a: b}
+.b { extend %x}
+.b:matches(.foo, #bar) { extend %x}
+SCSS
+  end
+
+  def test_extend_into_not_and_normal_extend
+    assert_equal <<CSS, render(<<SCSS)
+.x:not(.y):not(.bar), .foo:not(.y):not(.bar) {
+  a: b; }
+CSS
+.x:not(.y) {a: b}
+.foo { extend .x}
+.bar { extend .y}
+SCSS
+  end
+
+  def test_extend_into_matches_and_normal_extend
+    assert_equal <<CSS, render(<<SCSS)
+.x:matches(.y, .bar), .foo:matches(.y, .bar) {
+  a: b; }
+CSS
+.x:matches(.y) {a: b}
+.foo { extend .x}
+.bar { extend .y}
+SCSS
+  end
+
+  def test_multilayer_pseudoclass_extend
+    assert_equal <<CSS, render(<<SCSS)
+:matches(.x, .foo, .bar) {
+  a: b; }
+CSS
+:matches(.x) {a: b}
+.foo { extend .x}
+.bar { extend .foo}
+SCSS
+  end
+
+  def test_comma_extendee
+    assert_equal <<CSS, render(<<SCSS)
+.foo, .baz {
+  a: b; }
+
+.bar, .baz {
+  c: d; }
+CSS
+.foo {a: b}
+.bar {c: d}
+.baz { extend .foo, .bar}
+SCSS
+  end
+
+  def test_redundant_selector_elimination
+    assert_equal <<CSS, render(<<SCSS)
+.foo.bar, .x, .y {
+  a: b; }
+CSS
+.foo.bar {a: b}
+.x { extend .foo, .bar}
+.y { extend .foo, .bar}
+SCSS
+  end
+
+  def test_nested_pseudo_selectors
+    assert_equal <<CSS, render(<<SCSS)
+.foo .bar:not(.baz), .bang .bar:not(.baz) {
+  a: b; }
+CSS
+.foo {
+  .bar:not(.baz) {a: b}
+}
+.bang { extend .foo}
+SCSS
+  end
+
+  ## Long Extendees
+
+  def test_long_extendee
+    assert_extends '.foo.bar', '.baz { extend .foo.bar}', '.foo.bar, .baz'
+  end
+
+  def test_long_extendee_requires_all_selectors
+    assert_extend_doesnt_match('.baz', '.foo.bar', :not_found, 2) do
+      render_extends '.foo', '.baz { extend .foo.bar}'
+    end
+  end
+
+  def test_long_extendee_matches_supersets
+    assert_extends '.foo.bar.bap', '.baz { extend .foo.bar}', '.foo.bar.bap, .bap.baz'
+  end
+
+  def test_long_extendee_runs_unification
+    assert_extends 'ns|*.foo.bar', 'a.baz { extend .foo.bar}', 'ns|*.foo.bar, ns|a.baz'
+  end
+
+  ## Long Extenders
+
+  def test_long_extender
+    assert_extends '.foo.bar', '.baz.bang { extend .foo}', '.foo.bar, .bar.baz.bang'
+  end
+
+  def test_long_extender_runs_unification
+    assert_extends 'ns|*.foo.bar', 'a.baz { extend .foo}', 'ns|*.foo.bar, ns|a.bar.baz'
+  end
+
+  def test_long_extender_aborts_unification
+    assert_extend_doesnt_match('h1.baz', '.foo', :failed_to_unify, 2) do
+      render_extends 'a.foo#bar', 'h1.baz { extend .foo}'
+    end
+
+    assert_extend_doesnt_match('.bang#baz', '.foo', :failed_to_unify, 2) do
+      render_extends 'a.foo#bar', '.bang#baz { extend .foo}'
+    end
+  end
+
+  ## Nested Extenders
+
+  def test_nested_extender
+    assert_extends '.foo', 'foo bar { extend .foo}', '.foo, foo bar'
+  end
+
+  def test_nested_extender_runs_unification
+    assert_extends '.foo.bar', 'foo bar { extend .foo}', '.foo.bar, foo bar.bar'
+  end
+
+  def test_nested_extender_aborts_unification
+    assert_extend_doesnt_match('foo bar', '.foo', :failed_to_unify, 2) do
+      render_extends 'baz.foo', 'foo bar { extend .foo}'
+    end
+  end
+
+  def test_nested_extender_alternates_parents
+    assert_extends('.baz .bip .foo', 'foo .grank bar { extend .foo}',
+      '.baz .bip .foo, .baz .bip foo .grank bar, foo .grank .baz .bip bar')
+  end
+
+  def test_nested_extender_unifies_identical_parents
+    assert_extends('.baz .bip .foo', '.baz .bip bar { extend .foo}',
+      '.baz .bip .foo, .baz .bip bar')
+  end
+
+  def test_nested_extender_unifies_common_substring
+    assert_extends('.baz .bip .bap .bink .foo', '.brat .bip .bap bar { extend .foo}',
+      '.baz .bip .bap .bink .foo, .baz .brat .bip .bap .bink bar, .brat .baz .bip .bap .bink bar')
+  end
+
+  def test_nested_extender_unifies_common_subseq
+    assert_extends('.a .x .b .y .foo', '.a .n .b .m bar { extend .foo}',
+      '.a .x .b .y .foo, .a .x .n .b .y .m bar, .a .n .x .b .y .m bar, .a .x .n .b .m .y bar, .a .n .x .b .m 
.y bar')
+  end
+
+  def test_nested_extender_chooses_first_subseq
+    assert_extends('.a .b .c .d .foo', '.c .d .a .b .bar { extend .foo}',
+      '.a .b .c .d .foo, .a .b .c .d .a .b .bar')
+  end
+
+  def test_nested_extender_counts_extended_subselectors
+    assert_extends('.a .bip.bop .foo', '.b .bip .bar { extend .foo}',
+      '.a .bip.bop .foo, .a .b .bip.bop .bar, .b .a .bip.bop .bar')
+  end
+
+  def test_nested_extender_counts_extended_superselectors
+    assert_extends('.a .bip .foo', '.b .bip.bop .bar { extend .foo}',
+      '.a .bip .foo, .a .b .bip.bop .bar, .b .a .bip.bop .bar')
+  end
+
+  def test_nested_extender_with_child_selector
+    assert_extends '.baz .foo', 'foo > bar { extend .foo}', '.baz .foo, .baz foo > bar'
+  end
+
+  def test_nested_extender_finds_common_selectors_around_child_selector
+    assert_extends 'a > b c .c1', 'a c .c2 { extend .c1}', 'a > b c .c1, a > b c .c2'
+    assert_extends 'a > b c .c1', 'b c .c2 { extend .c1}', 'a > b c .c1, a > b c .c2'
+  end
+
+  def test_nested_extender_doesnt_find_common_selectors_around_adjacent_sibling_selector
+    assert_extends 'a + b c .c1', 'a c .c2 { extend .c1}', 'a + b c .c1, a + b a c .c2, a a + b c .c2'
+    assert_extends 'a + b c .c1', 'a b .c2 { extend .c1}', 'a + b c .c1, a a + b c .c2'
+    assert_extends 'a + b c .c1', 'b c .c2 { extend .c1}', 'a + b c .c1, a + b c .c2'
+  end
+
+  def test_nested_extender_doesnt_find_common_selectors_around_sibling_selector
+    assert_extends 'a ~ b c .c1', 'a c .c2 { extend .c1}', 'a ~ b c .c1, a ~ b a c .c2, a a ~ b c .c2'
+    assert_extends 'a ~ b c .c1', 'a b .c2 { extend .c1}', 'a ~ b c .c1, a a ~ b c .c2'
+    assert_extends 'a ~ b c .c1', 'b c .c2 { extend .c1}', 'a ~ b c .c1, a ~ b c .c2'
+  end
+
+  def test_nested_extender_doesnt_find_common_selectors_around_reference_selector
+    assert_extends 'a /for/ b c .c1', 'a c .c2 { extend .c1}', 'a /for/ b c .c1, a /for/ b a c .c2, a a 
/for/ b c .c2'
+    assert_extends 'a /for/ b c .c1', 'a b .c2 { extend .c1}', 'a /for/ b c .c1, a a /for/ b c .c2'
+    assert_extends 'a /for/ b c .c1', 'b c .c2 { extend .c1}', 'a /for/ b c .c1, a /for/ b c .c2'
+  end
+
+  def test_nested_extender_with_early_child_selectors_doesnt_subseq_them
+    assert_extends('.bip > .bap .foo', '.grip > .bap .bar { extend .foo}',
+      '.bip > .bap .foo, .bip > .bap .grip > .bap .bar, .grip > .bap .bip > .bap .bar')
+    assert_extends('.bap > .bip .foo', '.bap > .grip .bar { extend .foo}',
+      '.bap > .bip .foo, .bap > .bip .bap > .grip .bar, .bap > .grip .bap > .bip .bar')
+  end
+
+  def test_nested_extender_with_child_selector_unifies
+    assert_extends '.baz.foo', 'foo > bar { extend .foo}', '.baz.foo, foo > bar.baz'
+
+    assert_equal <<CSS, render(<<SCSS)
+.baz > .foo, .baz > .bar {
+  a: b; }
+CSS
+.baz > {
+  .foo {a: b}
+  .bar { extend .foo}
+}
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+.foo .bar, .foo > .baz {
+  a: b; }
+CSS
+.foo {
+  .bar {a: b}
+  > .baz { extend .bar}
+}
+SCSS
+  end
+
+  def test_nested_extender_with_early_child_selector
+    assert_equal <<CSS, render(<<SCSS)
+.foo .bar, .foo .bip > .baz {
+  a: b; }
+CSS
+.foo {
+  .bar {a: b}
+  .bip > .baz { extend .bar}
+}
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+.foo .bip .bar, .foo .bip .foo > .baz {
+  a: b; }
+CSS
+.foo {
+  .bip .bar {a: b}
+  > .baz { extend .bar}
+}
+SCSS
+
+    assert_extends '.foo > .bar', '.bip + .baz { extend .bar}', '.foo > .bar, .foo > .bip + .baz'
+    assert_extends '.foo + .bar', '.bip > .baz { extend .bar}', '.foo + .bar, .bip > .foo + .baz'
+    assert_extends '.foo > .bar', '.bip > .baz { extend .bar}', '.foo > .bar, .bip.foo > .baz'
+  end
+
+  def test_nested_extender_with_trailing_child_selector
+    assert_raises(Sass::SyntaxError, "bar > can't extend: invalid selector") do
+      render("bar > { extend .baz}")
+    end
+  end
+
+  def test_nested_extender_with_sibling_selector
+    assert_extends '.baz .foo', 'foo + bar { extend .foo}', '.baz .foo, .baz foo + bar'
+  end
+
+  def test_nested_extender_with_hacky_selector
+    assert_extends('.baz .foo', 'foo + > > + bar { extend .foo}',
+      '.baz .foo, .baz foo + > > + bar, foo .baz + > > + bar')
+    assert_extends '.baz .foo', '> > bar { extend .foo}', '.baz .foo, > > .baz bar'
+  end
+
+  def test_nested_extender_merges_with_same_selector
+    assert_equal <<CSS, render(<<SCSS)
+.foo .bar, .foo .baz {
+  a: b; }
+CSS
+.foo {
+  .bar {a: b}
+  .baz { extend .bar} }
+SCSS
+  end
+
+  def test_nested_extender_with_child_selector_merges_with_same_selector
+    assert_extends('.foo > .bar .baz', '.foo > .bar .bang { extend .baz}',
+      '.foo > .bar .baz, .foo > .bar .bang')
+  end
+
+  # Combinator Unification
+
+  def test_combinator_unification_for_hacky_combinators
+    assert_extends '.a > + x', '.b y { extend x}', '.a > + x, .a .b > + y, .b .a > + y'
+    assert_extends '.a x', '.b > + y { extend x}', '.a x, .a .b > + y, .b .a > + y'
+    assert_extends '.a > + x', '.b > + y { extend x}', '.a > + x, .a .b > + y, .b .a > + y'
+    assert_extends '.a ~ > + x', '.b > + y { extend x}', '.a ~ > + x, .a .b ~ > + y, .b .a ~ > + y'
+    assert_extends '.a + > x', '.b > + y { extend x}', '.a + > x'
+    assert_extends '.a + > x', '.b > + y { extend x}', '.a + > x'
+    assert_extends '.a ~ > + .b > x', '.c > + .d > y { extend x}', '.a ~ > + .b > x, .a .c ~ > + .d.b > y, 
.c .a ~ > + .d.b > y'
+  end
+
+  def test_combinator_unification_double_tilde
+    assert_extends '.a.b ~ x', '.a ~ y { extend x}', '.a.b ~ x, .a.b ~ y'
+    assert_extends '.a ~ x', '.a.b ~ y { extend x}', '.a ~ x, .a.b ~ y'
+    assert_extends '.a ~ x', '.b ~ y { extend x}', '.a ~ x, .a ~ .b ~ y, .b ~ .a ~ y, .b.a ~ y'
+    assert_extends 'a.a ~ x', 'b.b ~ y { extend x}', 'a.a ~ x, a.a ~ b.b ~ y, b.b ~ a.a ~ y'
+  end
+
+  def test_combinator_unification_tilde_plus
+    assert_extends '.a.b + x', '.a ~ y { extend x}', '.a.b + x, .a.b + y'
+    assert_extends '.a + x', '.a.b ~ y { extend x}', '.a + x, .a.b ~ .a + y, .a.b + y'
+    assert_extends '.a + x', '.b ~ y { extend x}', '.a + x, .b ~ .a + y, .b.a + y'
+    assert_extends 'a.a + x', 'b.b ~ y { extend x}', 'a.a + x, b.b ~ a.a + y'
+    assert_extends '.a.b ~ x', '.a + y { extend x}', '.a.b ~ x, .a.b ~ .a + y, .a.b + y'
+    assert_extends '.a ~ x', '.a.b + y { extend x}', '.a ~ x, .a.b + y'
+    assert_extends '.a ~ x', '.b + y { extend x}', '.a ~ x, .a ~ .b + y, .a.b + y'
+    assert_extends 'a.a ~ x', 'b.b + y { extend x}', 'a.a ~ x, a.a ~ b.b + y'
+  end
+
+  def test_combinator_unification_angle_sibling
+    assert_extends '.a > x', '.b ~ y { extend x}', '.a > x, .a > .b ~ y'
+    assert_extends '.a > x', '.b + y { extend x}', '.a > x, .a > .b + y'
+    assert_extends '.a ~ x', '.b > y { extend x}', '.a ~ x, .b > .a ~ y'
+    assert_extends '.a + x', '.b > y { extend x}', '.a + x, .b > .a + y'
+  end
+
+  def test_combinator_unification_double_angle
+    assert_extends '.a.b > x', '.b > y { extend x}', '.a.b > x, .b.a > y'
+    assert_extends '.a > x', '.a.b > y { extend x}', '.a > x, .a.b > y'
+    assert_extends '.a > x', '.b > y { extend x}', '.a > x, .b.a > y'
+    assert_extends 'a.a > x', 'b.b > y { extend x}', 'a.a > x'
+  end
+
+  def test_combinator_unification_double_plus
+    assert_extends '.a.b + x', '.b + y { extend x}', '.a.b + x, .b.a + y'
+    assert_extends '.a + x', '.a.b + y { extend x}', '.a + x, .a.b + y'
+    assert_extends '.a + x', '.b + y { extend x}', '.a + x, .b.a + y'
+    assert_extends 'a.a + x', 'b.b + y { extend x}', 'a.a + x'
+  end
+
+  def test_combinator_unification_angle_space
+    assert_extends '.a.b > x', '.a y { extend x}', '.a.b > x, .a.b > y'
+    assert_extends '.a > x', '.a.b y { extend x}', '.a > x, .a.b .a > y'
+    assert_extends '.a > x', '.b y { extend x}', '.a > x, .b .a > y'
+    assert_extends '.a.b x', '.a > y { extend x}', '.a.b x, .a.b .a > y'
+    assert_extends '.a x', '.a.b > y { extend x}', '.a x, .a.b > y'
+    assert_extends '.a x', '.b > y { extend x}', '.a x, .a .b > y'
+  end
+
+  def test_combinator_unification_plus_space
+    assert_extends '.a.b + x', '.a y { extend x}', '.a.b + x, .a .a.b + y'
+    assert_extends '.a + x', '.a.b y { extend x}', '.a + x, .a.b .a + y'
+    assert_extends '.a + x', '.b y { extend x}', '.a + x, .b .a + y'
+    assert_extends '.a.b x', '.a + y { extend x}', '.a.b x, .a.b .a + y'
+    assert_extends '.a x', '.a.b + y { extend x}', '.a x, .a .a.b + y'
+    assert_extends '.a x', '.b + y { extend x}', '.a x, .a .b + y'
+  end
+
+  def test_combinator_unification_nested
+    assert_extends '.a > .b + x', '.c > .d + y { extend x}', '.a > .b + x, .c.a > .d.b + y'
+    assert_extends '.a > .b + x', '.c > y { extend x}', '.a > .b + x, .c.a > .b + y'
+  end
+
+  def test_combinator_unification_with_newlines
+    assert_equal <<CSS, render(<<SCSS)
+.a >
+.b
++ x, .c.a > .d.b + y {
+  a: b; }
+CSS
+.a >
+.b
++ x {a: b}
+.c
+> .d +
+y { extend x}
+SCSS
+  end
+
+  # Loops
+
+  def test_extend_self_loop
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: b; }
+CSS
+.foo {a: b; @extend .foo}
+SCSS
+  end
+
+  def test_basic_extend_loop
+    assert_equal <<CSS, render(<<SCSS)
+.foo, .bar {
+  a: b; }
+
+.bar, .foo {
+  c: d; }
+CSS
+.foo {a: b; @extend .bar}
+.bar {c: d; @extend .foo}
+SCSS
+  end
+
+  def test_three_level_extend_loop
+    assert_equal <<CSS, render(<<SCSS)
+.foo, .baz, .bar {
+  a: b; }
+
+.bar, .foo, .baz {
+  c: d; }
+
+.baz, .bar, .foo {
+  e: f; }
+CSS
+.foo {a: b; @extend .bar}
+.bar {c: d; @extend .baz}
+.baz {e: f; @extend .foo}
+SCSS
+  end
+
+  def test_nested_extend_loop
+    assert_equal <<CSS, render(<<SCSS)
+.bar, .bar .foo {
+  a: b; }
+  .bar .foo {
+    c: d; }
+CSS
+.bar {
+  a: b;
+  .foo {c: d; @extend .bar}
+}
+SCSS
+  end
+
+  def test_cross_loop
+    # The first law of extend means the selector should stick around.
+    assert_equal <<CSS, render(<<SCSS)
+.foo.bar, .foo, .bar {
+  a: b; }
+CSS
+.foo.bar {a: b}
+.foo { extend .bar}
+.bar { extend .foo}
+SCSS
+  end
+
+  def test_multiple_extender_merges_with_superset_selector
+    assert_equal <<CSS, render(<<SCSS)
+a.bar.baz, a.foo {
+  a: b; }
+CSS
+.foo { extend .bar; @extend .baz}
+a.bar.baz {a: b}
+SCSS
+  end
+
+  def test_control_flow_if
+    assert_equal <<CSS, render(<<SCSS)
+.true, .also-true {
+  color: green; }
+
+.false, .also-false {
+  color: red; }
+CSS
+.true  { color: green; }
+.false { color: red;   }
+.also-true {
+  @if true { @extend .true;  }
+  @else    { @extend .false; }
+}
+.also-false {
+  @if false { @extend .true;  }
+  @else     { @extend .false; }
+}
+SCSS
+  end
+
+  def test_control_flow_for
+    assert_equal <<CSS, render(<<SCSS)
+.base-0, .added {
+  color: green; }
+
+.base-1, .added {
+  display: block; }
+
+.base-2, .added {
+  border: 1px solid blue; }
+CSS
+.base-0  { color: green; }
+.base-1  { display: block; }
+.base-2  { border: 1px solid blue; }
+.added {
+  @for $i from 0 to 3 {
+    @extend .base-\#{$i};
+  }
+}
+SCSS
+  end
+
+  def test_control_flow_while
+    assert_equal <<CSS, render(<<SCSS)
+.base-0, .added {
+  color: green; }
+
+.base-1, .added {
+  display: block; }
+
+.base-2, .added {
+  border: 1px solid blue; }
+CSS
+.base-0  { color: green; }
+.base-1  { display: block; }
+.base-2  { border: 1px solid blue; }
+.added {
+  $i : 0;
+  @while $i < 3 {
+    @extend .base-\#{$i};
+    $i : $i + 1;
+  }
+}
+SCSS
+  end
+
+  def test_basic_placeholder_selector
+    assert_extends '%foo', '.bar { extend %foo}', '.bar'
+  end
+
+  def test_unused_placeholder_selector
+    assert_equal <<CSS, render(<<SCSS)
+.baz {
+  color: blue; }
+CSS
+%foo {color: blue}
+%bar {color: red}
+.baz { extend %foo}
+SCSS
+  end
+
+  def test_placeholder_descendant_selector
+    assert_extends '#context %foo a', '.bar { extend %foo}', '#context .bar a'
+  end
+
+  def test_semi_placeholder_selector
+    assert_equal <<CSS, render(<<SCSS)
+.bar .baz {
+  color: blue; }
+CSS
+#context %foo, .bar .baz {color: blue}
+SCSS
+  end
+
+  def test_placeholder_selector_with_multiple_extenders
+    assert_equal <<CSS, render(<<SCSS)
+.bar, .baz {
+  color: blue; }
+CSS
+%foo {color: blue}
+.bar { extend %foo}
+.baz { extend %foo}
+SCSS
+  end
+
+  def test_placeholder_selector_as_modifier
+    assert_extend_doesnt_match('div', '%foo', :failed_to_unify, 3) do
+      render(<<SCSS)
+a%foo.baz {color: blue}
+.bar { extend %foo}
+div { extend %foo}
+SCSS
+    end
+  end
+
+  def test_placeholder_interpolation
+    assert_equal <<CSS, render(<<SCSS)
+.bar {
+  color: blue; }
+CSS
+$foo: foo;
+
+%\#{$foo} {color: blue}
+.bar { extend %foo}
+SCSS
+  end
+
+  def test_placeholder_in_selector_pseudoclass
+    assert_equal <<CSS, render(<<SCSS)
+:matches(.bar, .baz) {
+  color: blue; }
+CSS
+:matches(%foo) {color: blue}
+.bar { extend %foo}
+.baz { extend %foo}
+SCSS
+  end
+
+  def test_media_in_placeholder_selector
+    assert_equal <<CSS, render(<<SCSS)
+.baz {
+  c: d; }
+CSS
+%foo {bar { media screen {a: b}}}
+.baz {c: d}
+SCSS
+  end
+
+  def test_extend_out_of_media
+    assert_raise_message(Sass::SyntaxError, <<ERR) {render(<<SCSS)}
+You may not @extend an outer selector from within @media.
+You may only @extend selectors within the same directive.
+From "@extend .foo" on line 3 of test_extend_out_of_media_inline.scss.
+ERR
+.foo {a: b}
+ media screen {
+  .bar { extend .foo}
+}
+SCSS
+  end
+
+  def test_extend_out_of_unknown_directive
+    assert_raise_message(Sass::SyntaxError, <<ERR) {render(<<SCSS)}
+You may not @extend an outer selector from within @flooblehoof.
+You may only @extend selectors within the same directive.
+From "@extend .foo" on line 3 of test_extend_out_of_unknown_directive_inline.scss.
+ERR
+.foo {a: b}
+ flooblehoof {
+  .bar { extend .foo}
+}
+SCSS
+  end
+
+  def test_extend_out_of_nested_directives
+    assert_raise_message(Sass::SyntaxError, <<ERR) {render(<<SCSS)}
+You may not @extend an outer selector from within @flooblehoof.
+You may only @extend selectors within the same directive.
+From "@extend .foo" on line 4 of test_extend_out_of_nested_directives_inline.scss.
+ERR
+ media screen {
+  .foo {a: b}
+  @flooblehoof {
+    .bar { extend .foo}
+  }
+}
+SCSS
+  end
+
+  def test_extend_within_media
+    assert_equal(<<CSS, render(<<SCSS))
+ media screen {
+  .foo, .bar {
+    a: b; } }
+CSS
+ media screen {
+  .foo {a: b}
+  .bar { extend .foo}
+}
+SCSS
+  end
+
+  def test_extend_within_unknown_directive
+    assert_equal(<<CSS, render(<<SCSS))
+ flooblehoof {
+  .foo, .bar {
+    a: b; } }
+CSS
+ flooblehoof {
+  .foo {a: b}
+  .bar { extend .foo}
+}
+SCSS
+  end
+
+  def test_extend_within_nested_directives
+    assert_equal(<<CSS, render(<<SCSS))
+ media screen {
+  @flooblehoof {
+    .foo, .bar {
+      a: b; } } }
+CSS
+ media screen {
+  @flooblehoof {
+    .foo {a: b}
+    .bar { extend .foo}
+  }
+}
+SCSS
+  end
+
+  def test_extend_within_disparate_media
+    assert_equal(<<CSS, render(<<SCSS))
+ media screen {
+  .foo, .bar {
+    a: b; } }
+CSS
+ media screen {.foo {a: b}}
+ media screen {.bar { extend .foo}}
+SCSS
+  end
+
+  def test_extend_within_disparate_unknown_directive
+    assert_equal(<<CSS, render(<<SCSS))
+ flooblehoof {
+  .foo, .bar {
+    a: b; } }
+ flooblehoof {}
+CSS
+ flooblehoof {.foo {a: b}}
+ flooblehoof {.bar { extend .foo}}
+SCSS
+  end
+
+  def test_extend_within_disparate_nested_directives
+    assert_equal(<<CSS, render(<<SCSS))
+ media screen {
+  @flooblehoof {
+    .foo, .bar {
+      a: b; } } }
+ media screen {
+  @flooblehoof {} }
+CSS
+ media screen { flooblehoof {.foo {a: b}}}
+ media screen { flooblehoof {.bar { extend .foo}}}
+SCSS
+  end
+
+  def test_extend_within_and_without_media
+    assert_raise_message(Sass::SyntaxError, <<ERR) {render(<<SCSS)}
+You may not @extend an outer selector from within @media.
+You may only @extend selectors within the same directive.
+From "@extend .foo" on line 4 of test_extend_within_and_without_media_inline.scss.
+ERR
+.foo {a: b}
+ media screen {
+  .foo {c: d}
+  .bar { extend .foo}
+}
+SCSS
+  end
+
+  def test_extend_within_and_without_unknown_directive
+    assert_raise_message(Sass::SyntaxError, <<ERR) {render(<<SCSS)}
+You may not @extend an outer selector from within @flooblehoof.
+You may only @extend selectors within the same directive.
+From "@extend .foo" on line 4 of test_extend_within_and_without_unknown_directive_inline.scss.
+ERR
+.foo {a: b}
+ flooblehoof {
+  .foo {c: d}
+  .bar { extend .foo}
+}
+SCSS
+  end
+
+  def test_extend_within_and_without_nested_directives
+    assert_raise_message(Sass::SyntaxError, <<ERR) {render(<<SCSS)}
+You may not @extend an outer selector from within @flooblehoof.
+You may only @extend selectors within the same directive.
+From "@extend .foo" on line 5 of test_extend_within_and_without_nested_directives_inline.scss.
+ERR
+ media screen {
+  .foo {a: b}
+  @flooblehoof {
+    .foo {c: d}
+    .bar { extend .foo}
+  }
+}
+SCSS
+  end
+
+  def test_extend_with_subject_transfers_subject_to_extender
+    silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
+foo bar! baz, foo .bip .bap! baz, .bip foo .bap! baz {
+  a: b; }
+CSS
+foo bar! baz {a: b}
+.bip .bap { extend bar}
+SCSS
+
+    silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
+foo.x bar.y! baz.z, foo.x .bip bar.bap! baz.z, .bip foo.x bar.bap! baz.z {
+  a: b; }
+CSS
+foo.x bar.y! baz.z {a: b}
+.bip .bap { extend .y}
+SCSS
+  end
+
+  def test_extend_with_subject_retains_subject_on_target
+    silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
+.foo! .bar, .foo! .bip .bap, .bip .foo! .bap {
+  a: b; }
+CSS
+.foo! .bar {a: b}
+.bip .bap { extend .bar}
+SCSS
+  end
+
+  def test_extend_with_subject_transfers_subject_to_target
+    silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
+a.foo .bar, .bip a.bap! .bar {
+  a: b; }
+CSS
+a.foo .bar {a: b}
+.bip .bap! { extend .foo}
+SCSS
+  end
+
+  def test_extend_with_subject_retains_subject_on_extender
+    silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
+.foo .bar, .foo .bip! .bap, .bip! .foo .bap {
+  a: b; }
+CSS
+.foo .bar {a: b}
+.bip! .bap { extend .bar}
+SCSS
+  end
+
+  def test_extend_with_subject_fails_with_conflicting_subject
+    silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
+x! .bar {
+  a: b; }
+CSS
+x! .bar {a: b}
+y! .bap { extend .bar}
+SCSS
+  end
+
+  def test_extend_warns_when_extendee_doesnt_exist
+    assert_raise_message(Sass::SyntaxError, <<ERR) {render(<<SCSS)}
+".foo" failed to @extend ".bar".
+The selector ".bar" was not found.
+Use "@extend .bar !optional" if the extend should be able to fail.
+ERR
+.foo { extend .bar}
+SCSS
+  end
+
+  def test_extend_warns_when_extension_fails
+    assert_raise_message(Sass::SyntaxError, <<ERR) {render(<<SCSS)}
+"b.foo" failed to @extend ".bar".
+No selectors matching ".bar" could be unified with "b.foo".
+Use "@extend .bar !optional" if the extend should be able to fail.
+ERR
+a.bar {a: b}
+b.foo { extend .bar}
+SCSS
+  end
+
+  def test_extend_succeeds_when_one_extension_fails_but_others_dont
+    assert_equal(<<CSS, render(<<SCSS))
+a.bar {
+  a: b; }
+
+.bar, b.foo {
+  c: d; }
+CSS
+a.bar {a: b}
+.bar {c: d}
+b.foo { extend .bar}
+SCSS
+  end
+
+  def test_optional_extend_succeeds_when_extendee_doesnt_exist
+    assert_equal("", render(<<SCSS))
+.foo { extend .bar !optional}
+SCSS
+  end
+
+  def test_optional_extend_succeeds_when_extension_fails
+    assert_equal(<<CSS, render(<<SCSS))
+a.bar {
+  a: b; }
+CSS
+a.bar {a: b}
+b.foo { extend .bar !optional}
+SCSS
+  end
+
+  # Regression Tests
+
+  def test_extend_parent_selector_suffix
+    assert_equal <<CSS, render(<<SCSS)
+.a-b, .c {
+  x: y; }
+CSS
+.a {&-b {x: y}}
+.c { extend .a-b}
+SCSS
+  end
+
+  def test_pseudo_element_superselector
+    # Pseudo-elements shouldn't be removed in superselector calculations.
+    assert_equal <<CSS, render(<<SCSS)
+a#bar, a#bar::fblthp {
+  a: b; }
+CSS
+%x#bar {a: b} // Add an id to make the results have high specificity
+%y, %y::fblthp { extend %x}
+a { extend %y}
+SCSS
+
+    # Pseudo-classes can be removed when the second law allows.
+    assert_equal <<CSS, render(<<SCSS)
+a#bar {
+  a: b; }
+CSS
+%x#bar {a: b}
+%y, %y:fblthp { extend %x}
+a { extend %y}
+SCSS
+
+    # A few pseudo-elements can be written as pseudo-elements for historical
+    # reasons. See http://www.w3.org/TR/selectors4/#pseudo-elements.
+    %w[first-line first-letter before after].each do |pseudo|
+      assert_equal <<CSS, render(<<SCSS)
+a#bar, a#bar:#{pseudo} {
+  a: b; }
+CSS
+%x#bar {a: b}
+%y, %y:#{pseudo} { extend %x}
+a { extend %y}
+SCSS
+    end
+  end
+
+  def test_multiple_source_redundancy_elimination
+    assert_equal <<CSS, render(<<SCSS)
+.test-case, .test-case:active {
+  color: red; }
+
+.test-case:hover {
+  color: green; }
+CSS
+%default-color {color: red}
+%alt-color {color: green}
+
+%default-style {
+  @extend %default-color;
+  &:hover { extend %alt-color}
+  &:active { extend %default-color}
+}
+
+.test-case { extend %default-style}
+SCSS
+  end
+
+  def test_nested_sibling_extend
+    assert_equal <<CSS, render(<<SCSS)
+.parent .bar, .parent .foo {
+  width: 2000px; }
+CSS
+.foo { extend .bar}
+
+.parent {
+  .bar {
+    width: 2000px;
+  }
+  .foo {
+    @extend .bar
+  }
+}
+SCSS
+  end
+
+  def test_parent_and_sibling_extend
+    assert_equal <<CSS, render(<<SCSS)
+.parent1 .parent2 .child1.child2, .parent2 .parent1 .child1.child2 {
+  c: d; }
+CSS
+%foo %bar%baz {c: d}
+
+.parent1 {
+  @extend %foo;
+  .child1 { extend %bar}
+}
+
+.parent2 {
+  @extend %foo;
+  .child2 { extend %baz}
+}
+SCSS
+  end
+
+  def test_nested_extend_specificity
+    assert_equal <<CSS, render(<<SCSS)
+a :b, a :b:c {
+  a: b; }
+CSS
+%foo {a: b}
+
+a {
+  :b { extend %foo}
+  :b:c { extend %foo}
+}
+SCSS
+  end
+
+  def test_nested_double_extend_optimization
+    assert_equal <<CSS, render(<<SCSS)
+.parent1 .child {
+  a: b; }
+CSS
+%foo %bar {
+  a: b;
+}
+
+.parent1 {
+  @extend %foo;
+
+  .child {
+    @extend %bar;
+  }
+}
+
+.parent2 {
+  @extend %foo;
+}
+SCSS
+  end
+
+  def test_extend_in_double_nested_media_query
+    assert_equal <<CSS, render(<<SCSS)
+ media all and (orientation: landscape) {
+  .bar {
+    color: blue; } }
+CSS
+ media all {
+  @media (orientation: landscape) {
+    %foo {color: blue}
+    .bar { extend %foo}
+  }
+}
+SCSS
+  end
+
+  def test_partially_failed_extend
+    assert_no_warning {assert_equal(<<CSS, render(<<SCSS))}
+.rc, test {
+  color: white; }
+
+.prices span.pill span.rc {
+  color: red; }
+CSS
+test { @extend .rc; }
+.rc {color: white;}
+.prices span.pill span.rc {color: red;}
+SCSS
+  end
+
+  def test_newline_near_combinator
+    assert_equal <<CSS, render(<<SCSS)
+.a +
+.b x, .a +
+.b .c y, .c .a +
+.b y {
+  a: b; }
+CSS
+.a +
+.b x {a: b}
+.c y { extend x}
+SCSS
+  end
+
+  def test_duplicated_selector_with_newlines
+    assert_equal(<<CSS, render(<<SCSS))
+.example-1-1,
+.example-1-2,
+.my-page-1 .my-module-1-1,
+.example-1-3 {
+  a: b; }
+CSS
+.example-1-1,
+.example-1-2,
+.example-1-3 {
+  a: b;
+}
+
+.my-page-1 .my-module-1-1 { extend .example-1-2}
+SCSS
+  end
+
+  def test_nested_selector_with_child_selector_hack_extendee
+    assert_extends '> .foo', 'foo bar { extend .foo}', '> .foo, > foo bar'
+  end
+
+  def test_nested_selector_with_child_selector_hack_extender
+    assert_extends '.foo .bar', '> foo bar { extend .bar}', '.foo .bar, > .foo foo bar, > foo .foo bar'
+  end
+
+  def test_nested_selector_with_child_selector_hack_extender_and_extendee
+    assert_extends '> .foo', '> foo bar { extend .foo}', '> .foo, > foo bar'
+  end
+
+  def test_nested_selector_with_child_selector_hack_extender_and_sibling_selector_extendee
+    assert_extends '~ .foo', '> foo bar { extend .foo}', '~ .foo'
+  end
+
+  def test_nested_selector_with_child_selector_hack_extender_and_extendee_and_newline
+    assert_equal <<CSS, render(<<SCSS)
+> .foo, > flip,
+> foo bar {
+  a: b; }
+CSS
+> .foo {a: b}
+flip,
+> foo bar { extend .foo}
+SCSS
+  end
+
+  def test_extended_parent_and_child_redundancy_elimination
+    assert_equal <<CSS, render(<<SCSS)
+a b, d b, a c, d c {
+  a: b; }
+CSS
+a {
+  b {a: b}
+  c { extend b}
+}
+d { extend a}
+SCSS
+  end
+
+  def test_extend_redundancy_elimination_when_it_would_reduce_specificity
+    assert_extends 'a', 'a.foo { extend a}', 'a, a.foo'
+  end
+
+  def test_extend_redundancy_elimination_when_it_would_preserve_specificity
+    assert_extends '.bar a', 'a.foo { extend a}', '.bar a'
+  end
+
+  def test_extend_redundancy_elimination_never_eliminates_base_selector
+    assert_extends 'a.foo', '.foo { extend a}', 'a.foo, .foo'
+  end
+
+  def test_extend_cross_branch_redundancy_elimination
+    assert_equal <<CSS, render(<<SCSS)
+.a .c .d, .b .c .a .d {
+  a: b; }
+CSS
+%x .c %y {a: b}
+.a, .b { extend %x}
+.a .d { extend %y}
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+.e .a .c .d, .a .c .e .d, .e .b .c .a .d, .b .c .a .e .d {
+  a: b; }
+CSS
+.e %z {a: b}
+%x .c %y { extend %z}
+.a, .b { extend %x}
+.a .d { extend %y}
+SCSS
+  end
+
+  private
+
+  def assert_extend_doesnt_match(extender, target, reason, line, syntax = :scss)
+    message = "\"#{extender}\" failed to @extend \"#{target}\"."
+    reason = 
+      if reason == :not_found
+        "The selector \"#{target}\" was not found."
+      else
+        "No selectors matching \"#{target}\" could be unified with \"#{extender}\"."
+      end
+
+    assert_raise_message(Sass::SyntaxError, <<ERR) {yield}
+#{message}
+#{reason}
+Use "@extend #{target} !optional" if the extend should be able to fail.
+ERR
+  end
+
+  def assert_unification(selector, extension, unified, nested = true)
+    # Do some trickery so the first law of extend doesn't get in our way.
+    assert_extends(
+      "%-a #{selector}",
+      extension + " -a { extend %-a}",
+      unified.split(', ').map {|s| "-a #{s}"}.join(', '))
+  end
+
+  def assert_specificity_equals(sel1, sel2)
+    assert_specificity_gte(sel1, sel2)
+    assert_specificity_gte(sel2, sel1)
+  end
+
+  def assert_specificity_gte(sel1, sel2)
+    assert_equal <<CSS, render(<<SCSS)
+#{sel1} .a {
+  a: b; }
+CSS
+#{sel1} %-a {a: b}
+.a { extend %-a}
+#{sel2}.a { extend %-a}
+SCSS
+  end
+
+  def render_unification(selector, extension)
+    render_extends(
+      "%-a #{selector}",
+      extension + " -a { extend %-a}")
+  end
+
+  def assert_extends(selector, extension, result)
+    assert_equal <<CSS, render_extends(selector, extension)
+#{result} {
+  a: b; }
+CSS
+  end
+
+  def assert_extends_to_nothing(selector, extension)
+    assert_equal '', render_extends(selector, extension)
+  end
+
+  def render_extends(selector, extension)
+    render(<<SCSS)
+#{selector} {a: b}
+#{extension}
+SCSS
+  end
+
+  def render(sass, options = {})
+    options = {:syntax => :scss}.merge(options)
+    munge_filename options
+    Sass::Engine.new(sass, options).render
+  end
+end
diff --git a/backends/css/gems/sass-3.2.12/test/sass/fixtures/test_staleness_check_across_importers.css 
b/backends/css/gems/sass-3.4.9/test/sass/fixtures/test_staleness_check_across_importers.css
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/fixtures/test_staleness_check_across_importers.css
rename to backends/css/gems/sass-3.4.9/test/sass/fixtures/test_staleness_check_across_importers.css
diff --git a/backends/css/gems/sass-3.2.12/test/sass/fixtures/test_staleness_check_across_importers.scss 
b/backends/css/gems/sass-3.4.9/test/sass/fixtures/test_staleness_check_across_importers.scss
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/fixtures/test_staleness_check_across_importers.scss
rename to backends/css/gems/sass-3.4.9/test/sass/fixtures/test_staleness_check_across_importers.scss
diff --git a/backends/css/gems/sass-3.4.9/test/sass/functions_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/functions_test.rb
new file mode 100755
index 0000000..b13addb
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/functions_test.rb
@@ -0,0 +1,1954 @@
+#!/usr/bin/env ruby
+require 'minitest/autorun'
+require File.dirname(__FILE__) + '/../test_helper'
+require File.dirname(__FILE__) + '/test_helper'
+require 'sass/script'
+require 'mock_importer'
+
+module Sass::Script::Functions
+  def no_kw_args
+    Sass::Script::Value::String.new("no-kw-args")
+  end
+
+  def only_var_args(*args)
+    Sass::Script::Value::String.new("only-var-args("+args.map{|a| 
a.plus(Sass::Script::Value::Number.new(1)).to_s }.join(", ")+")")
+  end
+  declare :only_var_args, [], :var_args => true
+
+  def only_kw_args(kwargs)
+    Sass::Script::Value::String.new("only-kw-args(" + kwargs.keys.map {|a| a.to_s}.sort.join(", ") + ")")
+  end
+  declare :only_kw_args, [], :var_kwargs => true
+
+  def deprecated_arg_fn(arg1, arg2, arg3 = nil)
+    Sass::Script::Value::List.new([arg1, arg2, arg3 || Sass::Script::Value::Null.new], :space)
+  end
+  declare :deprecated_arg_fn, [:arg1, :arg2, :arg3], :deprecated => [:arg_1, :arg_2, :arg3]
+  declare :deprecated_arg_fn, [:arg1, :arg2], :deprecated => [:arg_1, :arg_2]
+end
+
+module Sass::Script::Functions::UserFunctions
+  def call_options_on_new_value
+    str = Sass::Script::Value::String.new("foo")
+    str.options[:foo]
+    str
+  end
+
+  def user_defined
+    Sass::Script::Value::String.new("I'm a user-defined string!")
+  end
+
+  def _preceding_underscore
+    Sass::Script::Value::String.new("I'm another user-defined string!")
+  end
+
+  def fetch_the_variable
+    environment.var('variable')
+  end
+end
+
+module Sass::Script::Functions
+  include Sass::Script::Functions::UserFunctions
+end
+
+class SassFunctionTest < MiniTest::Test
+  # Tests taken from:
+  #   http://www.w3.org/Style/CSS/Test/CSS3/Color/20070927/html4/t040204-hsl-h-rotating-b.htm
+  #   http://www.w3.org/Style/CSS/Test/CSS3/Color/20070927/html4/t040204-hsl-values-b.htm
+  File.read(File.dirname(__FILE__) + "/data/hsl-rgb.txt").split("\n\n").each do |chunk|
+    hsls, rgbs = chunk.strip.split("====")
+    hsls.strip.split("\n").zip(rgbs.strip.split("\n")) do |hsl, rgb|
+      hsl_method = "test_hsl: #{hsl} = #{rgb}"
+      unless method_defined?(hsl_method)
+        define_method(hsl_method) do
+          assert_equal(evaluate(rgb), evaluate(hsl))
+        end
+      end
+
+      rgb_to_hsl_method = "test_rgb_to_hsl: #{rgb} = #{hsl}"
+      unless method_defined?(rgb_to_hsl_method)
+        define_method(rgb_to_hsl_method) do
+          rgb_color = perform(rgb)
+          hsl_color = perform(hsl)
+
+          white = hsl_color.lightness == 100
+          black = hsl_color.lightness == 0
+          grayscale = white || black || hsl_color.saturation == 0
+
+          assert_in_delta(hsl_color.hue, rgb_color.hue, 0.0001,
+            "Hues should be equal") unless grayscale
+          assert_in_delta(hsl_color.saturation, rgb_color.saturation, 0.0001,
+            "Saturations should be equal") unless white || black
+          assert_in_delta(hsl_color.lightness, rgb_color.lightness, 0.0001,
+            "Lightnesses should be equal")
+        end
+      end
+    end
+  end
+
+  def test_hsl_kwargs
+    assert_equal "#33cccc", evaluate("hsl($hue: 180, $saturation: 60%, $lightness: 50%)")
+  end
+
+  def test_hsl_clamps_bounds
+    assert_equal("#1f1f1f", evaluate("hsl(10, -114, 12)"))
+    assert_equal("white", evaluate("hsl(10, 10, 256%)"))
+  end
+
+  def test_hsl_checks_types
+    assert_error_message("$hue: \"foo\" is not a number for `hsl'", "hsl(\"foo\", 10, 12)");
+    assert_error_message("$saturation: \"foo\" is not a number for `hsl'", "hsl(10, \"foo\", 12)");
+    assert_error_message("$lightness: \"foo\" is not a number for `hsl'", "hsl(10, 10, \"foo\")");
+  end
+
+  def test_hsla
+    assert_equal "rgba(51, 204, 204, 0.4)", evaluate("hsla(180, 60%, 50%, 0.4)")
+    assert_equal "#33cccc", evaluate("hsla(180, 60%, 50%, 1)")
+    assert_equal "rgba(51, 204, 204, 0)", evaluate("hsla(180, 60%, 50%, 0)")
+    assert_equal "rgba(51, 204, 204, 0.4)", evaluate("hsla($hue: 180, $saturation: 60%, $lightness: 50%, 
$alpha: 0.4)")
+  end
+
+  def test_hsla_clamps_bounds
+    assert_equal("#1f1f1f", evaluate("hsla(10, -114, 12, 1)"))
+    assert_equal("rgba(255, 255, 255, 0)", evaluate("hsla(10, 10, 256%, 0)"))
+    assert_equal("rgba(28, 24, 23, 0)", evaluate("hsla(10, 10, 10, -0.1)"))
+    assert_equal("#1c1817", evaluate("hsla(10, 10, 10, 1.1)"))
+  end
+
+  def test_hsla_checks_types
+    assert_error_message("$hue: \"foo\" is not a number for `hsla'", "hsla(\"foo\", 10, 12, 0.3)");
+    assert_error_message("$saturation: \"foo\" is not a number for `hsla'", "hsla(10, \"foo\", 12, 0)");
+    assert_error_message("$lightness: \"foo\" is not a number for `hsla'", "hsla(10, 10, \"foo\", 1)");
+    assert_error_message("$alpha: \"foo\" is not a number for `hsla'", "hsla(10, 10, 10, \"foo\")");
+  end
+
+  def test_hsla_percent_warning
+    assert_warning(<<WARNING) {evaluate("hsla(180, 60%, 50%, 40%)")}
+DEPRECATION WARNING: Passing a percentage as the alpha value to hsla() will be
+interpreted differently in future versions of Sass. For now, use 40 instead.
+WARNING
+  end
+
+  def test_hsla_unit_warning
+    assert_warning(<<WARNING) {evaluate("hsla(180, 60%, 50%, 40em)")}
+DEPRECATION WARNING: Passing a number with units as the alpha value to hsla() is
+deprecated and will be an error in future versions of Sass. Use 40 instead.
+WARNING
+  end
+
+  def test_percentage
+    assert_equal("50%",  evaluate("percentage(.5)"))
+    assert_equal("100%", evaluate("percentage(1)"))
+    assert_equal("25%",  evaluate("percentage(25px / 100px)"))
+    assert_equal("50%",  evaluate("percentage($number: 0.5)"))
+  end
+
+  def test_percentage_checks_types
+    assert_error_message("$number: 25px is not a unitless number for `percentage'", "percentage(25px)")
+    assert_error_message("$number: #cccccc is not a unitless number for `percentage'", "percentage(#ccc)")
+    assert_error_message("$number: \"string\" is not a unitless number for `percentage'", 
%Q{percentage("string")})
+  end
+
+  def test_round
+    assert_equal("5",   evaluate("round(4.8)"))
+    assert_equal("5px", evaluate("round(4.8px)"))
+    assert_equal("5px", evaluate("round(5.49px)"))
+    assert_equal("5px", evaluate("round($number: 5.49px)"))
+  end
+
+  def test_round_checks_types
+    assert_error_message("$value: #cccccc is not a number for `round'", "round(#ccc)")
+  end
+
+  def test_floor
+    assert_equal("4",   evaluate("floor(4.8)"))
+    assert_equal("4px", evaluate("floor(4.8px)"))
+    assert_equal("4px", evaluate("floor($number: 4.8px)"))
+  end
+
+  def test_floor_checks_types
+    assert_error_message("$value: \"foo\" is not a number for `floor'", "floor(\"foo\")")
+  end
+
+  def test_ceil
+    assert_equal("5",   evaluate("ceil(4.1)"))
+    assert_equal("5px", evaluate("ceil(4.8px)"))
+    assert_equal("5px", evaluate("ceil($number: 4.8px)"))
+  end
+
+  def test_ceil_checks_types
+    assert_error_message("$value: \"a\" is not a number for `ceil'", "ceil(\"a\")")
+  end
+
+  def test_abs
+    assert_equal("5",   evaluate("abs(-5)"))
+    assert_equal("5px", evaluate("abs(-5px)"))
+    assert_equal("5",   evaluate("abs(5)"))
+    assert_equal("5px", evaluate("abs(5px)"))
+    assert_equal("5px", evaluate("abs($number: 5px)"))
+  end
+
+  def test_abs_checks_types
+    assert_error_message("$value: #aaaaaa is not a number for `abs'", "abs(#aaa)")
+  end
+
+  def test_min
+    assert_equal("1", evaluate("min(1, 2, 3)"))
+    assert_equal("1", evaluate("min(3px, 2px, 1)"))
+    assert_equal("4em", evaluate("min(4em)"))
+    assert_equal("10cm", evaluate("min(10cm, 6in)"))
+
+    assert_error_message("#aaaaaa is not a number for `min'", "min(#aaa)")
+    assert_error_message("Incompatible units: 'px' and 'em'.", "min(3em, 4em, 1px)")
+  end
+
+  def test_max
+    assert_equal("3", evaluate("max(1, 2, 3)"))
+    assert_equal("3", evaluate("max(3, 2px, 1px)"))
+    assert_equal("4em", evaluate("max(4em)"))
+    assert_equal("6in", evaluate("max(10cm, 6in)"))
+
+    assert_error_message("#aaaaaa is not a number for `max'", "max(#aaa)")
+    assert_error_message("Incompatible units: 'px' and 'em'.", "max(3em, 4em, 1px)")
+  end
+
+  def test_rgb
+    assert_equal("#123456", evaluate("rgb(18, 52, 86)"))
+    assert_equal("#beaded", evaluate("rgb(190, 173, 237)"))
+    assert_equal("springgreen", evaluate("rgb(0, 255, 127)"))
+    assert_equal("springgreen", evaluate("rgb($red: 0, $green: 255, $blue: 127)"))
+  end
+
+  def test_rgb_percent
+    assert_equal("#123456", evaluate("rgb(7.1%, 20.4%, 34%)"))
+    assert_equal("#beaded", evaluate("rgb(74.7%, 173, 93%)"))
+    assert_equal("#beaded", evaluate("rgb(190, 68%, 237)"))
+    assert_equal("springgreen", evaluate("rgb(0%, 100%, 50%)"))
+  end
+
+  def test_rgb_clamps_bounds
+    assert_equal("#ff0101", evaluate("rgb(256, 1, 1)"))
+    assert_equal("#01ff01", evaluate("rgb(1, 256, 1)"))
+    assert_equal("#0101ff", evaluate("rgb(1, 1, 256)"))
+    assert_equal("#01ffff", evaluate("rgb(1, 256, 257)"))
+    assert_equal("#000101", evaluate("rgb(-1, 1, 1)"))
+  end
+
+  def test_rgb_clamps_percent_bounds
+    assert_equal("red", evaluate("rgb(100.1%, 0, 0)"))
+    assert_equal("black", evaluate("rgb(0, -0.1%, 0)"))
+    assert_equal("blue", evaluate("rgb(0, 0, 101%)"))
+  end
+
+  def test_rgb_tests_types
+    assert_error_message("$red: \"foo\" is not a number for `rgb'", "rgb(\"foo\", 10, 12)");
+    assert_error_message("$green: \"foo\" is not a number for `rgb'", "rgb(10, \"foo\", 12)");
+    assert_error_message("$blue: \"foo\" is not a number for `rgb'", "rgb(10, 10, \"foo\")");
+  end
+
+  def test_rgba
+    assert_equal("rgba(18, 52, 86, 0.5)", evaluate("rgba(18, 52, 86, 0.5)"))
+    assert_equal("#beaded", evaluate("rgba(190, 173, 237, 1)"))
+    assert_equal("rgba(0, 255, 127, 0)", evaluate("rgba(0, 255, 127, 0)"))
+    assert_equal("rgba(0, 255, 127, 0)", evaluate("rgba($red: 0, $green: 255, $blue: 127, $alpha: 0)"))
+  end
+
+  def test_rgba_clamps_bounds
+    assert_equal("rgba(255, 1, 1, 0.3)", evaluate("rgba(256, 1, 1, 0.3)"))
+    assert_equal("rgba(1, 255, 1, 0.3)", evaluate("rgba(1, 256, 1, 0.3)"))
+    assert_equal("rgba(1, 1, 255, 0.3)", evaluate("rgba(1, 1, 256, 0.3)"))
+    assert_equal("rgba(1, 255, 255, 0.3)", evaluate("rgba(1, 256, 257, 0.3)"))
+    assert_equal("rgba(0, 1, 1, 0.3)", evaluate("rgba(-1, 1, 1, 0.3)"))
+    assert_equal("rgba(1, 1, 1, 0)", evaluate("rgba(1, 1, 1, -0.2)"))
+    assert_equal("#010101", evaluate("rgba(1, 1, 1, 1.2)"))
+  end
+
+  def test_rgba_tests_types
+    assert_error_message("$red: \"foo\" is not a number for `rgba'", "rgba(\"foo\", 10, 12, 0.2)");
+    assert_error_message("$green: \"foo\" is not a number for `rgba'", "rgba(10, \"foo\", 12, 0.1)");
+    assert_error_message("$blue: \"foo\" is not a number for `rgba'", "rgba(10, 10, \"foo\", 0)");
+    assert_error_message("$alpha: \"foo\" is not a number for `rgba'", "rgba(10, 10, 10, \"foo\")");
+  end
+
+  def test_rgba_with_color
+    assert_equal "rgba(16, 32, 48, 0.5)", evaluate("rgba(#102030, 0.5)")
+    assert_equal "rgba(0, 0, 255, 0.5)", evaluate("rgba(blue, 0.5)")
+    assert_equal "rgba(0, 0, 255, 0.5)", evaluate("rgba($color: blue, $alpha: 0.5)")
+  end
+
+  def test_rgba_with_color_tests_types
+    assert_error_message("$color: \"foo\" is not a color for `rgba'", "rgba(\"foo\", 0.2)");
+    assert_error_message("$alpha: \"foo\" is not a number for `rgba'", "rgba(blue, \"foo\")");
+  end
+
+  def test_rgba_tests_num_args
+    assert_error_message("wrong number of arguments (0 for 4) for `rgba'", "rgba()");
+    assert_error_message("wrong number of arguments (1 for 4) for `rgba'", "rgba(blue)");
+    assert_error_message("wrong number of arguments (3 for 4) for `rgba'", "rgba(1, 2, 3)");
+    assert_error_message("wrong number of arguments (5 for 4) for `rgba'", "rgba(1, 2, 3, 0.4, 5)");
+  end
+
+  def test_rgba_percent_warning
+    assert_warning(<<WARNING) {evaluate("rgba(1, 2, 3, 40%)")}
+DEPRECATION WARNING: Passing a percentage as the alpha value to rgba() will be
+interpreted differently in future versions of Sass. For now, use 40 instead.
+WARNING
+  end
+
+  def test_rgba_unit_warning
+    assert_warning(<<WARNING) {evaluate("rgba(1, 2, 3, 40em)")}
+DEPRECATION WARNING: Passing a number with units as the alpha value to rgba() is
+deprecated and will be an error in future versions of Sass. Use 40 instead.
+WARNING
+  end
+
+  def test_red
+    assert_equal("18", evaluate("red(#123456)"))
+    assert_equal("18", evaluate("red($color: #123456)"))
+  end
+
+  def test_red_exception
+    assert_error_message("$color: 12 is not a color for `red'", "red(12)")
+  end
+
+  def test_green
+    assert_equal("52", evaluate("green(#123456)"))
+    assert_equal("52", evaluate("green($color: #123456)"))
+  end
+
+  def test_green_exception
+    assert_error_message("$color: 12 is not a color for `green'", "green(12)")
+  end
+
+  def test_blue
+    assert_equal("86", evaluate("blue(#123456)"))
+    assert_equal("86", evaluate("blue($color: #123456)"))
+  end
+
+  def test_blue_exception
+    assert_error_message("$color: 12 is not a color for `blue'", "blue(12)")
+  end
+
+  def test_hue
+    assert_equal("18deg", evaluate("hue(hsl(18, 50%, 20%))"))
+    assert_equal("18deg", evaluate("hue($color: hsl(18, 50%, 20%))"))
+  end
+
+  def test_hue_exception
+    assert_error_message("$color: 12 is not a color for `hue'", "hue(12)")
+  end
+
+  def test_saturation
+    assert_equal("52%", evaluate("saturation(hsl(20, 52%, 20%))"))
+    assert_equal("52%", evaluate("saturation(hsl(20, 52, 20%))"))
+    assert_equal("52%", evaluate("saturation($color: hsl(20, 52, 20%))"))
+  end
+
+  def test_saturation_exception
+    assert_error_message("$color: 12 is not a color for `saturation'", "saturation(12)")
+  end
+
+  def test_lightness
+    assert_equal("86%", evaluate("lightness(hsl(120, 50%, 86%))"))
+    assert_equal("86%", evaluate("lightness(hsl(120, 50%, 86))"))
+    assert_equal("86%", evaluate("lightness($color: hsl(120, 50%, 86))"))
+  end
+
+  def test_lightness_exception
+    assert_error_message("$color: 12 is not a color for `lightness'", "lightness(12)")
+  end
+
+  def test_alpha
+    assert_equal("1", evaluate("alpha(#123456)"))
+    assert_equal("0.34", evaluate("alpha(rgba(0, 1, 2, 0.34))"))
+    assert_equal("0", evaluate("alpha(hsla(0, 1, 2, 0))"))
+    assert_equal("0", evaluate("alpha($color: hsla(0, 1, 2, 0))"))
+  end
+
+  def test_alpha_exception
+    assert_error_message("$color: 12 is not a color for `alpha'", "alpha(12)")
+  end
+
+  def test_opacity
+    assert_equal("1", evaluate("opacity(#123456)"))
+    assert_equal("0.34", evaluate("opacity(rgba(0, 1, 2, 0.34))"))
+    assert_equal("0", evaluate("opacity(hsla(0, 1, 2, 0))"))
+    assert_equal("0", evaluate("opacity($color: hsla(0, 1, 2, 0))"))
+    assert_equal("opacity(20%)", evaluate("opacity(20%)"))
+  end
+
+  def test_opacity_exception
+    assert_error_message("$color: \"foo\" is not a color for `opacity'", "opacity(foo)")
+  end
+
+  def test_opacify
+    assert_equal("rgba(0, 0, 0, 0.75)", evaluate("opacify(rgba(0, 0, 0, 0.5), 0.25)"))
+    assert_equal("rgba(0, 0, 0, 0.3)", evaluate("opacify(rgba(0, 0, 0, 0.2), 0.1)"))
+    assert_equal("rgba(0, 0, 0, 0.7)", evaluate("fade-in(rgba(0, 0, 0, 0.2), 0.5px)"))
+    assert_equal("black", evaluate("fade_in(rgba(0, 0, 0, 0.2), 0.8)"))
+    assert_equal("black", evaluate("opacify(rgba(0, 0, 0, 0.2), 1)"))
+    assert_equal("rgba(0, 0, 0, 0.2)", evaluate("opacify(rgba(0, 0, 0, 0.2), 0%)"))
+    assert_equal("rgba(0, 0, 0, 0.2)", evaluate("opacify($color: rgba(0, 0, 0, 0.2), $amount: 0%)"))
+    assert_equal("rgba(0, 0, 0, 0.2)", evaluate("fade-in($color: rgba(0, 0, 0, 0.2), $amount: 0%)"))
+  end
+
+  def test_opacify_tests_bounds
+    assert_error_message("Amount -0.001 must be between 0 and 1 for `opacify'",
+      "opacify(rgba(0, 0, 0, 0.2), -0.001)")
+    assert_error_message("Amount 1.001 must be between 0 and 1 for `opacify'",
+      "opacify(rgba(0, 0, 0, 0.2), 1.001)")
+  end
+
+  def test_opacify_tests_types
+    assert_error_message("$color: \"foo\" is not a color for `opacify'", "opacify(\"foo\", 10%)")
+    assert_error_message("$amount: \"foo\" is not a number for `opacify'", "opacify(#fff, \"foo\")")
+  end
+
+  def test_transparentize
+    assert_equal("rgba(0, 0, 0, 0.3)", evaluate("transparentize(rgba(0, 0, 0, 0.5), 0.2)"))
+    assert_equal("rgba(0, 0, 0, 0.1)", evaluate("transparentize(rgba(0, 0, 0, 0.2), 0.1)"))
+    assert_equal("rgba(0, 0, 0, 0.2)", evaluate("fade-out(rgba(0, 0, 0, 0.5), 0.3px)"))
+    assert_equal("transparent", evaluate("fade_out(rgba(0, 0, 0, 0.2), 0.2)"))
+    assert_equal("transparent", evaluate("transparentize(rgba(0, 0, 0, 0.2), 1)"))
+    assert_equal("rgba(0, 0, 0, 0.2)", evaluate("transparentize(rgba(0, 0, 0, 0.2), 0)"))
+    assert_equal("rgba(0, 0, 0, 0.2)", evaluate("transparentize($color: rgba(0, 0, 0, 0.2), $amount: 0)"))
+    assert_equal("rgba(0, 0, 0, 0.2)", evaluate("fade-out($color: rgba(0, 0, 0, 0.2), $amount: 0)"))
+  end
+
+  def test_transparentize_tests_bounds
+    assert_error_message("Amount -0.001 must be between 0 and 1 for `transparentize'",
+      "transparentize(rgba(0, 0, 0, 0.2), -0.001)")
+    assert_error_message("Amount 1.001 must be between 0 and 1 for `transparentize'",
+      "transparentize(rgba(0, 0, 0, 0.2), 1.001)")
+  end
+
+  def test_transparentize_tests_types
+    assert_error_message("$color: \"foo\" is not a color for `transparentize'", "transparentize(\"foo\", 
10%)")
+    assert_error_message("$amount: \"foo\" is not a number for `transparentize'", "transparentize(#fff, 
\"foo\")")
+  end
+
+  def test_lighten
+    assert_equal("#4d4d4d", evaluate("lighten(hsl(0, 0, 0), 30%)"))
+    assert_equal("#ee0000", evaluate("lighten(#800, 20%)"))
+    assert_equal("white", evaluate("lighten(#fff, 20%)"))
+    assert_equal("white", evaluate("lighten(#800, 100%)"))
+    assert_equal("#880000", evaluate("lighten(#800, 0%)"))
+    assert_equal("rgba(238, 0, 0, 0.5)", evaluate("lighten(rgba(136, 0, 0, 0.5), 20%)"))
+    assert_equal("rgba(238, 0, 0, 0.5)", evaluate("lighten($color: rgba(136, 0, 0, 0.5), $amount: 20%)"))
+  end
+
+  def test_lighten_tests_bounds
+    assert_error_message("Amount -0.001 must be between 0% and 100% for `lighten'",
+      "lighten(#123, -0.001)")
+    assert_error_message("Amount 100.001 must be between 0% and 100% for `lighten'",
+      "lighten(#123, 100.001)")
+  end
+
+  def test_lighten_tests_types
+    assert_error_message("$color: \"foo\" is not a color for `lighten'", "lighten(\"foo\", 10%)")
+    assert_error_message("$amount: \"foo\" is not a number for `lighten'", "lighten(#fff, \"foo\")")
+  end
+
+  def test_darken
+    assert_equal("#ff6a00", evaluate("darken(hsl(25, 100, 80), 30%)"))
+    assert_equal("#220000", evaluate("darken(#800, 20%)"))
+    assert_equal("black", evaluate("darken(#000, 20%)"))
+    assert_equal("black", evaluate("darken(#800, 100%)"))
+    assert_equal("#880000", evaluate("darken(#800, 0%)"))
+    assert_equal("rgba(34, 0, 0, 0.5)", evaluate("darken(rgba(136, 0, 0, 0.5), 20%)"))
+    assert_equal("rgba(34, 0, 0, 0.5)", evaluate("darken($color: rgba(136, 0, 0, 0.5), $amount: 20%)"))
+  end
+
+  def test_darken_tests_bounds
+    assert_error_message("Amount -0.001 must be between 0% and 100% for `darken'",
+      "darken(#123, -0.001)")
+    assert_error_message("Amount 100.001 must be between 0% and 100% for `darken'",
+      "darken(#123, 100.001)")
+  end
+
+  def test_darken_tests_types
+    assert_error_message("$color: \"foo\" is not a color for `darken'", "darken(\"foo\", 10%)")
+    assert_error_message("$amount: \"foo\" is not a number for `darken'", "darken(#fff, \"foo\")")
+  end
+
+  def test_saturate
+    assert_equal("#d9f2d9", evaluate("saturate(hsl(120, 30, 90), 20%)"))
+    assert_equal("#9e3f3f", evaluate("saturate(#855, 20%)"))
+    assert_equal("black", evaluate("saturate(#000, 20%)"))
+    assert_equal("white", evaluate("saturate(#fff, 20%)"))
+    assert_equal("#33ff33", evaluate("saturate(#8a8, 100%)"))
+    assert_equal("#88aa88", evaluate("saturate(#8a8, 0%)"))
+    assert_equal("rgba(158, 63, 63, 0.5)", evaluate("saturate(rgba(136, 85, 85, 0.5), 20%)"))
+    assert_equal("rgba(158, 63, 63, 0.5)", evaluate("saturate($color: rgba(136, 85, 85, 0.5), $amount: 
20%)"))
+    assert_equal("saturate(50%)", evaluate("saturate(50%)"))
+  end
+
+  def test_saturate_tests_bounds
+    assert_error_message("Amount -0.001 must be between 0% and 100% for `saturate'",
+      "saturate(#123, -0.001)")
+    assert_error_message("Amount 100.001 must be between 0% and 100% for `saturate'",
+      "saturate(#123, 100.001)")
+  end
+
+  def test_saturate_tests_types
+    assert_error_message("$color: \"foo\" is not a color for `saturate'", "saturate(\"foo\", 10%)")
+    assert_error_message("$amount: \"foo\" is not a number for `saturate'", "saturate(#fff, \"foo\")")
+  end
+
+  def test_desaturate
+    assert_equal("#e3e8e3", evaluate("desaturate(hsl(120, 30, 90), 20%)"))
+    assert_equal("#726b6b", evaluate("desaturate(#855, 20%)"))
+    assert_equal("black", evaluate("desaturate(#000, 20%)"))
+    assert_equal("white", evaluate("desaturate(#fff, 20%)"))
+    assert_equal("#999999", evaluate("desaturate(#8a8, 100%)"))
+    assert_equal("#88aa88", evaluate("desaturate(#8a8, 0%)"))
+    assert_equal("rgba(114, 107, 107, 0.5)", evaluate("desaturate(rgba(136, 85, 85, 0.5), 20%)"))
+    assert_equal("rgba(114, 107, 107, 0.5)", evaluate("desaturate($color: rgba(136, 85, 85, 0.5), $amount: 
20%)"))
+  end
+
+  def test_desaturate_tests_bounds
+    assert_error_message("Amount -0.001 must be between 0% and 100% for `desaturate'",
+      "desaturate(#123, -0.001)")
+    assert_error_message("Amount 100.001 must be between 0% and 100% for `desaturate'",
+      "desaturate(#123, 100.001)")
+  end
+
+  def test_desaturate_tests_types
+    assert_error_message("$color: \"foo\" is not a color for `desaturate'", "desaturate(\"foo\", 10%)")
+    assert_error_message("$amount: \"foo\" is not a number for `desaturate'", "desaturate(#fff, \"foo\")")
+  end
+
+  def test_adjust_hue
+    assert_equal("#deeded", evaluate("adjust-hue(hsl(120, 30, 90), 60deg)"))
+    assert_equal("#ededde", evaluate("adjust-hue(hsl(120, 30, 90), -60deg)"))
+    assert_equal("#886a11", evaluate("adjust-hue(#811, 45deg)"))
+    assert_equal("black", evaluate("adjust-hue(#000, 45deg)"))
+    assert_equal("white", evaluate("adjust-hue(#fff, 45deg)"))
+    assert_equal("#88aa88", evaluate("adjust-hue(#8a8, 360deg)"))
+    assert_equal("#88aa88", evaluate("adjust-hue(#8a8, 0deg)"))
+    assert_equal("rgba(136, 106, 17, 0.5)", evaluate("adjust-hue(rgba(136, 17, 17, 0.5), 45deg)"))
+    assert_equal("rgba(136, 106, 17, 0.5)", evaluate("adjust-hue($color: rgba(136, 17, 17, 0.5), $degrees: 
45deg)"))
+  end
+
+  def test_adjust_hue_tests_types
+    assert_error_message("$color: \"foo\" is not a color for `adjust-hue'", "adjust-hue(\"foo\", 10%)")
+    assert_error_message("$degrees: \"foo\" is not a number for `adjust-hue'", "adjust-hue(#fff, \"foo\")")
+  end
+
+  def test_adjust_color
+    # HSL
+    assert_equal(evaluate("hsl(180, 30, 90)"),
+      evaluate("adjust-color(hsl(120, 30, 90), $hue: 60deg)"))
+    assert_equal(evaluate("hsl(120, 50, 90)"),
+      evaluate("adjust-color(hsl(120, 30, 90), $saturation: 20%)"))
+    assert_equal(evaluate("hsl(120, 30, 60)"),
+      evaluate("adjust-color(hsl(120, 30, 90), $lightness: -30%)"))
+    # RGB
+    assert_equal(evaluate("rgb(15, 20, 30)"),
+      evaluate("adjust-color(rgb(10, 20, 30), $red: 5)"))
+    assert_equal(evaluate("rgb(10, 15, 30)"),
+      evaluate("adjust-color(rgb(10, 20, 30), $green: -5)"))
+    assert_equal(evaluate("rgb(10, 20, 40)"),
+      evaluate("adjust-color(rgb(10, 20, 30), $blue: 10)"))
+    # Alpha
+    assert_equal(evaluate("hsla(120, 30, 90, 0.65)"),
+      evaluate("adjust-color(hsl(120, 30, 90), $alpha: -0.35)"))
+    assert_equal(evaluate("rgba(10, 20, 30, 0.9)"),
+      evaluate("adjust-color(rgba(10, 20, 30, 0.4), $alpha: 0.5)"))
+
+    # HSL composability
+    assert_equal(evaluate("hsl(180, 20, 90)"),
+      evaluate("adjust-color(hsl(120, 30, 90), $hue: 60deg, $saturation: -10%)"))
+    assert_equal(evaluate("hsl(180, 20, 95)"),
+      evaluate("adjust-color(hsl(120, 30, 90), $hue: 60deg, $saturation: -10%, $lightness: 5%)"))
+    assert_equal(evaluate("hsla(120, 20, 95, 0.3)"),
+      evaluate("adjust-color(hsl(120, 30, 90), $saturation: -10%, $lightness: 5%, $alpha: -0.7)"))
+
+    # RGB composability
+    assert_equal(evaluate("rgb(15, 20, 29)"),
+      evaluate("adjust-color(rgb(10, 20, 30), $red: 5, $blue: -1)"))
+    assert_equal(evaluate("rgb(15, 45, 29)"),
+      evaluate("adjust-color(rgb(10, 20, 30), $red: 5, $green: 25, $blue: -1)"))
+    assert_equal(evaluate("rgba(10, 25, 29, 0.7)"),
+      evaluate("adjust-color(rgb(10, 20, 30), $green: 5, $blue: -1, $alpha: -0.3)"))
+
+    # HSL range restriction
+    assert_equal(evaluate("hsl(120, 30, 90)"),
+      evaluate("adjust-color(hsl(120, 30, 90), $hue: 720deg)"))
+    assert_equal(evaluate("hsl(120, 0, 90)"),
+      evaluate("adjust-color(hsl(120, 30, 90), $saturation: -90%)"))
+    assert_equal(evaluate("hsl(120, 30, 100)"),
+      evaluate("adjust-color(hsl(120, 30, 90), $lightness: 30%)"))
+
+    # RGB range restriction
+    assert_equal(evaluate("rgb(255, 20, 30)"),
+      evaluate("adjust-color(rgb(10, 20, 30), $red: 250)"))
+    assert_equal(evaluate("rgb(10, 0, 30)"),
+      evaluate("adjust-color(rgb(10, 20, 30), $green: -30)"))
+    assert_equal(evaluate("rgb(10, 20, 0)"),
+      evaluate("adjust-color(rgb(10, 20, 30), $blue: -40)"))
+  end
+
+  def test_adjust_color_tests_types
+    assert_error_message("$color: \"foo\" is not a color for `adjust-color'", "adjust-color(foo, $hue: 10)")
+    # HSL
+    assert_error_message("$hue: \"foo\" is not a number for `adjust-color'",
+      "adjust-color(blue, $hue: foo)")
+    assert_error_message("$saturation: \"foo\" is not a number for `adjust-color'",
+      "adjust-color(blue, $saturation: foo)")
+    assert_error_message("$lightness: \"foo\" is not a number for `adjust-color'",
+      "adjust-color(blue, $lightness: foo)")
+    # RGB
+    assert_error_message("$red: \"foo\" is not a number for `adjust-color'",
+      "adjust-color(blue, $red: foo)")
+    assert_error_message("$green: \"foo\" is not a number for `adjust-color'",
+      "adjust-color(blue, $green: foo)")
+    assert_error_message("$blue: \"foo\" is not a number for `adjust-color'",
+      "adjust-color(blue, $blue: foo)")
+    # Alpha
+    assert_error_message("$alpha: \"foo\" is not a number for `adjust-color'",
+      "adjust-color(blue, $alpha: foo)")
+  end
+
+  def test_adjust_color_tests_arg_range
+    # HSL
+    assert_error_message("$saturation: Amount 101% must be between -100% and 100% for `adjust-color'",
+      "adjust-color(blue, $saturation: 101%)")
+    assert_error_message("$saturation: Amount -101% must be between -100% and 100% for `adjust-color'",
+      "adjust-color(blue, $saturation: -101%)")
+    assert_error_message("$lightness: Amount 101% must be between -100% and 100% for `adjust-color'",
+      "adjust-color(blue, $lightness: 101%)")
+    assert_error_message("$lightness: Amount -101% must be between -100% and 100% for `adjust-color'",
+      "adjust-color(blue, $lightness: -101%)")
+    # RGB
+    assert_error_message("$red: Amount 256 must be between -255 and 255 for `adjust-color'",
+      "adjust-color(blue, $red: 256)")
+    assert_error_message("$red: Amount -256 must be between -255 and 255 for `adjust-color'",
+      "adjust-color(blue, $red: -256)")
+    assert_error_message("$green: Amount 256 must be between -255 and 255 for `adjust-color'",
+      "adjust-color(blue, $green: 256)")
+    assert_error_message("$green: Amount -256 must be between -255 and 255 for `adjust-color'",
+      "adjust-color(blue, $green: -256)")
+    assert_error_message("$blue: Amount 256 must be between -255 and 255 for `adjust-color'",
+      "adjust-color(blue, $blue: 256)")
+    assert_error_message("$blue: Amount -256 must be between -255 and 255 for `adjust-color'",
+      "adjust-color(blue, $blue: -256)")
+    # Alpha
+    assert_error_message("$alpha: Amount 1.1 must be between -1 and 1 for `adjust-color'",
+      "adjust-color(blue, $alpha: 1.1)")
+    assert_error_message("$alpha: Amount -1.1 must be between -1 and 1 for `adjust-color'",
+      "adjust-color(blue, $alpha: -1.1)")
+  end
+
+  def test_adjust_color_argument_errors
+    assert_error_message("Unknown argument $hoo (260deg) for `adjust-color'",
+      "adjust-color(blue, $hoo: 260deg)")
+    assert_error_message("Cannot specify HSL and RGB values for a color at the same time for `adjust-color'",
+      "adjust-color(blue, $hue: 120deg, $red: 10)");
+    assert_error_message("10px is not a keyword argument for `adjust_color'",
+      "adjust-color(blue, 10px)")
+    assert_error_message("10px is not a keyword argument for `adjust_color'",
+      "adjust-color(blue, 10px, 20px)")
+    assert_error_message("10px is not a keyword argument for `adjust_color'",
+      "adjust-color(blue, 10px, $hue: 180deg)")
+  end
+
+  def test_scale_color
+    # HSL
+    assert_equal(evaluate("hsl(120, 51, 90)"),
+      evaluate("scale-color(hsl(120, 30, 90), $saturation: 30%)"))
+    assert_equal(evaluate("hsl(120, 30, 76.5)"),
+      evaluate("scale-color(hsl(120, 30, 90), $lightness: -15%)"))
+    # RGB
+    assert_equal(evaluate("rgb(157, 20, 30)"),
+      evaluate("scale-color(rgb(10, 20, 30), $red: 60%)"))
+    assert_equal(evaluate("rgb(10, 38.8, 30)"),
+      evaluate("scale-color(rgb(10, 20, 30), $green: 8%)"))
+    assert_equal(evaluate("rgb(10, 20, 20)"),
+      evaluate("scale-color(rgb(10, 20, 30), $blue: -(1/3)*100%)"))
+    # Alpha
+    assert_equal(evaluate("hsla(120, 30, 90, 0.86)"),
+      evaluate("scale-color(hsl(120, 30, 90), $alpha: -14%)"))
+    assert_equal(evaluate("rgba(10, 20, 30, 0.82)"),
+      evaluate("scale-color(rgba(10, 20, 30, 0.8), $alpha: 10%)"))
+
+    # HSL composability
+    assert_equal(evaluate("hsl(120, 51, 76.5)"),
+      evaluate("scale-color(hsl(120, 30, 90), $saturation: 30%, $lightness: -15%)"))
+    assert_equal(evaluate("hsla(120, 51, 90, 0.2)"),
+      evaluate("scale-color(hsl(120, 30, 90), $saturation: 30%, $alpha: -80%)"))
+
+    # RGB composability
+    assert_equal(evaluate("rgb(157, 38.8, 30)"),
+      evaluate("scale-color(rgb(10, 20, 30), $red: 60%, $green: 8%)"))
+    assert_equal(evaluate("rgb(157, 38.8, 20)"),
+      evaluate("scale-color(rgb(10, 20, 30), $red: 60%, $green: 8%, $blue: -(1/3)*100%)"))
+    assert_equal(evaluate("rgba(10, 38.8, 20, 0.55)"),
+      evaluate("scale-color(rgba(10, 20, 30, 0.5), $green: 8%, $blue: -(1/3)*100%, $alpha: 10%)"))
+
+    # Extremes
+    assert_equal(evaluate("hsl(120, 100, 90)"),
+      evaluate("scale-color(hsl(120, 30, 90), $saturation: 100%)"))
+    assert_equal(evaluate("hsl(120, 30, 90)"),
+      evaluate("scale-color(hsl(120, 30, 90), $saturation: 0%)"))
+    assert_equal(evaluate("hsl(120, 0, 90)"),
+      evaluate("scale-color(hsl(120, 30, 90), $saturation: -100%)"))
+  end
+
+  def test_scale_color_tests_types
+    assert_error_message("$color: \"foo\" is not a color for `scale-color'", "scale-color(foo, $red: 10%)")
+    # HSL
+    assert_error_message("$saturation: \"foo\" is not a number for `scale-color'",
+      "scale-color(blue, $saturation: foo)")
+    assert_error_message("$lightness: \"foo\" is not a number for `scale-color'",
+      "scale-color(blue, $lightness: foo)")
+    # RGB
+    assert_error_message("$red: \"foo\" is not a number for `scale-color'",
+      "scale-color(blue, $red: foo)")
+    assert_error_message("$green: \"foo\" is not a number for `scale-color'",
+      "scale-color(blue, $green: foo)")
+    assert_error_message("$blue: \"foo\" is not a number for `scale-color'",
+      "scale-color(blue, $blue: foo)")
+    # Alpha
+    assert_error_message("$alpha: \"foo\" is not a number for `scale-color'",
+      "scale-color(blue, $alpha: foo)")
+  end
+
+  def test_scale_color_argument_errors
+    # Range
+    assert_error_message("$saturation: Amount 101% must be between -100% and 100% for `scale-color'",
+      "scale-color(blue, $saturation: 101%)")
+    assert_error_message("$red: Amount -101% must be between -100% and 100% for `scale-color'",
+      "scale-color(blue, $red: -101%)")
+    assert_error_message("$alpha: Amount -101% must be between -100% and 100% for `scale-color'",
+      "scale-color(blue, $alpha: -101%)")
+
+    # Unit
+    assert_error_message("Expected $saturation to have a unit of % but got 80 for `scale-color'",
+      "scale-color(blue, $saturation: 80)")
+    assert_error_message("Expected $alpha to have a unit of % but got 0.5 for `scale-color'",
+      "scale-color(blue, $alpha: 0.5)")
+
+    # Unknown argument
+    assert_error_message("Unknown argument $hue (80%) for `scale-color'", "scale-color(blue, $hue: 80%)")
+
+    # Non-keyword arg
+    assert_error_message("10px is not a keyword argument for `scale_color'", "scale-color(blue, 10px)")
+
+    # HSL/RGB
+    assert_error_message("Cannot specify HSL and RGB values for a color at the same time for `scale-color'",
+      "scale-color(blue, $lightness: 10%, $red: 20%)");
+  end
+
+  def test_change_color
+    # HSL
+    assert_equal(evaluate("hsl(195, 30, 90)"),
+      evaluate("change-color(hsl(120, 30, 90), $hue: 195deg)"))
+    assert_equal(evaluate("hsl(120, 50, 90)"),
+      evaluate("change-color(hsl(120, 30, 90), $saturation: 50%)"))
+    assert_equal(evaluate("hsl(120, 30, 40)"),
+      evaluate("change-color(hsl(120, 30, 90), $lightness: 40%)"))
+    # RGB
+    assert_equal(evaluate("rgb(123, 20, 30)"),
+      evaluate("change-color(rgb(10, 20, 30), $red: 123)"))
+    assert_equal(evaluate("rgb(10, 234, 30)"),
+      evaluate("change-color(rgb(10, 20, 30), $green: 234)"))
+    assert_equal(evaluate("rgb(10, 20, 198)"),
+      evaluate("change-color(rgb(10, 20, 30), $blue: 198)"))
+    # Alpha
+    assert_equal(evaluate("rgba(10, 20, 30, 0.76)"),
+      evaluate("change-color(rgb(10, 20, 30), $alpha: 0.76)"))
+
+    # HSL composability
+    assert_equal(evaluate("hsl(56, 30, 47)"),
+      evaluate("change-color(hsl(120, 30, 90), $hue: 56deg, $lightness: 47%)"))
+    assert_equal(evaluate("hsla(56, 30, 47, 0.9)"),
+      evaluate("change-color(hsl(120, 30, 90), $hue: 56deg, $lightness: 47%, $alpha: 0.9)"))
+  end
+
+  def test_change_color_tests_types
+    assert_error_message("$color: \"foo\" is not a color for `change-color'", "change-color(foo, $red: 10%)")
+    # HSL
+    assert_error_message("$saturation: \"foo\" is not a number for `change-color'",
+      "change-color(blue, $saturation: foo)")
+    assert_error_message("$lightness: \"foo\" is not a number for `change-color'",
+      "change-color(blue, $lightness: foo)")
+    # RGB
+    assert_error_message("$red: \"foo\" is not a number for `change-color'", "change-color(blue, $red: foo)")
+    assert_error_message("$green: \"foo\" is not a number for `change-color'", "change-color(blue, $green: 
foo)")
+    assert_error_message("$blue: \"foo\" is not a number for `change-color'", "change-color(blue, $blue: 
foo)")
+    # Alpha
+    assert_error_message("$alpha: \"foo\" is not a number for `change-color'", "change-color(blue, $alpha: 
foo)")
+  end
+
+  def test_change_color_argument_errors
+    # Range
+    assert_error_message("Saturation 101% must be between 0% and 100% for `change-color'",
+      "change-color(blue, $saturation: 101%)")
+    assert_error_message("Lightness 101% must be between 0% and 100% for `change-color'",
+      "change-color(blue, $lightness: 101%)")
+    assert_error_message("Red value -1 must be between 0 and 255 for `change-color'",
+      "change-color(blue, $red: -1)")
+    assert_error_message("Green value 256 must be between 0 and 255 for `change-color'",
+      "change-color(blue, $green: 256)")
+    assert_error_message("Blue value 500 must be between 0 and 255 for `change-color'",
+      "change-color(blue, $blue: 500)")
+
+    # Unknown argument
+    assert_error_message("Unknown argument $hoo (80%) for `change-color'", "change-color(blue, $hoo: 80%)")
+
+    # Non-keyword arg
+    assert_error_message("10px is not a keyword argument for `change_color'", "change-color(blue, 10px)")
+
+    # HSL/RGB
+    assert_error_message("Cannot specify HSL and RGB values for a color at the same time for `change-color'",
+      "change-color(blue, $lightness: 10%, $red: 120)");
+  end
+
+  def test_ie_hex_str
+    assert_equal("#FFAA11CC", evaluate('ie-hex-str(#aa11cc)'))
+    assert_equal("#FFAA11CC", evaluate('ie-hex-str(#a1c)'))
+    assert_equal("#FFAA11CC", evaluate('ie-hex-str(#A1c)'))
+    assert_equal("#80FF0000", evaluate('ie-hex-str(rgba(255, 0, 0, 0.5))'))
+  end
+
+  def test_mix
+    assert_equal("#7f007f", evaluate("mix(#f00, #00f)"))
+    assert_equal("#7f7f7f", evaluate("mix(#f00, #0ff)"))
+    assert_equal("#7f9055", evaluate("mix(#f70, #0aa)"))
+    assert_equal("#3f00bf", evaluate("mix(#f00, #00f, 25%)"))
+    assert_equal("rgba(63, 0, 191, 0.75)", evaluate("mix(rgba(255, 0, 0, 0.5), #00f)"))
+    assert_equal("red", evaluate("mix(#f00, #00f, 100%)"))
+    assert_equal("blue", evaluate("mix(#f00, #00f, 0%)"))
+    assert_equal("rgba(255, 0, 0, 0.5)", evaluate("mix(#f00, transparentize(#00f, 1))"))
+    assert_equal("rgba(0, 0, 255, 0.5)", evaluate("mix(transparentize(#f00, 1), #00f)"))
+    assert_equal("red", evaluate("mix(#f00, transparentize(#00f, 1), 100%)"))
+    assert_equal("blue", evaluate("mix(transparentize(#f00, 1), #00f, 0%)"))
+    assert_equal("rgba(0, 0, 255, 0)", evaluate("mix(#f00, transparentize(#00f, 1), 0%)"))
+    assert_equal("rgba(255, 0, 0, 0)", evaluate("mix(transparentize(#f00, 1), #00f, 100%)"))
+    assert_equal("rgba(255, 0, 0, 0)", evaluate("mix($color1: transparentize(#f00, 1), $color2: #00f, 
$weight: 100%)"))
+  end
+
+  def test_mix_tests_types
+    assert_error_message("$color1: \"foo\" is not a color for `mix'", "mix(\"foo\", #f00, 10%)")
+    assert_error_message("$color2: \"foo\" is not a color for `mix'", "mix(#f00, \"foo\", 10%)")
+    assert_error_message("$weight: \"foo\" is not a number for `mix'", "mix(#f00, #baf, \"foo\")")
+  end
+
+  def test_mix_tests_bounds
+    assert_error_message("Weight -0.001 must be between 0% and 100% for `mix'",
+      "mix(#123, #456, -0.001)")
+    assert_error_message("Weight 100.001 must be between 0% and 100% for `mix'",
+      "mix(#123, #456, 100.001)")
+  end
+
+  def test_grayscale
+    assert_equal("#bbbbbb", evaluate("grayscale(#abc)"))
+    assert_equal("gray", evaluate("grayscale(#f00)"))
+    assert_equal("gray", evaluate("grayscale(#00f)"))
+    assert_equal("white", evaluate("grayscale(white)"))
+    assert_equal("black", evaluate("grayscale(black)"))
+    assert_equal("black", evaluate("grayscale($color: black)"))
+
+    assert_equal("grayscale(2)", evaluate("grayscale(2)"))
+    assert_equal("grayscale(-5px)", evaluate("grayscale(-5px)"))
+  end
+
+  def tets_grayscale_tests_types
+    assert_error_message("$color: \"foo\" is not a color for `grayscale'", "grayscale(\"foo\")")
+  end
+
+  def test_complement
+    assert_equal("#ccbbaa", evaluate("complement(#abc)"))
+    assert_equal("cyan", evaluate("complement(red)"))
+    assert_equal("red", evaluate("complement(cyan)"))
+    assert_equal("white", evaluate("complement(white)"))
+    assert_equal("black", evaluate("complement(black)"))
+    assert_equal("black", evaluate("complement($color: black)"))
+  end
+
+  def tets_complement_tests_types
+    assert_error_message("$color: \"foo\" is not a color for `complement'", "complement(\"foo\")")
+  end
+
+  def test_invert
+    assert_equal("#112233", evaluate("invert(#edc)"))
+    assert_equal("rgba(245, 235, 225, 0.5)", evaluate("invert(rgba(10, 20, 30, 0.5))"))
+    assert_equal("invert(20%)", evaluate("invert(20%)"))
+  end
+
+  def test_invert_tests_types
+    assert_error_message("$color: \"foo\" is not a color for `invert'", "invert(\"foo\")")
+  end
+
+  def test_unquote
+    assert_equal('foo', evaluate('unquote("foo")'))
+    assert_equal('foo', evaluate('unquote(foo)'))
+    assert_equal('foo', evaluate('unquote($string: foo)'))
+  end
+
+  def test_quote
+    assert_equal('"foo"', evaluate('quote(foo)'))
+    assert_equal('"foo"', evaluate('quote("foo")'))
+    assert_equal('"foo"', evaluate('quote($string: "foo")'))
+  end
+
+  def test_quote_tests_type
+    assert_error_message("$string: #ff0000 is not a string for `quote'", "quote(#f00)")
+  end
+
+  def test_str_length
+    assert_equal('3', evaluate('str-length(foo)'))
+  end
+
+  def test_str_length_requires_a_string
+    assert_error_message("$string: #ff0000 is not a string for `str-length'", "str-length(#f00)")
+  end
+
+  def test_str_insert
+    assert_equal('Xabcd', evaluate('str-insert(abcd, X, 0)'))
+    assert_equal('Xabcd', evaluate('str-insert(abcd, X, 1)'))
+    assert_equal('abcXd', evaluate('str-insert(abcd, X, 4)'))
+    assert_equal('abcdX', evaluate('str-insert(abcd, X, 100)'))
+    assert_equal('Xabcd', evaluate('str-insert(abcd, X, -100)'))
+    assert_equal('aXbcd', evaluate('str-insert(abcd, X, -4)'))
+    assert_equal('abcdX', evaluate('str-insert(abcd, X, -1)'))
+  end
+
+  def test_str_insert_maintains_quote_of_primary_string
+    assert_equal('"Xfoo"', evaluate('str-insert("foo", X, 1)'))
+    assert_equal('"Xfoo"', evaluate('str-insert("foo", "X", 1)'))
+    assert_equal('Xfoo', evaluate('str-insert(foo, "X", 1)'))
+  end
+
+  def test_str_insert_asserts_types
+    assert_error_message("$string: #ff0000 is not a string for `str-insert'", "str-insert(#f00, X, 1)")
+    assert_error_message("$insert: #ff0000 is not a string for `str-insert'", "str-insert(foo, #f00, 1)")
+    assert_error_message("$index: #ff0000 is not a number for `str-insert'", "str-insert(foo, X, #f00)")
+    assert_error_message("Expected $index to be unitless but got 10px for `str-insert'", "str-insert(foo, X, 
10px)")
+  end
+
+  def test_str_index
+    assert_equal('1', evaluate('str-index(abcd, a)'))
+    assert_equal('1', evaluate('str-index(abcd, ab)'))
+    assert_equal(Sass::Script::Value::Null.new, perform('str-index(abcd, X)'))
+    assert_equal('3', evaluate('str-index(abcd, c)'))
+  end
+
+  def test_str_index_asserts_types
+    assert_error_message("$string: #ff0000 is not a string for `str-index'", "str-index(#f00, X)")
+    assert_error_message("$substring: #ff0000 is not a string for `str-index'", "str-index(asdf, #f00)")
+  end
+
+  def test_to_lower_case
+    assert_equal('abcd', evaluate('to-lower-case(ABCD)'))
+    assert_equal('"abcd"', evaluate('to-lower-case("ABCD")'))
+    assert_error_message("$string: #ff0000 is not a string for `to-lower-case'", "to-lower-case(#f00)")
+  end
+
+  def test_to_upper_case
+    assert_equal('ABCD', evaluate('to-upper-case(abcd)'))
+    assert_equal('"ABCD"', evaluate('to-upper-case("abcd")'))
+    assert_error_message("$string: #ff0000 is not a string for `to-upper-case'", "to-upper-case(#f00)")
+  end
+
+  def test_str_slice
+    assert_equal('bc',   evaluate('str-slice(abcd,2,3)'))    # in the middle of the string
+    assert_equal('a',    evaluate('str-slice(abcd,1,1)'))    # when start = end
+    assert_equal('ab',   evaluate('str-slice(abcd,1,2)'))    # for completeness
+    assert_equal('abcd', evaluate('str-slice(abcd,1,4)'))    # at the end points
+    assert_equal('abcd', evaluate('str-slice(abcd,0,4)'))    # when start is before the start of the string
+    assert_equal('',     evaluate('str-slice(abcd,1,0)'))    # when end is before the start of the string
+    assert_equal('abcd', evaluate('str-slice(abcd,1,100)'))  # when end is past the end of the string
+    assert_equal('',     evaluate('str-slice(abcd,2,1)'))    # when end is before start
+    assert_equal('"bc"', evaluate('str-slice("abcd",2,3)'))  # when used with a quoted string
+    assert_equal('bcd',  evaluate('str-slice(abcd,2)'))      # when end is omitted, you get the remainder of 
the string
+    assert_equal('cd',   evaluate('str-slice(abcd,-2)'))     # when start is negative, it counts from the 
beginning
+    assert_equal('bc',   evaluate('str-slice(abcd,2,-2)'))   # when end is negative it counts in from the end
+    assert_equal('',     evaluate('str-slice(abcd,3,-3)'))   # when end is negative and comes before the 
start
+    assert_equal('bc',   evaluate('str-slice(abcd,-3,-2)'))  # when both are negative
+    assert_error_message("$string: #ff0000 is not a string for `str-slice'", "str-slice(#f00,2,3)")
+    assert_error_message("$start-at: #ff0000 is not a number for `str-slice'", "str-slice(abcd,#f00,3)")
+    assert_error_message("$end-at: #ff0000 is not a number for `str-slice'", "str-slice(abcd,2,#f00)")
+    assert_error_message("Expected $end-at to be unitless but got 3px for `str-slice'", 
"str-slice(abcd,2,3px)")
+    assert_error_message("Expected $start-at to be unitless but got 2px for `str-slice'", 
"str-slice(abcd,2px,3)")
+  end
+
+  def test_user_defined_function
+    assert_equal("I'm a user-defined string!", evaluate("user_defined()"))
+  end
+
+  def test_user_defined_function_with_preceding_underscore
+    assert_equal("I'm another user-defined string!", evaluate("_preceding_underscore()"))
+    assert_equal("I'm another user-defined string!", evaluate("-preceding-underscore()"))
+  end
+
+  def test_user_defined_function_using_environment
+    environment = env('variable' => Sass::Script::Value::String.new('The variable'))
+    assert_equal("The variable", evaluate("fetch_the_variable()", environment))
+  end
+
+  def test_options_on_new_values_fails
+    assert_error_message(<<MSG, "call-options-on-new-value()")
+The #options attribute is not set on this Sass::Script::Value::String.
+  This error is probably occurring because #to_s was called
+  on this value within a custom Sass function without first
+  setting the #options attribute.
+MSG
+  end
+
+  def test_type_of
+    assert_equal("string", evaluate("type-of(\"asdf\")"))
+    assert_equal("string", evaluate("type-of(asdf)"))
+    assert_equal("number", evaluate("type-of(1px)"))
+    assert_equal("bool", evaluate("type-of(true)"))
+    assert_equal("color", evaluate("type-of(#fff)"))
+    assert_equal("color", evaluate("type-of($value: #fff)"))
+    assert_equal("null", evaluate("type-of(null)"))
+    assert_equal("list", evaluate("type-of(1 2 3)"))
+    assert_equal("list", evaluate("type-of((1, 2, 3))"))
+    assert_equal("list", evaluate("type-of(())"))
+    assert_equal("map", evaluate("type-of((foo: bar))"))
+  end
+
+  def test_feature_exists
+    assert_raises ArgumentError do
+      Sass.add_feature("my-test-feature")
+    end
+    Sass.add_feature("-my-test-feature")
+    assert_equal("true", evaluate("feature-exists(-my-test-feature)"))
+    assert_equal("false", evaluate("feature-exists(whatisthisidontevenknow)"))
+    assert_equal("true", evaluate("feature-exists($feature: -my-test-feature)"))
+  ensure
+    Sass::Features::KNOWN_FEATURES.delete("-my-test-feature")
+  end
+
+  def test_unit
+    assert_equal(%Q{""}, evaluate("unit(100)"))
+    assert_equal(%Q{"px"}, evaluate("unit(100px)"))
+    assert_equal(%Q{"em*px"}, evaluate("unit(10px * 5em)"))
+    assert_equal(%Q{"em*px"}, evaluate("unit(5em * 10px)"))
+    assert_equal(%Q{"em/rem"}, evaluate("unit(10px * 5em / 30cm / 1rem)"))
+    assert_equal(%Q{"em*vh/cm*rem"}, evaluate("unit(10vh * 5em / 30cm / 1rem)"))
+    assert_equal(%Q{"px"}, evaluate("unit($number: 100px)"))
+    assert_error_message("$number: #ff0000 is not a number for `unit'", "unit(#f00)")
+  end
+
+  def test_unitless
+    assert_equal(%Q{true}, evaluate("unitless(100)"))
+    assert_equal(%Q{false}, evaluate("unitless(100px)"))
+    assert_equal(%Q{false}, evaluate("unitless($number: 100px)"))
+    assert_error_message("$number: #ff0000 is not a number for `unitless'", "unitless(#f00)")
+  end
+
+  def test_comparable
+    assert_equal(%Q{true}, evaluate("comparable(2px, 1px)"))
+    assert_equal(%Q{true}, evaluate("comparable(10cm, 3mm)"))
+    assert_equal(%Q{false}, evaluate("comparable(100px, 3em)"))
+    assert_equal(%Q{false}, evaluate("comparable($number1: 100px, $number2: 3em)"))
+  end
+
+  def test_comparable_checks_types
+    assert_error_message("$number1: #ff0000 is not a number for `comparable'", "comparable(#f00, 1px)")
+    assert_error_message("$number2: #ff0000 is not a number for `comparable'", "comparable(1px, #f00)")
+  end
+
+  def test_length
+    assert_equal("5", evaluate("length(1 2 3 4 5)"))
+    assert_equal("4", evaluate("length((foo, bar, baz, bip))"))
+    assert_equal("3", evaluate("length((foo, bar, baz bip))"))
+    assert_equal("3", evaluate("length((foo, bar, (baz, bip)))"))
+    assert_equal("1", evaluate("length(#f00)"))
+    assert_equal("0", evaluate("length(())"))
+    assert_equal("4", evaluate("length(1 2 () 3)"))
+
+    assert_equal("2", evaluate("length((foo: bar, bar: baz))"))
+  end
+
+  def test_nth
+    assert_equal("1", evaluate("nth(1 2 3, 1)"))
+    assert_equal("2", evaluate("nth(1 2 3, 2)"))
+    assert_equal("3", evaluate("nth(1 2 3, -1)"))
+    assert_equal("1", evaluate("nth(1 2 3, -3)"))
+    assert_equal("3", evaluate("nth((1, 2, 3), 3)"))
+    assert_equal("3", evaluate("nth($list: (1, 2, 3), $n: 3)"))
+    assert_equal("foo", evaluate("nth(foo, 1)"))
+    assert_equal("bar baz", evaluate("nth(foo (bar baz) bang, 2)"))
+    assert_error_message("List index 0 must be a non-zero integer for `nth'", "nth(foo, 0)")
+    assert_error_message("List index is -10 but list is only 1 item long for `nth'", "nth(foo, -10)")
+    assert_error_message("List index 1.5 must be a non-zero integer for `nth'", "nth(foo, 1.5)")
+    assert_error_message("List index is 5 but list is only 4 items long for `nth'", "nth(1 2 3 4, 5)")
+    assert_error_message("List index is 2 but list is only 1 item long for `nth'", "nth(foo, 2)")
+    assert_error_message("List index is 1 but list has no items for `nth'", "nth((), 1)")
+    assert_error_message("$n: \"foo\" is not a number for `nth'", "nth(1 2 3, foo)")
+
+    assert_equal("foo bar", evaluate("nth((foo: bar, bar: baz), 1)"))
+    assert_equal("bar baz", evaluate("nth((foo: bar, bar: baz), 2)"))
+  end
+
+  def test_set_nth
+    assert_equal("a 2 3", evaluate("set-nth(1 2 3, 1, a)"))
+    assert_equal("1 a 3", evaluate("set-nth(1 2 3, 2, a)"))
+    assert_equal("1 2 a", evaluate("set-nth(1 2 3, -1, a)"))
+    assert_equal("a 2 3", evaluate("set-nth(1 2 3, -3, a)"))
+    assert_equal("a 2 3", evaluate("set-nth($list: 1 2 3, $n: -3, $value: a)"))
+    assert_equal("1, 2, a", evaluate("set-nth((1, 2, 3), 3, a)"))
+    assert_equal("a", evaluate("set-nth(foo, 1, a)"))
+    assert_equal("foo, a b, baz", evaluate("set-nth((foo, bar, baz), 2, (a b))"))
+    assert_error_message("List index 0 must be a non-zero integer for `set-nth'", "set-nth(foo, 0, a)")
+    assert_error_message("List index is -10 but list is only 1 item long for `set-nth'", "set-nth(foo, -10, 
a)")
+    assert_error_message("List index 1.5 must be a non-zero integer for `set-nth'", "set-nth(foo, 1.5, a)")
+    assert_error_message("List index is 5 but list is only 4 items long for `set-nth'", "set-nth(1 2 3 4, 5, 
a)")
+    assert_error_message("List index is 2 but list is only 1 item long for `set-nth'", "set-nth(foo, 2, a)")
+    assert_error_message("List index is 1 but list has no items for `set-nth'", "set-nth((), 1, a)")
+    assert_error_message("$n: \"foo\" is not a number for `set-nth'", "set-nth(1 2 3, foo, a)")
+  end
+
+  def test_join
+    assert_equal("1 2 3", evaluate("join(1 2, 3)"))
+    assert_equal("1 2 3", evaluate("join(1, 2 3)"))
+    assert_equal("1 2 3 4", evaluate("join(1 2, 3 4)"))
+    assert_equal("true", evaluate("(1 2 3 4) == join(1 2, 3 4)"))
+    assert_equal("false", evaluate("(1 2 (3 4)) == join(1 2, 3 4)"))
+    assert_equal("1, 2, 3", evaluate("join((1, 2), 3)"))
+    assert_equal("1, 2, 3", evaluate("join(1, (2, 3))"))
+    assert_equal("1, 2, 3, 4", evaluate("join((1, 2), (3, 4))"))
+    assert_equal("true", evaluate("(1, 2, 3, 4) == join((1, 2), (3, 4))"))
+    assert_equal("false", evaluate("(1, 2, (3, 4)) == join((1, 2), (3, 4))"))
+
+    assert_equal("1 2", evaluate("join(1, 2)"))
+    assert_equal("1 2 3 4", evaluate("join(1 2, (3, 4))"))
+    assert_equal("1, 2, 3, 4", evaluate("join((1, 2), 3 4)"))
+
+    assert_equal("1 2", evaluate("join(1, 2, auto)"))
+    assert_equal("1, 2, 3, 4", evaluate("join(1 2, 3 4, comma)"))
+    assert_equal("1 2 3 4", evaluate("join((1, 2), (3, 4), space)"))
+    assert_equal("1, 2", evaluate("join(1, 2, comma)"))
+
+    assert_equal("1 2", evaluate("join(1 2, ())"))
+    assert_equal("1, 2", evaluate("join((1, 2), ())"))
+    assert_equal("true", evaluate("(1 2) == join(1 2, ())"))
+    assert_equal("true", evaluate("(1, 2) == join((1, 2), ())"))
+    assert_equal("false", evaluate("(1 2 ()) == join(1 2, ())"))
+    assert_equal("false", evaluate("(1, 2, ()) == join((1, 2), ())"))
+
+    assert_equal("1 2", evaluate("join((), 1 2)"))
+    assert_equal("1, 2", evaluate("join((), (1, 2))"))
+    assert_equal("true", evaluate("(1 2) == join((), 1 2)"))
+    assert_equal("true", evaluate("(1, 2) == join((), (1, 2))"))
+    assert_equal("false", evaluate("(1 2 ()) == join((), 1 2)"))
+    assert_equal("false", evaluate("(1, 2, ()) == join((), (1, 2))"))
+
+    assert_error_message("Separator name must be space, comma, or auto for `join'", "join(1, 2, baboon)")
+    assert_error_message("$separator: 12 is not a string for `join'", "join(1, 2, 12)")
+
+    assert_equal("foo bar, bar baz, baz bip, bip bop",
+      perform("join((foo: bar, bar: baz), (baz: bip, bip: bop))").to_sass)
+    assert_equal("(foo bar) (bar baz) (baz bip) (bip bop)",
+      perform("join((foo: bar, bar: baz), (baz: bip, bip: bop), space)").to_sass)
+    assert_equal("foo bar (baz bip) (bip bop)",
+      perform("join(foo bar, (baz: bip, bip: bop))").to_sass)
+    assert_equal("foo bar, bar baz, bip, bop",
+      perform("join((foo: bar, bar: baz), bip bop)").to_sass)
+    assert_equal("baz bip, bip bop",
+      perform("join((), (baz: bip, bip: bop))").to_sass)
+    assert_equal("foo bar, bar baz",
+      perform("join((foo: bar, bar: baz), ())").to_sass)
+  end
+
+  def test_append
+    assert_equal("1 2 3", evaluate("append(1 2, 3)"))
+    assert_equal("1 2 3 4", evaluate("append(1 2, 3 4)"))
+    assert_equal("false", evaluate("(1 2 3 4) == append(1 2, 3 4)"))
+    assert_equal("true", evaluate("(1 2 (3 4)) == append(1 2, 3 4)"))
+    assert_equal("1, 2, 3", evaluate("append((1, 2), 3)"))
+    assert_equal("1, 2, 3, 4", evaluate("append((1, 2), (3, 4))"))
+    assert_equal("false", evaluate("(1, 2, 3, 4) == append((1, 2), (3, 4))"))
+    assert_equal("true", evaluate("(1, 2, (3, 4)) == append((1, 2), (3, 4))"))
+
+    assert_equal("1 2", evaluate("append(1, 2)"))
+    assert_equal("1 2 3, 4", evaluate("append(1 2, (3, 4))"))
+    assert_equal("true", evaluate("(1 2 (3, 4)) == append(1 2, (3, 4))"))
+    assert_equal("1, 2, 3 4", evaluate("append((1, 2), 3 4)"))
+    assert_equal("true", evaluate("(1, 2, 3 4) == append((1, 2), 3 4)"))
+
+    assert_equal("1 2", evaluate("append(1, 2, auto)"))
+    assert_equal("1, 2, 3 4", evaluate("append(1 2, 3 4, comma)"))
+    assert_equal("1 2 3, 4", evaluate("append((1, 2), (3, 4), space)"))
+    assert_equal("1, 2", evaluate("append(1, 2, comma)"))
+
+    assert_equal("1 2", evaluate("append(1 2, ())"))
+    assert_equal("1, 2", evaluate("append((1, 2), ())"))
+    assert_equal("true", evaluate("(1 2 ()) == append(1 2, ())"))
+    assert_equal("true", evaluate("(1, 2, ()) == append((1, 2), ())"))
+
+    assert_equal("1 2", evaluate("append((), 1 2)"))
+    assert_equal("1, 2", evaluate("append((), (1, 2))"))
+    assert_equal("false", evaluate("(1 2) == append((), 1 2)"))
+    assert_equal("true", evaluate("(1 2) == nth(append((), 1 2), 1)"))
+
+    assert_error_message("Separator name must be space, comma, or auto for `append'", "append(1, 2, baboon)")
+    assert_error_message("$separator: 12 is not a string for `append'", "append(1, 2, 12)")
+
+    assert_equal("1 2 (foo: bar)", perform("append(1 2, (foo: bar))").to_sass)
+    assert_equal("foo bar, bar baz, 1", perform("append((foo: bar, bar: baz), 1)").to_sass)
+    assert_equal("foo bar, bar baz, (baz: bip)",
+      perform("append((foo: bar, bar: baz), (baz: bip))").to_sass)
+  end
+
+  def test_zip
+    assert_equal("1 3 5, 2 4 6", evaluate("zip(1 2, 3 4, 5 6)"))
+    assert_equal("1 4 7, 2 5 8", evaluate("zip(1 2 3, 4 5 6, 7 8)"))
+    assert_equal("1 2 3", evaluate("zip(1, 2, 3)"))
+    assert_equal("(foo bar) 1 3, (bar baz) 2 4",
+      perform("zip((foo: bar, bar: baz), 1 2, 3 4)").to_sass)
+  end
+
+  def test_index
+    null = Sass::Script::Value::Null.new
+    assert_equal("1", evaluate("index(1px solid blue, 1px)"))
+    assert_equal("2", evaluate("index(1px solid blue, solid)"))
+    assert_equal("3", evaluate("index(1px solid blue, #00f)"))
+    assert_equal("1", evaluate("index(1px, 1px)"))
+    assert_equal(null, perform("index(1px solid blue, 1em)"))
+    assert_equal(null, perform("index(1px solid blue, notfound)"))
+    assert_equal(null, perform("index(1px, #00f)"))
+
+    assert_equal("1", evaluate("index((foo: bar, bar: baz), (foo bar))"))
+    assert_equal(null, perform("index((foo: bar, bar: baz), (foo: bar))"))
+  end
+
+  def test_list_separator
+    assert_equal("space", evaluate("list-separator(1 2 3 4 5)"))
+    assert_equal("comma", evaluate("list-separator((foo, bar, baz, bip))"))
+    assert_equal("comma", evaluate("list-separator((foo, bar, baz bip))"))
+    assert_equal("comma", evaluate("list-separator((foo, bar, (baz, bip)))"))
+    assert_equal("space", evaluate("list-separator(#f00)"))
+    assert_equal("space", evaluate("list-separator(())"))
+    assert_equal("space", evaluate("list-separator(1 2 () 3)"))
+
+    assert_equal("comma", evaluate("list-separator((foo: bar, bar: baz))"))
+  end
+
+  def test_if
+    assert_equal("1px", evaluate("if(true, 1px, 2px)"))
+    assert_equal("2px", evaluate("if(false, 1px, 2px)"))
+    assert_equal("2px", evaluate("if(null, 1px, 2px)"))
+    assert_equal("1px", evaluate("if(true, 1px, $broken)"))
+    assert_equal("1px", evaluate("if(false, $broken, 1px)"))
+    assert_equal("1px", evaluate("if(false, $if-true: $broken, $if-false: 1px)"))
+    assert_equal("1px", evaluate("if(true, $if-true: 1px, $if-false: $broken)"))
+    assert_equal(<<CSS, render(<<SCSS))
+.if {
+  result: yay; }
+CSS
+.if {
+  $something: yay;
+  result: if(true, $if-true: $something, $if-false: $broken);
+}
+SCSS
+    assert_equal(<<CSS, render(<<SCSS))
+.if {
+  result: 1px; }
+CSS
+.if {
+  $splat: 1px, 2px;
+  result: if(true, $splat...);
+}
+SCSS
+  end
+
+  def test_counter
+    assert_equal("counter(foo)", evaluate("counter(foo)"))
+    assert_equal('counter(item,".")', evaluate('counter(item, ".")'))
+    assert_equal('counter(item,".")', evaluate('counter(item,".")'))
+  end
+
+  def test_counters
+    assert_equal("counters(foo)", evaluate("counters(foo)"))
+    assert_equal('counters(item,".")', evaluate('counters(item, ".")'))
+    assert_equal('counters(item,".")', evaluate('counters(item,".")'))
+  end
+
+  def test_keyword_args_rgb
+    assert_equal(%Q{white}, evaluate("rgb($red: 255, $green: 255, $blue: 255)"))
+  end
+
+  def test_keyword_args_rgba
+    assert_equal(%Q{rgba(255, 255, 255, 0.5)}, evaluate("rgba($red: 255, $green: 255, $blue: 255, $alpha: 
0.5)"))
+    assert_equal(%Q{rgba(255, 255, 255, 0.5)}, evaluate("rgba($color: #fff, $alpha: 0.5)"))
+  end
+
+  def test_keyword_args_rgba_with_extra_args
+    evaluate("rgba($red: 255, $green: 255, $blue: 255, $alpha: 0.5, $extra: error)")
+    flunk("Expected exception")
+  rescue Sass::SyntaxError => e
+    assert_equal("Function rgba doesn't have an argument named $extra", e.message)
+  end
+
+  def test_keyword_args_must_have_signature
+    evaluate("no-kw-args($fake: value)")
+    flunk("Expected exception")
+  rescue Sass::SyntaxError => e
+    assert_equal("Function no_kw_args doesn't support keyword arguments", e.message)
+  end
+
+  def test_keyword_args_with_missing_argument
+    evaluate("rgb($red: 255, $green: 255)")
+    flunk("Expected exception")
+  rescue Sass::SyntaxError => e
+    assert_equal("Function rgb requires an argument named $blue", e.message)
+  end
+
+  def test_keyword_args_with_extra_argument
+    evaluate("rgb($red: 255, $green: 255, $blue: 255, $purple: 255)")
+    flunk("Expected exception")
+  rescue Sass::SyntaxError => e
+    assert_equal("Function rgb doesn't have an argument named $purple", e.message)
+  end
+
+  def test_keyword_args_with_positional_and_keyword_argument
+    evaluate("rgb(255, 255, 255, $red: 255)")
+    flunk("Expected exception")
+  rescue Sass::SyntaxError => e
+    assert_equal("Function rgb was passed argument $red both by position and by name", e.message)
+  end
+
+  def test_keyword_args_with_keyword_before_positional_argument
+    evaluate("rgb($red: 255, 255, 255)")
+    flunk("Expected exception")
+  rescue Sass::SyntaxError => e
+    assert_equal("Positional arguments must come before keyword arguments.", e.message)
+  end
+
+  def test_only_var_args
+    assert_equal "only-var-args(2px, 3px, 4px)", evaluate("only-var-args(1px, 2px, 3px)")
+  end
+
+  def test_only_kw_args
+    assert_equal "only-kw-args(a, b, c)", evaluate("only-kw-args($a: 1, $b: 2, $c: 3)")
+  end
+
+  def test_unique_id
+    last_id, current_id = nil, evaluate("unique-id()")
+
+    50.times do
+      last_id, current_id = current_id, evaluate("unique-id()")
+      assert_match(/u[a-z0-9]{8}/, current_id)
+      refute_equal last_id, current_id
+    end
+  end
+
+  def test_map_get
+    assert_equal "1", evaluate("map-get((foo: 1, bar: 2), foo)")
+    assert_equal "2", evaluate("map-get((foo: 1, bar: 2), bar)")
+    assert_equal "null", perform("map-get((foo: 1, bar: 2), baz)").to_sass
+    assert_equal "null", perform("map-get((), foo)").to_sass
+  end
+
+  def test_map_get_checks_type
+    assert_error_message("$map: 12 is not a map for `map-get'", "map-get(12, bar)")
+  end
+
+  def test_map_merge
+    assert_equal("(foo: 1, bar: 2, baz: 3)",
+      perform("map-merge((foo: 1, bar: 2), (baz: 3))").to_sass)
+    assert_equal("(foo: 1, bar: 2)",
+      perform("map-merge((), (foo: 1, bar: 2))").to_sass)
+    assert_equal("(foo: 1, bar: 2)",
+      perform("map-merge((foo: 1, bar: 2), ())").to_sass)
+  end
+
+  def test_map_merge_checks_type
+    assert_error_message("$map1: 12 is not a map for `map-merge'", "map-merge(12, (foo: 1))")
+    assert_error_message("$map2: 12 is not a map for `map-merge'", "map-merge((foo: 1), 12)")
+  end
+
+  def test_map_remove
+    assert_equal("(foo: 1, baz: 3)",
+      perform("map-remove((foo: 1, bar: 2, baz: 3), bar)").to_sass)
+    assert_equal("(foo: 1, baz: 3)",
+      perform("map-remove($map: (foo: 1, bar: 2, baz: 3), $key: bar)").to_sass)
+    assert_equal("()",
+      perform("map-remove((foo: 1, bar: 2, baz: 3), foo, bar, baz)").to_sass)
+    assert_equal("()", perform("map-remove((), foo)").to_sass)
+    assert_equal("()", perform("map-remove((), foo, bar)").to_sass)
+  end
+
+  def test_map_remove_checks_type
+    assert_error_message("$map: 12 is not a map for `map-remove'", "map-remove(12, foo)")
+  end
+
+  def test_map_keys
+    assert_equal("foo, bar",
+      perform("map-keys((foo: 1, bar: 2))").to_sass)
+    assert_equal("()", perform("map-keys(())").to_sass)
+  end
+
+  def test_map_keys_checks_type
+    assert_error_message("$map: 12 is not a map for `map-keys'", "map-keys(12)")
+  end
+
+  def test_map_values
+    assert_equal("1, 2", perform("map-values((foo: 1, bar: 2))").to_sass)
+    assert_equal("1, 2, 2",
+      perform("map-values((foo: 1, bar: 2, baz: 2))").to_sass)
+    assert_equal("()", perform("map-values(())").to_sass)
+  end
+
+  def test_map_values_checks_type
+    assert_error_message("$map: 12 is not a map for `map-values'", "map-values(12)")
+  end
+
+  def test_map_has_key
+    assert_equal "true", evaluate("map-has-key((foo: 1, bar: 1), foo)")
+    assert_equal "false", evaluate("map-has-key((foo: 1, bar: 1), baz)")
+    assert_equal "false", evaluate("map-has-key((), foo)")
+  end
+
+  def test_map_has_key_checks_type
+    assert_error_message("$map: 12 is not a map for `map-has-key'", "map-has-key(12, foo)")
+  end
+
+  def test_keywords
+    # The actual functionality is tested in tests where real arglists are passed.
+    assert_error_message("$args: 12 is not a variable argument list for `keywords'", "keywords(12)")
+    assert_error_message(
+      "$args: (1 2 3) is not a variable argument list for `keywords'", "keywords(1 2 3)")
+  end
+
+  def test_partial_list_of_pairs_doesnt_work_as_a_map
+    assert_raises(Sass::SyntaxError) {evaluate("map-get((foo bar, baz bang, bip), 1)")}
+    assert_raises(Sass::SyntaxError) {evaluate("map-get((foo bar, baz bang, bip bap bop), 1)")}
+    assert_raises(Sass::SyntaxError) {evaluate("map-get((foo bar), 1)")}
+  end
+
+  def test_assert_unit
+    ctx = Sass::Script::Functions::EvaluationContext.new(Sass::Environment.new(nil, {}))
+    ctx.assert_unit Sass::Script::Value::Number.new(10, ["px"], []), "px"
+    ctx.assert_unit Sass::Script::Value::Number.new(10, [], []), nil
+
+    begin
+      ctx.assert_unit Sass::Script::Value::Number.new(10, [], []), "px"
+      fail
+    rescue ArgumentError => e
+      assert_equal "Expected 10 to have a unit of px", e.message
+    end
+
+    begin
+      ctx.assert_unit Sass::Script::Value::Number.new(10, ["px"], []), nil
+      fail
+    rescue ArgumentError => e
+      assert_equal "Expected 10px to be unitless", e.message
+    end
+
+    begin
+      ctx.assert_unit Sass::Script::Value::Number.new(10, [], []), "px", "arg"
+      fail
+    rescue ArgumentError => e
+      assert_equal "Expected $arg to have a unit of px but got 10", e.message
+    end
+
+    begin
+      ctx.assert_unit Sass::Script::Value::Number.new(10, ["px"], []), nil, "arg"
+      fail
+    rescue ArgumentError => e
+      assert_equal "Expected $arg to be unitless but got 10px", e.message
+    end
+  end
+
+  def test_call_with_positional_arguments
+    assert_equal evaluate("lighten(blue, 5%)"), evaluate("call(lighten, blue, 5%)")
+  end
+
+  def test_call_with_keyword_arguments
+    assert_equal(
+      evaluate("lighten($color: blue, $amount: 5%)"),
+      evaluate("call(lighten, $color: blue, $amount: 5%)"))
+  end
+
+  def test_call_with_keyword_and_positional_arguments
+    assert_equal(
+      evaluate("lighten(blue, $amount: 5%)"),
+      evaluate("call(lighten, blue, $amount: 5%)"))
+  end
+
+  def test_call_with_dynamic_name
+    assert_equal(
+      evaluate("lighten($color: blue, $amount: 5%)"),
+      evaluate("call($fn, $color: blue, $amount: 5%)",
+        env("fn" => Sass::Script::String.new("lighten"))))
+  end
+
+  def test_call_uses_local_scope
+    assert_equal <<CSS, render(<<SCSS)
+.first-scope {
+  a: local; }
+
+.second-scope {
+  a: global; }
+CSS
+ function foo() { return global}
+
+.first-scope {
+  @function foo() { return local}
+  a: call(foo);
+}
+
+.second-scope {
+  a: call(foo);
+}
+SCSS
+  end
+
+  def test_call_unknown_function
+    assert_equal evaluate("unknown(red, blue)"), evaluate("call(unknown, red, blue)")
+  end
+
+  def test_call_with_non_string_argument
+    assert_error_message "$name: 3px is not a string for `call'", "call(3px)"
+  end
+
+  def test_errors_in_called_function
+    assert_error_message "$color: 3px is not a color for `lighten'", "call(lighten, 3px, 5%)"
+  end
+
+  def test_variable_exists
+    assert_equal <<CSS, render(<<SCSS)
+.test {
+  false: false;
+  true: true;
+  true: true;
+  true: true;
+  true: true; }
+CSS
+$global-var: has-value;
+.test {
+  false: variable-exists(foo);
+  $foo: has-value;
+  true: variable-exists(foo);
+  true: variable-exists($name: foo);
+  true: variable-exists(global-var);
+  true: variable-exists($name: global-var);
+}
+SCSS
+  end
+
+  def test_variable_exists_checks_type
+    assert_error_message("$name: 1 is not a string for `variable-exists'", "variable-exists(1)")
+  end
+
+  def test_global_variable_exists
+    assert_equal <<CSS, render(<<SCSS)
+.test {
+  false: false;
+  false: false;
+  true: true;
+  true: true;
+  false: false;
+  true: true;
+  true: true; }
+CSS
+$g: something;
+$h: null;
+$false: global-variable-exists(foo);
+$true: global-variable-exists(g);
+$named: global-variable-exists($name: g);
+.test {
+  $foo: locally-defined;
+  false: global-variable-exists(foo);
+  false: global-variable-exists(foo2);
+  true: global-variable-exists(g);
+  true: global-variable-exists(h);
+  false: $false;
+  true: $true;
+  true: $named;
+}
+SCSS
+  end
+
+  def test_global_variable_exists_checks_type
+    assert_error_message("$name: 1 is not a string for `global-variable-exists'",
+      "global-variable-exists(1)")
+  end
+
+  def test_function_exists
+    # built-ins
+    assert_equal "true", evaluate("function-exists(lighten)")
+    # with named argument
+    assert_equal "true", evaluate("function-exists($name: lighten)")
+    # user-defined
+    assert_equal <<CSS, render(<<SCSS)
+.test {
+  foo-exists: true;
+  bar-exists: false; }
+CSS
+ function foo() { @return "foo" }
+.test {
+  foo-exists: function-exists(foo);
+  bar-exists: function-exists(bar);
+}
+SCSS
+  end
+
+  def test_function_exists_checks_type
+    assert_error_message("$name: 1 is not a string for `function-exists'", "function-exists(1)")
+  end
+
+  def test_mixin_exists
+    assert_equal "false", evaluate("mixin-exists(foo)")
+    # with named argument
+    assert_equal "false", evaluate("mixin-exists($name: foo)")
+    assert_equal <<CSS, render(<<SCSS)
+.test {
+  foo-exists: true;
+  bar-exists: false; }
+CSS
+ mixin foo() { foo: exists }
+.test {
+  foo-exists: mixin-exists(foo);
+  bar-exists: mixin-exists(bar);
+}
+SCSS
+  end
+
+  def test_mixin_exists_checks_type
+    assert_error_message("$name: 1 is not a string for `mixin-exists'", "mixin-exists(1)")
+  end
+
+  def test_inspect
+    assert_equal "()", evaluate("inspect(())")
+    assert_equal "null", evaluate("inspect(null)")
+    assert_equal "1px null 3px", evaluate("inspect(1px null 3px)")
+    assert_equal "(a: 1, b: 2)", evaluate("inspect((a: 1, b: 2))")
+  end
+
+  def test_random
+    Sass::Script::Functions.random_seed = 1
+    assert_equal "0.41702", evaluate("random()")
+    assert_equal "13", evaluate("random(100)")
+  end
+
+  def test_random_works_without_a_seed
+    if Sass::Script::Functions.instance_variable_defined?("@random_number_generator")
+      Sass::Script::Functions.send(:remove_instance_variable, "@random_number_generator")
+    end
+
+    result = perform("random()")
+    assert_kind_of Sass::Script::Number, result
+    assert result.value >= 0, "Random number was below 0"
+    assert result.value <= 1, "Random number was above 1"
+  end
+
+  def test_random_with_limit_one
+    # Passing 1 as the limit should always return 1, since limit calls return
+    # integers from 1 to the argument, so when the argument is 1, its a predicatble
+    # outcome
+    assert "1", evaluate("random(1)")
+  end
+
+  def test_random_with_limit_too_low
+    assert_error_message("$limit 0 must be greater than or equal to 1 for `random'", "random(0)")
+  end
+
+  def test_random_with_non_integer_limit
+    assert_error_message("Expected $limit to be an integer but got 1.5 for `random'", "random(1.5)")
+  end
+
+  # This could *possibly* fail, but exceedingly unlikely
+  def test_random_is_semi_unique
+    if Sass::Script::Functions.instance_variable_defined?("@random_number_generator")
+      Sass::Script::Functions.send(:remove_instance_variable, "@random_number_generator")
+    end
+    refute_equal evaluate("random()"), evaluate("random()")
+  end
+
+  def test_deprecated_arg_names
+    assert_warning <<WARNING do
+DEPRECATION WARNING: The `$arg-1' argument for `deprecated-arg-fn()' has been renamed to `$arg1'.
+DEPRECATION WARNING: The `$arg-2' argument for `deprecated-arg-fn()' has been renamed to `$arg2'.
+WARNING
+      assert_equal("1 2 3",
+        evaluate("deprecated-arg-fn($arg-1: 1, $arg-2: 2, $arg3: 3)"))
+    end
+
+    assert_warning <<WARNING do
+DEPRECATION WARNING: The `$arg-1' argument for `deprecated-arg-fn()' has been renamed to `$arg1'.
+DEPRECATION WARNING: The `$arg-2' argument for `deprecated-arg-fn()' has been renamed to `$arg2'.
+WARNING
+      assert_equal("1 2",
+        evaluate("deprecated-arg-fn($arg-1: 1, $arg-2: 2)"))
+    end
+
+    assert_warning <<WARNING do
+DEPRECATION WARNING: The `$arg_1' argument for `deprecated-arg-fn()' has been renamed to `$arg1'.
+DEPRECATION WARNING: The `$arg_2' argument for `deprecated-arg-fn()' has been renamed to `$arg2'.
+WARNING
+      assert_equal("1 2",
+        evaluate("deprecated-arg-fn($arg_1: 1, $arg_2: 2)"))
+    end
+  end
+
+  def test_non_deprecated_arg_names
+    assert_equal("1 2 3", evaluate("deprecated-arg-fn($arg1: 1, $arg2: 2, $arg3: 3)"))
+    assert_equal("1 2", evaluate("deprecated-arg-fn($arg1: 1, $arg2: 2)"))
+  end
+
+  ## Selector Functions
+
+  def test_selector_argument_parsing
+    assert_equal("true", evaluate("selector-parse('.foo') == (join(('.foo',), (), space),)"))
+    assert_equal("true", evaluate("selector-parse('.foo .bar') == ('.foo' '.bar',)"))
+    assert_equal("true",
+      evaluate("selector-parse('.foo .bar, .baz .bang') == ('.foo' '.bar', '.baz' '.bang')"))
+
+    assert_equal(".foo %bar", evaluate("selector-parse('.foo %bar')"))
+
+    assert_equal("true",
+      evaluate("selector-parse(('.foo', '.bar')) == selector-parse('.foo, .bar')"))
+    assert_equal("true",
+      evaluate("selector-parse('.foo' '.bar') == selector-parse('.foo .bar')"))
+
+    assert_equal("true", evaluate("selector-parse(('.foo' '.bar', '.baz' '.bang')) == " +
+        "selector-parse('.foo .bar, .baz .bang')"))
+    assert_equal("true", evaluate("selector-parse(('.foo .bar', '.baz .bang')) == " +
+        "selector-parse('.foo .bar, .baz .bang')"))
+
+    # This may throw an error in the future.
+    assert_equal("true", evaluate("selector-parse(('.foo, .bar' '.baz, .bang')) == " +
+        "selector-parse('.foo, .bar .baz, .bang')"))
+  end
+
+  def test_selector_argument_validation
+    assert_error_message("$selector: 12 is not a valid selector: it must be a string,\n" +
+      "a list of strings, or a list of lists of strings for `selector-parse'", "selector-parse(12)")
+    assert_error_message("$selector: (((\".foo\" \".bar\"), \".baz\") (\".bang\", \".qux\")) is not a valid 
selector: it must be a string,\n" +
+      "a list of strings, or a list of lists of strings for `selector-parse'",
+      "selector-parse(('.foo' '.bar', '.baz') ('.bang', '.qux'))")
+    assert_error_message("$selector: \".#\" is not a valid selector: Invalid CSS after \".\": " +
+      "expected class name, was \"#\" for `selector-parse'", "selector-parse('.#')")
+    assert_error_message("$selector: \"&.foo\" is not a valid selector: Invalid CSS after \"\": " +
+      "expected selector, was \"&.foo\" for `selector-parse'", "selector-parse('&.foo')")
+  end
+
+  def test_selector_nest
+    assert_equal(".foo", evaluate("selector-nest('.foo')"))
+    assert_equal(".foo .bar", evaluate("selector-nest('.foo', '.bar')"))
+    assert_equal(".foo .bar .baz", evaluate("selector-nest('.foo', '.bar', '.baz')"))
+    assert_equal(".a .foo .b .bar", evaluate("selector-nest('.a .foo', '.b .bar')"))
+    assert_equal(".foo.bar", evaluate("selector-nest('.foo', '&.bar')"))
+    assert_equal(".baz .foo.bar", evaluate("selector-nest('.foo', '&.bar', '.baz &')"))
+  end
+
+  def test_selector_nest_checks_types
+    assert_error_message("$selectors: 12 is not a valid selector: it must be a string,\n" +
+      "a list of strings, or a list of lists of strings for `selector-nest'",
+      "selector-nest(12)")
+    assert_error_message("$selectors: 12 is not a valid selector: it must be a string,\n" +
+      "a list of strings, or a list of lists of strings for `selector-nest'",
+      "selector-nest('.foo', 12)")
+  end
+
+  def test_selector_nest_argument_validation
+    assert_error_message("$selectors: At least one selector must be passed for `selector-nest'",
+      "selector-nest()")
+  end
+
+  def test_selector_append
+    assert_equal(".foo.bar", evaluate("selector-append('.foo', '.bar')"))
+    assert_equal(".a .foo.b .bar", evaluate("selector-append('.a .foo', '.b .bar')"))
+    assert_equal(".foo-suffix", evaluate("selector-append('.foo', '-suffix')"))
+    assert_equal(".foo.bar, .foo-suffix", evaluate("selector-append('.foo', '.bar, -suffix')"))
+    assert_equal(".foo--suffix", evaluate("selector-append('.foo', '--suffix')"))
+    assert_equal(".foo.bar, .foo--suffix", evaluate("selector-append('.foo', '.bar, --suffix')"))
+  end
+
+  def test_selector_append_checks_types
+    assert_error_message("$selectors: 12 is not a valid selector: it must be a string,\n" +
+      "a list of strings, or a list of lists of strings for `selector-append'",
+      "selector-append(12)")
+    assert_error_message("$selectors: 12 is not a valid selector: it must be a string,\n" +
+      "a list of strings, or a list of lists of strings for `selector-append'",
+      "selector-append('.foo', 12)")
+  end
+
+  def test_selector_append_errors
+    assert_error_message("$selectors: At least one selector must be passed for `selector-append'",
+      "selector-append()")
+    assert_error_message("Can't append \"> .bar\" to \".foo\" for `selector-append'",
+      "selector-append('.foo', '> .bar')")
+    assert_error_message("Can't append \"*.bar\" to \".foo\" for `selector-append'",
+      "selector-append('.foo', '*.bar')")
+    assert_error_message("Can't append \"ns|suffix\" to \".foo\" for `selector-append'",
+      "selector-append('.foo', 'ns|suffix')")
+  end
+
+  def test_selector_extend
+    assert_equal(".foo .x, .foo .a .bar, .a .foo .bar",
+      evaluate("selector-extend('.foo .x', '.x', '.a .bar')"))
+    assert_equal(".foo .x, .foo .bang, .x.bar, .bar.bang",
+      evaluate("selector-extend('.foo .x, .x.bar', '.x', '.bang')"))
+    assert_equal(".y .x, .foo .x, .y .foo, .foo .foo",
+      evaluate("selector-extend('.y .x', '.x, .y', '.foo')"))
+    assert_equal(".foo .x, .foo .bar, .foo .bang",
+      evaluate("selector-extend('.foo .x', '.x', '.bar, .bang')"))
+    assert_equal(".foo.x, .foo",
+      evaluate("selector-extend('.foo.x', '.x', '.foo')"))
+  end
+
+  def test_selector_extend_checks_types
+    assert_error_message("$selector: 12 is not a valid selector: it must be a string,\n" +
+      "a list of strings, or a list of lists of strings for `selector-extend'",
+      "selector-extend(12, '.foo', '.bar')")
+    assert_error_message("$extendee: 12 is not a valid selector: it must be a string,\n" +
+      "a list of strings, or a list of lists of strings for `selector-extend'",
+      "selector-extend('.foo', 12, '.bar')")
+    assert_error_message("$extender: 12 is not a valid selector: it must be a string,\n" +
+      "a list of strings, or a list of lists of strings for `selector-extend'",
+      "selector-extend('.foo', '.bar', 12)")
+  end
+
+  def test_selector_extend_errors
+    assert_error_message("Can't extend .bar .baz: can't extend nested selectors for " +
+      "`selector-extend'", "selector-extend('.foo', '.bar .baz', '.bang')")
+    assert_error_message("Can't extend >: invalid selector for `selector-extend'",
+      "selector-extend('.foo', '>', '.bang')")
+    assert_error_message(".bang > can't extend: invalid selector for `selector-extend'",
+      "selector-extend('.foo', '.bar', '.bang >')")
+  end
+
+  def test_selector_replace
+    assert_equal(".bar", evaluate("selector-replace('.foo', '.foo', '.bar')"))
+    assert_equal(".foo.baz", evaluate("selector-replace('.foo.bar', '.bar', '.baz')"))
+    assert_equal(".a .foo.baz", evaluate("selector-replace('.foo.bar', '.bar', '.a .baz')"))
+    assert_equal(".foo.bar", evaluate("selector-replace('.foo.bar', '.baz.bar', '.qux')"))
+    assert_equal(".bar.qux", evaluate("selector-replace('.foo.bar.baz', '.foo.baz', '.qux')"))
+
+    assert_equal(":not(.bar)", evaluate("selector-replace(':not(.foo)', '.foo', '.bar')"))
+    assert_equal(".bar", evaluate("selector-replace(':not(.foo)', ':not(.foo)', '.bar')"))
+  end
+
+  def test_selector_replace_checks_types
+    assert_error_message("$selector: 12 is not a valid selector: it must be a string,\n" +
+      "a list of strings, or a list of lists of strings for `selector-replace'",
+      "selector-replace(12, '.foo', '.bar')")
+    assert_error_message("$original: 12 is not a valid selector: it must be a string,\n" +
+      "a list of strings, or a list of lists of strings for `selector-replace'",
+      "selector-replace('.foo', 12, '.bar')")
+    assert_error_message("$replacement: 12 is not a valid selector: it must be a string,\n" +
+      "a list of strings, or a list of lists of strings for `selector-replace'",
+      "selector-replace('.foo', '.bar', 12)")
+  end
+
+  def test_selector_replace_errors
+    assert_error_message("Can't extend .bar .baz: can't extend nested selectors for " +
+      "`selector-replace'", "selector-replace('.foo', '.bar .baz', '.bang')")
+    assert_error_message("Can't extend >: invalid selector for `selector-replace'",
+      "selector-replace('.foo', '>', '.bang')")
+    assert_error_message(".bang > can't extend: invalid selector for `selector-replace'",
+      "selector-replace('.foo', '.bar', '.bang >')")
+  end
+
+  def test_selector_unify
+    assert_equal(".foo", evaluate("selector-unify('.foo', '.foo')"))
+    assert_equal(".foo.bar", evaluate("selector-unify('.foo', '.bar')"))
+    assert_equal(".foo.bar.baz", evaluate("selector-unify('.foo.bar', '.bar.baz')"))
+    assert_equal(".a .b .foo.bar, .b .a .foo.bar", evaluate("selector-unify('.a .foo', '.b .bar')"))
+    assert_equal(".a .foo.bar", evaluate("selector-unify('.a .foo', '.a .bar')"))
+    assert_equal("", evaluate("selector-unify('p', 'a')"))
+    assert_equal("", evaluate("selector-unify('.foo >', '.bar')"))
+    assert_equal("", evaluate("selector-unify('.foo', '.bar >')"))
+    assert_equal(".foo.baz, .foo.bang, .bar.baz, .bar.bang",
+      evaluate("selector-unify('.foo, .bar', '.baz, .bang')"))
+  end
+
+  def test_selector_unify_checks_types
+    assert_error_message("$selector1: 12 is not a valid selector: it must be a string,\n" +
+      "a list of strings, or a list of lists of strings for `selector-unify'",
+      "selector-unify(12, '.foo')")
+    assert_error_message("$selector2: 12 is not a valid selector: it must be a string,\n" +
+      "a list of strings, or a list of lists of strings for `selector-unify'",
+      "selector-unify('.foo', 12)")
+  end
+
+  def test_simple_selectors
+    assert_equal('(.foo,)', evaluate("inspect(simple-selectors('.foo'))"))
+    assert_equal('.foo, .bar', evaluate("inspect(simple-selectors('.foo.bar'))"))
+    assert_equal('.foo, .bar, :pseudo("flip, flap")',
+      evaluate("inspect(simple-selectors('.foo.bar:pseudo(\"flip, flap\")'))"))
+  end
+
+  def test_simple_selectors_checks_types
+    assert_error_message("$selector: 12 is not a string for `simple-selectors'",
+      "simple-selectors(12)")
+  end
+
+  def test_simple_selectors_errors
+    assert_error_message("$selector: \".foo .bar\" is not a compound selector for `simple-selectors'",
+      "simple-selectors('.foo .bar')")
+    assert_error_message("$selector: \".foo,.bar\" is not a compound selector for `simple-selectors'",
+      "simple-selectors('.foo,.bar')")
+    assert_error_message("$selector: \".#\" is not a valid selector: Invalid CSS after \".\": " +
+      "expected class name, was \"#\" for `simple-selectors'", "simple-selectors('.#')")
+  end
+
+  def test_is_superselector
+    assert_equal("true", evaluate("is-superselector('.foo', '.foo.bar')"))
+    assert_equal("false", evaluate("is-superselector('.foo.bar', '.foo')"))
+    assert_equal("true", evaluate("is-superselector('.foo', '.foo')"))
+    assert_equal("true", evaluate("is-superselector('.bar', '.foo .bar')"))
+    assert_equal("false", evaluate("is-superselector('.foo .bar', '.bar')"))
+    assert_equal("true", evaluate("is-superselector('.foo .bar', '.foo > .bar')"))
+    assert_equal("false", evaluate("is-superselector('.foo > .bar', '.foo .bar')"))
+  end
+
+  def test_is_superselector_checks_types
+    assert_error_message("$super: 12 is not a valid selector: it must be a string,\n" +
+      "a list of strings, or a list of lists of strings for `is-superselector'",
+      "is-superselector(12, '.foo')")
+    assert_error_message("$sub: 12 is not a valid selector: it must be a string,\n" +
+      "a list of strings, or a list of lists of strings for `is-superselector'",
+      "is-superselector('.foo', 12)")
+  end
+
+  ## Regression Tests
+
+  def test_inspect_nested_empty_lists
+    assert_equal "() ()", evaluate("inspect(() ())")
+  end
+
+  def test_saturation_bounds
+    assert_equal "#fbfdff", evaluate("hsl(hue(#fbfdff), saturation(#fbfdff), lightness(#fbfdff))")
+  end
+
+  private
+  def env(hash = {}, parent = nil)
+    env = Sass::Environment.new(parent)
+    hash.each {|k, v| env.set_var(k, v)}
+    env
+  end
+
+  def evaluate(value, environment = env)
+    result = perform(value, environment)
+    assert_kind_of Sass::Script::Value::Base, result
+    return result.to_s
+  end
+
+  def perform(value, environment = env)
+    Sass::Script::Parser.parse(value, 0, 0).perform(environment)
+  end
+
+  def render(sass, options = {})
+    options[:syntax] ||= :scss
+    munge_filename options
+    options[:importer] ||= MockImporter.new
+    Sass::Engine.new(sass, options).render
+  end
+
+  def assert_error_message(message, value)
+    evaluate(value)
+    flunk("Error message expected but not raised: #{message}")
+  rescue Sass::SyntaxError => e
+    assert_equal(message, e.message)
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/test/sass/importer_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/importer_test.rb
new file mode 100755
index 0000000..9d5890c
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/importer_test.rb
@@ -0,0 +1,421 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../test_helper'
+require File.dirname(__FILE__) + '/test_helper'
+require 'mock_importer'
+require 'sass/plugin'
+
+class ImporterTest < MiniTest::Test
+
+  class FruitImporter < Sass::Importers::Base
+    def find(name, context = nil)
+      fruit = parse(name)
+      return unless fruit
+      color = case fruit
+      when "apple"
+        "red"
+      when "orange"
+        "orange"
+      else
+        "blue"
+      end
+      contents = %Q{
+        $#{fruit}-color: #{color} !default;
+        @mixin #{fruit} {
+          color: $#{fruit}-color;
+        }
+      }
+      Sass::Engine.new(contents, :filename => name, :syntax => :scss, :importer => self)
+    end
+
+    def key(name, context)
+      [self.class.name, name]
+    end
+
+    def public_url(name, sourcemap_directory = nil)
+      "http://#{parse(name)}.example.com/style.scss"
+    end
+
+    private
+
+    def parse(name)
+      name[%r{fruits/(\w+)(\.s[ac]ss)?}, 1]
+    end
+  end
+
+  class NoPublicUrlImporter < FruitImporter
+    def public_url(name, sourcemap_directory = nil)
+      nil
+    end
+
+    private
+
+    def parse(name)
+      name[%r{ephemeral/(\w+)(\.s[ac]ss)?}, 1]
+    end
+  end
+
+  # This class proves that you can override the extension scheme for importers
+  class ReversedExtImporter < Sass::Importers::Filesystem
+    def extensions
+      {"sscs" => :scss, "ssas" => :sass}
+    end
+  end
+
+  # This importer maps one import to another import
+  # based on the mappings passed to importer's constructor.
+  class IndirectImporter < Sass::Importers::Base
+    def initialize(mappings, mtimes)
+      @mappings = mappings
+      @mtimes = mtimes
+    end
+    def find_relative(uri, base, options)
+      nil
+    end
+    def find(name, options)
+      if @mappings.has_key?(name)
+        Sass::Engine.new(
+          %Q[ import "#{ mappings[name]}";],
+          options.merge(
+            :filename => name,
+            :syntax => :scss,
+            :importer => self
+          )
+        )
+      end
+    end
+    def mtime(uri, options)
+      @mtimes.fetch(uri, @mtimes.has_key?(uri) ? Time.now : nil)
+    end
+    def key(uri, options)
+      [self.class.name, uri]
+    end
+    def to_s
+      "IndirectImporter(#{ mappings keys join(", ")})"
+    end
+  end
+
+  # This importer maps the import to single class
+  # based on the mappings passed to importer's constructor.
+  class ClassImporter < Sass::Importers::Base
+    def initialize(mappings, mtimes)
+      @mappings = mappings
+      @mtimes = mtimes
+    end
+    def find_relative(uri, base, options)
+      nil
+    end
+    def find(name, options)
+      if @mappings.has_key?(name)
+        Sass::Engine.new(
+          %Q[ #{name}{#{ mappings[name]}}],
+          options.merge(
+            :filename => name,
+            :syntax => :scss,
+            :importer => self
+          )
+        )
+      end
+    end
+    def mtime(uri, options)
+      @mtimes.fetch(uri, @mtimes.has_key?(uri) ? Time.now : nil)
+    end
+    def key(uri, options)
+      [self.class.name, uri]
+    end
+    def to_s
+      "ClassImporter(#{ mappings keys join(", ")})"
+    end
+  end
+
+  def test_can_resolve_generated_imports
+    scss_file = %Q{
+      $pear-color: green;
+      @import "fruits/apple"; @import "fruits/orange"; @import "fruits/pear";
+      .apple { @include apple; }
+      .orange { @include orange; }
+      .pear { @include pear; }
+    }
+    css_file = <<CSS
+.apple { color: red; }
+
+.orange { color: orange; }
+
+.pear { color: green; }
+CSS
+    options = {:style => :compact, :load_paths => [FruitImporter.new], :syntax => :scss}
+    assert_equal css_file, Sass::Engine.new(scss_file, options).render
+  end
+
+  def test_extension_overrides
+    FileUtils.mkdir_p(absolutize("tmp"))
+    open(absolutize("tmp/foo.ssas"), "w") {|f| f.write(".foo\n  reversed: true\n")}
+    open(absolutize("tmp/bar.sscs"), "w") {|f| f.write(".bar {reversed: true}\n")}
+    scss_file = %Q{
+      @import "foo", "bar";
+      @import "foo.ssas", "bar.sscs";
+    }
+    css_file = <<CSS
+.foo { reversed: true; }
+
+.bar { reversed: true; }
+
+.foo { reversed: true; }
+
+.bar { reversed: true; }
+CSS
+    options = {:style => :compact, :load_paths => [ReversedExtImporter.new(absolutize("tmp"))], :syntax => 
:scss}
+    assert_equal css_file, Sass::Engine.new(scss_file, options).render
+  ensure
+    FileUtils.rm_rf(absolutize("tmp"))
+  end
+
+  def test_staleness_check_across_importers
+    file_system_importer = Sass::Importers::Filesystem.new(fixture_dir)
+    # Make sure the first import is older
+    indirect_importer = IndirectImporter.new({"apple" => "pear"}, {"apple" => Time.now - 1})
+    # Make css file is newer so the dependencies are the only way for the css file to be out of date.
+    FileUtils.touch(fixture_file("test_staleness_check_across_importers.css"))
+    # Make sure the first import is older
+    class_importer = ClassImporter.new({"pear" => %Q{color: green;}}, {"pear" => Time.now + 1})
+
+    options = {
+      :style => :compact,
+      :filename => fixture_file("test_staleness_check_across_importers.scss"),
+      :importer => file_system_importer,
+      :load_paths => [file_system_importer, indirect_importer, class_importer],
+      :syntax => :scss
+    }
+
+    assert_equal File.read(fixture_file("test_staleness_check_across_importers.css")),
+                 Sass::Engine.new(File.read(fixture_file("test_staleness_check_across_importers.scss")), 
options).render
+
+    checker = Sass::Plugin::StalenessChecker.new(options)
+
+    assert checker.stylesheet_needs_update?(
+      fixture_file("test_staleness_check_across_importers.css"),
+      fixture_file("test_staleness_check_across_importers.scss"),
+      file_system_importer
+    )
+  end
+
+  def test_source_map_with_only_css_uri_supports_public_url_imports
+    fruit_importer = FruitImporter.new
+
+    options = {
+      :filename => 'fruits/orange',
+      :importer => fruit_importer,
+      :syntax => :scss
+    }
+
+    engine = Sass::Engine.new(<<SCSS, options)
+.orchard {
+  color: blue;
+}
+SCSS
+
+    _, sourcemap = engine.render_with_sourcemap('sourcemap_uri')
+    assert_equal <<JSON.strip, sourcemap.to_json(:css_uri => 'css_uri')
+{
+"version": 3,
+"mappings": "AAAA,QAAS;EACP,KAAK,EAAE,IAAI",
+"sources": ["http://orange.example.com/style.scss";],
+"names": [],
+"file": "css_uri"
+}
+JSON
+  end
+
+  def test_source_map_with_only_css_uri_can_have_no_public_url
+    ephemeral_importer = NoPublicUrlImporter.new
+    mock_importer = MockImporter.new
+    def mock_importer.public_url(name, sourcemap_directory = nil)
+      "source_uri"
+    end
+
+    options = {
+      :filename => filename_for_test,
+      :sourcemap_filename => sourcemap_filename_for_test,
+      :importer => mock_importer,
+      :syntax => :scss,
+      :load_paths => [ephemeral_importer],
+      :cache => false
+    }
+
+    engine = Sass::Engine.new(<<SCSS, options)
+ import "ephemeral/orange";
+.orange {
+  @include orange;
+}
+SCSS
+
+    css_output, sourcemap = engine.render_with_sourcemap('sourcemap_uri')
+    assert_equal <<CSS.strip, css_output.strip
+.orange {
+  color: orange; }
+
+/*# sourceMappingURL=sourcemap_uri */
+CSS
+    map = sourcemap.to_json(:css_uri => 'css_uri')
+    assert_equal <<JSON.strip, map
+{
+"version": 3,
+"mappings": "AACA,OAAQ",
+"sources": ["source_uri"],
+"names": [],
+"file": "css_uri"
+}
+JSON
+  end
+
+  def test_source_map_with_only_css_uri_falls_back_to_file_uris
+    file_system_importer = Sass::Importers::Filesystem.new('.')
+    options = {
+      :filename => filename_for_test(:scss),
+      :sourcemap_filename => sourcemap_filename_for_test,
+      :importer => file_system_importer,
+      :syntax => :scss
+    }
+
+    engine = Sass::Engine.new(<<SCSS, options)
+.foo {a: b}
+SCSS
+
+    _, sourcemap = engine.render_with_sourcemap('http://1.example.com/style.map')
+
+    uri = Sass::Util.file_uri_from_path(Sass::Util.absolute_path(filename_for_test(:scss)))
+    assert_equal <<JSON.strip, sourcemap.to_json(:css_uri => 'css_uri')
+{
+"version": 3,
+"mappings": "AAAA,IAAK;EAAC,CAAC,EAAE,CAAC",
+"sources": ["#{uri}"],
+"names": [],
+"file": "css_uri"
+}
+JSON
+  end
+
+  def test_source_map_with_css_uri_and_css_path_falls_back_to_file_uris
+    file_system_importer = Sass::Importers::Filesystem.new('.')
+    options = {
+      :filename => filename_for_test(:scss),
+      :sourcemap_filename => sourcemap_filename_for_test,
+      :importer => file_system_importer,
+      :syntax => :scss
+    }
+
+    engine = Sass::Engine.new(<<SCSS, options)
+.foo {a: b}
+SCSS
+
+    _, sourcemap = engine.render_with_sourcemap('http://1.example.com/style.map')
+
+    uri = Sass::Util.file_uri_from_path(Sass::Util.absolute_path(filename_for_test(:scss)))
+    assert_equal <<JSON.strip, sourcemap.to_json(:css_uri => 'css_uri', :css_path => 'css_path')
+{
+"version": 3,
+"mappings": "AAAA,IAAK;EAAC,CAAC,EAAE,CAAC",
+"sources": ["#{uri}"],
+"names": [],
+"file": "css_uri"
+}
+JSON
+  end
+
+  def test_source_map_with_css_uri_and_sourcemap_path_supports_filesystem_importer
+    file_system_importer = Sass::Importers::Filesystem.new('.')
+    css_uri = 'css_uri'
+    sourcemap_path = 'map/style.map'
+    options = {
+      :filename => 'sass/style.scss',
+      :sourcemap_filename => sourcemap_path,
+      :importer => file_system_importer,
+      :syntax => :scss
+    }
+
+    engine = Sass::Engine.new(<<SCSS, options)
+.foo {a: b}
+SCSS
+
+    rendered, sourcemap = engine.render_with_sourcemap('http://1.example.com/style.map')
+
+
+    rendered, sourcemap = engine.render_with_sourcemap('http://map.example.com/map/style.map')
+    assert_equal <<JSON.strip, sourcemap.to_json(:css_uri => css_uri, :sourcemap_path => sourcemap_path)
+{
+"version": 3,
+"mappings": "AAAA,IAAK;EAAC,CAAC,EAAE,CAAC",
+"sources": ["../sass/style.scss"],
+"names": [],
+"file": "css_uri"
+}
+JSON
+  end
+
+  def test_source_map_with_css_path_and_sourcemap_path_supports_file_system_importer
+    file_system_importer = Sass::Importers::Filesystem.new('.')
+    sass_path = 'sass/style.scss'
+    css_path = 'static/style.css'
+    sourcemap_path = 'map/style.map'
+    options = {
+      :filename => sass_path,
+      :sourcemap_filename => sourcemap_path,
+      :importer => file_system_importer,
+      :syntax => :scss
+    }
+
+    engine = Sass::Engine.new(<<SCSS, options)
+.foo {a: b}
+SCSS
+
+    _, sourcemap = engine.render_with_sourcemap('http://map.example.com/map/style.map')
+    assert_equal <<JSON.strip, sourcemap.to_json(:css_path => css_path, :sourcemap_path => sourcemap_path)
+{
+"version": 3,
+"mappings": "AAAA,IAAK;EAAC,CAAC,EAAE,CAAC",
+"sources": ["../sass/style.scss"],
+"names": [],
+"file": "../static/style.css"
+}
+JSON
+  end
+
+  def test_render_with_sourcemap_requires_filename
+    file_system_importer = Sass::Importers::Filesystem.new('.')
+    engine = Sass::Engine.new(".foo {a: b}", :syntax => :scss, :importer => file_system_importer)
+    assert_raise_message(Sass::SyntaxError, <<MESSAGE) {engine.render_with_sourcemap('sourcemap_url')}
+Error generating source map: couldn't determine public URL for the source stylesheet.
+  No filename is available so there's nothing for the source map to link to.
+MESSAGE
+  end
+
+  def test_render_with_sourcemap_requires_importer_with_public_url
+    class_importer = ClassImporter.new({"pear" => "color: green;"}, {"pear" => Time.now})
+    assert_raise_message(Sass::SyntaxError, <<MESSAGE) {class_importer.find("pear", 
{}).render_with_sourcemap('sourcemap_url')}
+Error generating source map: couldn't determine public URL for "pear".
+  Without a public URL, there's nothing for the source map to link to.
+  Custom importers should define the #public_url method.
+MESSAGE
+  end
+
+  def fixture_dir
+    File.join(File.dirname(__FILE__), "fixtures")
+  end
+
+  def fixture_file(path)
+    File.join(fixture_dir, path)
+  end
+
+  def test_filesystem_importer_eql
+    importer = Sass::Importers::Filesystem.new('.')
+    assert importer.eql?(Sass::Importers::Filesystem.new('.'))
+    assert importer.eql?(ReversedExtImporter.new('.'))
+    assert !importer.eql?(Sass::Importers::Filesystem.new('foo'))
+    assert !importer.eql?(nil)
+    assert !importer.eql?('foo')
+  end
+
+  def test_absolute_files_across_template_locations
+    importer = Sass::Importers::Filesystem.new(absolutize 'templates')
+    refute_nil importer.mtime(absolutize('more_templates/more1.sass'), {})
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/test/sass/logger_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/logger_test.rb
new file mode 100755
index 0000000..cc6c9aa
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/logger_test.rb
@@ -0,0 +1,58 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../test_helper'
+require 'pathname'
+
+class LoggerTest < MiniTest::Test
+
+  class InterceptedLogger < Sass::Logger::Base
+
+    attr_accessor :messages
+
+    def initialize(*args)
+      super
+      self.messages = []
+    end
+
+    def reset!
+      self.messages = []
+    end
+
+    def _log(*args)
+      messages << [args]
+    end
+
+  end
+
+  def test_global_sass_logger_instance_exists
+    assert Sass.logger.respond_to?(:warn)
+  end
+
+  def test_log_level_orders
+    logged_levels = {
+      :trace => [ [], [:trace, :debug, :info, :warn, :error]],
+      :debug => [ [:trace],   [:debug, :info, :warn, :error]],
+      :info  => [ [:trace, :debug],   [:info, :warn, :error]],
+      :warn  => [ [:trace, :debug, :info],   [:warn, :error]],
+      :error => [ [:trace, :debug, :info, :warn],   [:error]]
+    }
+    logged_levels.each do |level, (should_not_be_logged, should_be_logged)|
+      logger = Sass::Logger::Base.new(level)
+      should_not_be_logged.each do |should_level|
+        assert !logger.logging_level?(should_level)
+      end
+      should_be_logged.each do |should_level|
+        assert logger.logging_level?(should_level)
+      end
+    end
+  end
+
+  def test_logging_can_be_disabled
+    logger = InterceptedLogger.new
+    logger.error("message #1")
+    assert_equal 1, logger.messages.size
+    logger.reset!
+    logger.disabled = true
+    logger.error("message #2")
+    assert_equal 0, logger.messages.size
+  end
+end
diff --git a/backends/css/gems/sass-3.2.12/test/sass/mock_importer.rb 
b/backends/css/gems/sass-3.4.9/test/sass/mock_importer.rb
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/mock_importer.rb
rename to backends/css/gems/sass-3.4.9/test/sass/mock_importer.rb
diff --git a/backends/css/gems/sass-3.2.12/test/sass/more_results/more1.css 
b/backends/css/gems/sass-3.4.9/test/sass/more_results/more1.css
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/more_results/more1.css
rename to backends/css/gems/sass-3.4.9/test/sass/more_results/more1.css
diff --git a/backends/css/gems/sass-3.2.12/test/sass/more_results/more1_with_line_comments.css 
b/backends/css/gems/sass-3.4.9/test/sass/more_results/more1_with_line_comments.css
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/more_results/more1_with_line_comments.css
rename to backends/css/gems/sass-3.4.9/test/sass/more_results/more1_with_line_comments.css
diff --git a/backends/css/gems/sass-3.4.9/test/sass/more_results/more_import.css 
b/backends/css/gems/sass-3.4.9/test/sass/more_results/more_import.css
new file mode 100644
index 0000000..b5dae09
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/more_results/more_import.css
@@ -0,0 +1,29 @@
+ import url(basic.css);
+ import url(../results/complex.css);
+imported { otherconst: hello; myconst: goodbye; pre-mixin: here; }
+
+body { font: Arial; background: blue; }
+
+#page { width: 700px; height: 100; }
+#page #header { height: 300px; }
+#page #header h1 { font-size: 50px; color: blue; }
+
+#content.user.show #container.top #column.left { width: 100px; }
+#content.user.show #container.top #column.right { width: 600px; }
+#content.user.show #container.bottom { background: brown; }
+
+midrule { inthe: middle; }
+
+body { font: Arial; background: blue; }
+
+#page { width: 700px; height: 100; }
+#page #header { height: 300px; }
+#page #header h1 { font-size: 50px; color: blue; }
+
+#content.user.show #container.top #column.left { width: 100px; }
+#content.user.show #container.top #column.right { width: 600px; }
+#content.user.show #container.bottom { background: brown; }
+
+#foo { background-color: #baf; }
+
+nonimported { myconst: hello; otherconst: goodbye; post-mixin: here; }
diff --git a/backends/css/gems/sass-3.2.12/test/sass/more_templates/_more_partial.sass 
b/backends/css/gems/sass-3.4.9/test/sass/more_templates/_more_partial.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/more_templates/_more_partial.sass
rename to backends/css/gems/sass-3.4.9/test/sass/more_templates/_more_partial.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/more_templates/more1.sass 
b/backends/css/gems/sass-3.4.9/test/sass/more_templates/more1.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/more_templates/more1.sass
rename to backends/css/gems/sass-3.4.9/test/sass/more_templates/more1.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/more_templates/more_import.sass 
b/backends/css/gems/sass-3.4.9/test/sass/more_templates/more_import.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/more_templates/more_import.sass
rename to backends/css/gems/sass-3.4.9/test/sass/more_templates/more_import.sass
diff --git a/backends/css/gems/sass-3.4.9/test/sass/plugin_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/plugin_test.rb
new file mode 100755
index 0000000..187a2cf
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/plugin_test.rb
@@ -0,0 +1,556 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../test_helper'
+require File.dirname(__FILE__) + '/test_helper'
+require 'sass/plugin'
+require 'fileutils'
+
+module Sass::Script::Functions
+  def filename
+    filename = options[:filename].gsub(%r{.*((/[^/]+){4})}, '\1')
+    Sass::Script::Value::String.new(filename)
+  end
+
+  def whatever
+    custom = options[:custom]
+    whatever = custom && custom[:whatever]
+    Sass::Script::Value::String.new(whatever || "incorrect")
+  end
+end
+
+class SassPluginTest < MiniTest::Test
+  @@templates = %w{
+    complex script parent_ref import scss_import alt
+    subdir/subdir subdir/nested_subdir/nested_subdir
+    options import_content filename_fn
+  }
+  @@templates += %w[import_charset import_charset_ibm866] unless Sass::Util.ruby1_8?
+  @@templates << 'import_charset_1_8' if Sass::Util.ruby1_8?
+
+  @@cache_store = Sass::CacheStores::Memory.new
+
+  def setup
+    Sass::Util.retry_on_windows {FileUtils.mkdir_p tempfile_loc}
+    Sass::Util.retry_on_windows {FileUtils.mkdir_p tempfile_loc(nil,"more_")}
+    set_plugin_opts
+    check_for_updates!
+    reset_mtimes
+  end
+
+  def teardown
+    clean_up_sassc
+    Sass::Plugin.reset!
+    Sass::Util.retry_on_windows {FileUtils.rm_r tempfile_loc}
+    Sass::Util.retry_on_windows {FileUtils.rm_r tempfile_loc(nil,"more_")}
+  end
+
+  @@templates.each do |name|
+    define_method("test_template_renders_correctly (#{name})") do
+      assert_renders_correctly(name)
+    end
+  end
+
+  def test_no_update
+    File.delete(tempfile_loc('basic'))
+    assert_needs_update 'basic'
+    check_for_updates!
+    assert_stylesheet_updated 'basic'
+  end
+
+  def test_update_needed_when_modified
+    touch 'basic'
+    assert_needs_update 'basic'
+    check_for_updates!
+    assert_stylesheet_updated 'basic'
+  end
+
+  def test_update_needed_when_dependency_modified
+    touch 'basic'
+    assert_needs_update 'import'
+    check_for_updates!
+    assert_stylesheet_updated 'basic'
+    assert_stylesheet_updated 'import'
+  end
+
+  def test_update_needed_when_scss_dependency_modified
+    touch 'scss_importee'
+    assert_needs_update 'import'
+    check_for_updates!
+    assert_stylesheet_updated 'scss_importee'
+    assert_stylesheet_updated 'import'
+  end
+
+  def test_scss_update_needed_when_dependency_modified
+    touch 'basic'
+    assert_needs_update 'scss_import'
+    check_for_updates!
+    assert_stylesheet_updated 'basic'
+    assert_stylesheet_updated 'scss_import'
+  end
+
+  def test_update_needed_when_nested_import_dependency_modified
+    touch 'basic'
+    assert_needs_update 'nested_import'
+    check_for_updates!
+    assert_stylesheet_updated 'basic'
+    assert_stylesheet_updated 'scss_import'
+  end
+
+  def test_no_updates_when_always_check_and_always_update_both_false
+    Sass::Plugin.options[:always_update] = false
+    Sass::Plugin.options[:always_check] = false
+
+    touch 'basic'
+    assert_needs_update 'basic'
+    check_for_updates!
+
+    # Check it's still stale
+    assert_needs_update 'basic'
+  end
+
+  def test_full_exception_handling
+    File.delete(tempfile_loc('bork1'))
+    check_for_updates!
+    File.open(tempfile_loc('bork1')) do |file|
+      assert_equal(<<CSS.strip, file.read.split("\n")[0...6].join("\n"))
+/*
+Error: Undefined variable: "$bork".
+        on line 2 of #{template_loc('bork1')}
+
+1: bork
+2:   :bork $bork
+CSS
+    end
+    File.delete(tempfile_loc('bork1'))
+  end
+
+  def test_full_exception_with_block_comment
+    File.delete(tempfile_loc('bork5'))
+    check_for_updates!
+    File.open(tempfile_loc('bork5')) do |file|
+      assert_equal(<<CSS.strip, file.read.split("\n")[0...7].join("\n"))
+/*
+Error: Undefined variable: "$bork".
+        on line 3 of #{template_loc('bork5')}
+
+1: bork
+2:   /* foo *\\/
+3:   :bork $bork
+CSS
+    end
+    File.delete(tempfile_loc('bork1'))
+  end
+
+  def test_single_level_import_loop
+    File.delete(tempfile_loc('single_import_loop'))
+    check_for_updates!
+    File.open(tempfile_loc('single_import_loop')) do |file|
+      assert_equal(<<CSS.strip, file.read.split("\n")[0...2].join("\n"))
+/*
+Error: An @import loop has been found: #{template_loc('single_import_loop')} imports itself
+CSS
+    end
+  end
+
+  def test_double_level_import_loop
+    File.delete(tempfile_loc('double_import_loop1'))
+    check_for_updates!
+    File.open(tempfile_loc('double_import_loop1')) do |file|
+      assert_equal(<<CSS.strip, file.read.split("\n")[0...4].join("\n"))
+/*
+Error: An @import loop has been found:
+           #{template_loc('double_import_loop1')} imports #{template_loc('_double_import_loop2')}
+           #{template_loc('_double_import_loop2')} imports #{template_loc('double_import_loop1')}
+CSS
+    end
+  end
+
+  def test_import_name_cleanup
+    File.delete(tempfile_loc('subdir/import_up1'))
+    check_for_updates!
+    File.open(tempfile_loc('subdir/import_up1')) do |file|
+      assert_equal(<<CSS.strip, file.read.split("\n")[0...5].join("\n"))
+/*
+Error: File to import not found or unreadable: ../subdir/import_up3.scss.
+       Load path: #{template_loc}
+        on line 1 of #{template_loc 'subdir/import_up2'}
+        from line 1 of #{template_loc 'subdir/import_up1'}
+CSS
+    end
+  end
+
+  def test_nonfull_exception_handling
+    old_full_exception = Sass::Plugin.options[:full_exception]
+    Sass::Plugin.options[:full_exception] = false
+
+    File.delete(tempfile_loc('bork1'))
+    assert_raises(Sass::SyntaxError) {check_for_updates!}
+  ensure
+    Sass::Plugin.options[:full_exception] = old_full_exception
+  end
+
+  def test_two_template_directories
+    set_plugin_opts :template_location => {
+      template_loc => tempfile_loc,
+      template_loc(nil,'more_') => tempfile_loc(nil,'more_')
+    }
+    check_for_updates!
+    ['more1', 'more_import'].each { |name| assert_renders_correctly(name, :prefix => 'more_') }
+  end
+
+  def test_two_template_directories_with_line_annotations
+    set_plugin_opts :line_comments => true,
+                    :style => :nested,
+                    :template_location => {
+                      template_loc => tempfile_loc,
+                      template_loc(nil,'more_') => tempfile_loc(nil,'more_')
+                    }
+    check_for_updates!
+    assert_renders_correctly('more1_with_line_comments', 'more1', :prefix => 'more_')
+  end
+
+  def test_doesnt_render_partials
+    assert !File.exist?(tempfile_loc('_partial'))
+  end
+
+  def test_template_location_array
+    assert_equal [[template_loc, tempfile_loc]], Sass::Plugin.template_location_array
+  end
+
+  def test_add_template_location
+    Sass::Plugin.add_template_location(template_loc(nil, "more_"), tempfile_loc(nil, "more_"))
+    assert_equal(
+      [[template_loc, tempfile_loc], [template_loc(nil, "more_"), tempfile_loc(nil, "more_")]],
+      Sass::Plugin.template_location_array)
+
+    touch 'more1', 'more_'
+    touch 'basic'
+    assert_needs_update "more1", "more_"
+    assert_needs_update "basic"
+    check_for_updates!
+    assert_doesnt_need_update "more1", "more_"
+    assert_doesnt_need_update "basic"
+  end
+
+  def test_remove_template_location
+    Sass::Plugin.add_template_location(template_loc(nil, "more_"), tempfile_loc(nil, "more_"))
+    Sass::Plugin.remove_template_location(template_loc, tempfile_loc)
+    assert_equal(
+      [[template_loc(nil, "more_"), tempfile_loc(nil, "more_")]],
+      Sass::Plugin.template_location_array)
+
+    touch 'more1', 'more_'
+    touch 'basic'
+    assert_needs_update "more1", "more_"
+    assert_needs_update "basic"
+    check_for_updates!
+    assert_doesnt_need_update "more1", "more_"
+    assert_needs_update "basic"
+  end
+
+  def test_import_same_name
+    assert_warning <<WARNING do
+WARNING: In #{template_loc}:
+  There are multiple files that match the name "same_name_different_partiality.scss":
+    _same_name_different_partiality.scss
+    same_name_different_partiality.scss
+WARNING
+      touch "_same_name_different_partiality"
+      assert_needs_update "same_name_different_partiality"
+    end
+  end
+
+  # Callbacks
+
+  def test_updated_stylesheet_callback_for_updated_template
+    Sass::Plugin.options[:always_update] = false
+    touch 'basic'
+    assert_no_callback :updated_stylesheet, template_loc("complex"), tempfile_loc("complex") do
+      assert_callbacks(
+        [:updated_stylesheet, template_loc("basic"), tempfile_loc("basic")],
+        [:updated_stylesheet, template_loc("import"), tempfile_loc("import")])
+    end
+  end
+
+  def test_updated_stylesheet_callback_for_fresh_template
+    Sass::Plugin.options[:always_update] = false
+    assert_no_callback :updated_stylesheet
+  end
+
+  def test_updated_stylesheet_callback_for_error_template
+    Sass::Plugin.options[:always_update] = false
+    touch 'bork1'
+    assert_no_callback :updated_stylesheet
+  end
+
+  def test_not_updating_stylesheet_callback_for_fresh_template
+    Sass::Plugin.options[:always_update] = false
+    assert_callback :not_updating_stylesheet, template_loc("basic"), tempfile_loc("basic")
+  end
+
+  def test_not_updating_stylesheet_callback_for_updated_template
+    Sass::Plugin.options[:always_update] = false
+    assert_callback :not_updating_stylesheet, template_loc("complex"), tempfile_loc("complex") do
+      assert_no_callbacks(
+        [:updated_stylesheet, template_loc("basic"), tempfile_loc("basic")],
+        [:updated_stylesheet, template_loc("import"), tempfile_loc("import")])
+    end
+  end
+
+  def test_not_updating_stylesheet_callback_with_never_update
+    Sass::Plugin.options[:never_update] = true
+    assert_no_callback :not_updating_stylesheet
+  end
+
+  def test_not_updating_stylesheet_callback_for_partial
+    Sass::Plugin.options[:always_update] = false
+    assert_no_callback :not_updating_stylesheet, template_loc("_partial"), tempfile_loc("_partial")
+  end
+
+  def test_not_updating_stylesheet_callback_for_error
+    Sass::Plugin.options[:always_update] = false
+    touch 'bork1'
+    assert_no_callback :not_updating_stylesheet, template_loc("bork1"), tempfile_loc("bork1")
+  end
+
+  def test_compilation_error_callback
+    Sass::Plugin.options[:always_update] = false
+    touch 'bork1'
+    assert_callback(:compilation_error,
+      lambda {|e| e.message == 'Undefined variable: "$bork".'},
+      template_loc("bork1"), tempfile_loc("bork1"))
+  end
+
+  def test_compilation_error_callback_for_file_access
+    Sass::Plugin.options[:always_update] = false
+    assert_callback(:compilation_error,
+      lambda {|e| e.is_a?(Errno::ENOENT)},
+      template_loc("nonexistent"), tempfile_loc("nonexistent")) do
+      Sass::Plugin.update_stylesheets([[template_loc("nonexistent"), tempfile_loc("nonexistent")]])
+    end
+  end
+
+  def test_creating_directory_callback
+    Sass::Plugin.options[:always_update] = false
+    dir = File.join(tempfile_loc, "subdir", "nested_subdir")
+    FileUtils.rm_r dir
+    assert_callback :creating_directory, dir
+  end
+
+  ## Regression
+
+  def test_cached_dependencies_update
+    FileUtils.mv(template_loc("basic"), template_loc("basic", "more_"))
+    set_plugin_opts :load_paths => [template_loc(nil, "more_")]
+
+    touch 'basic', 'more_'
+    assert_needs_update "import"
+    check_for_updates!
+    assert_renders_correctly("import")
+  ensure
+    FileUtils.mv(template_loc("basic", "more_"), template_loc("basic"))
+  end
+
+  def test_cached_relative_import
+    old_always_update = Sass::Plugin.options[:always_update]
+    Sass::Plugin.options[:always_update] = true
+    check_for_updates!
+    assert_renders_correctly('subdir/subdir')
+  ensure
+    Sass::Plugin.options[:always_update] = old_always_update
+  end
+
+  def test_cached_if
+    set_plugin_opts :cache_store => Sass::CacheStores::Filesystem.new(tempfile_loc + '/cache')
+    check_for_updates!
+    assert_renders_correctly 'if'
+    check_for_updates!
+    assert_renders_correctly 'if'
+  ensure
+    set_plugin_opts
+  end
+
+  def test_cached_import_option
+    set_plugin_opts :custom => {:whatever => "correct"}
+    check_for_updates!
+    assert_renders_correctly "cached_import_option"
+
+    @@cache_store.reset!
+    set_plugin_opts :custom => nil, :always_update => false
+    check_for_updates!
+    assert_renders_correctly "cached_import_option"
+
+    set_plugin_opts :custom => {:whatever => "correct"}, :always_update => true
+    check_for_updates!
+    assert_renders_correctly "cached_import_option"
+  ensure
+    set_plugin_opts :custom => nil
+  end
+
+ private
+
+  def assert_renders_correctly(*arguments)
+    options = arguments.last.is_a?(Hash) ? arguments.pop : {}
+    prefix = options[:prefix]
+    result_name = arguments.shift
+    tempfile_name = arguments.shift || result_name
+
+    expected_str = File.read(result_loc(result_name, prefix))
+    actual_str = File.read(tempfile_loc(tempfile_name, prefix))
+    unless Sass::Util.ruby1_8?
+      expected_str = expected_str.force_encoding('IBM866') if result_name == 'import_charset_ibm866'
+      actual_str = actual_str.force_encoding('IBM866') if tempfile_name == 'import_charset_ibm866'
+    end
+    expected_lines = expected_str.split("\n")
+    actual_lines = actual_str.split("\n")
+
+    if actual_lines.first == "/*" && expected_lines.first != "/*"
+      assert(false, actual_lines[0..Sass::Util.enum_with_index(actual_lines).find {|l, i| l == 
"*/"}.last].join("\n"))
+    end
+
+    expected_lines.zip(actual_lines).each_with_index do |pair, line|
+      message = "template: #{result_name}\nline:     #{line + 1}"
+      assert_equal(pair.first, pair.last, message)
+    end
+    if expected_lines.size < actual_lines.size
+      assert(false, "#{actual_lines.size - expected_lines.size} Trailing lines found in 
#{tempfile_name}.css: #{actual_lines[expected_lines.size..-1].join('\n')}")
+    end
+  end
+
+  def assert_stylesheet_updated(name)
+    assert_doesnt_need_update name
+
+    # Make sure it isn't an exception
+    expected_lines = File.read(result_loc(name)).split("\n")
+    actual_lines = File.read(tempfile_loc(name)).split("\n")
+    if actual_lines.first == "/*" && expected_lines.first != "/*"
+      assert(false, actual_lines[0..actual_lines.enum_with_index.find {|l, i| l == "*/"}.last].join("\n"))
+    end
+  end
+
+  def assert_callback(name, *expected_args)
+    run = false
+    received_args = nil
+    Sass::Plugin.send("on_#{name}") do |*args|
+      received_args = args
+      run ||= expected_args.zip(received_args).all? do |ea, ra|
+        ea.respond_to?(:call) ? ea.call(ra) : ea == ra
+      end
+    end
+
+    if block_given?
+      Sass::Util.silence_sass_warnings {yield}
+    else
+      check_for_updates!
+    end
+
+    assert run, "Expected #{name} callback to be run with arguments:\n  #{expected_args.inspect}\nHowever, 
it got:\n  #{received_args.inspect}"
+  end
+
+  def assert_no_callback(name, *unexpected_args)
+    Sass::Plugin.send("on_#{name}") do |*a|
+      next unless unexpected_args.empty? || a == unexpected_args
+
+      msg = "Expected #{name} callback not to be run"
+      if !unexpected_args.empty?
+        msg << " with arguments #{unexpected_args.inspect}"
+      elsif !a.empty?
+        msg << ",\n  was run with arguments #{a.inspect}"
+      end
+
+      flunk msg
+    end
+
+    if block_given?
+      yield
+    else
+      check_for_updates!
+    end
+  end
+
+  def assert_callbacks(*args)
+    return check_for_updates! if args.empty?
+    assert_callback(*args.pop) {assert_callbacks(*args)}
+  end
+
+  def assert_no_callbacks(*args)
+    return check_for_updates! if args.empty?
+    assert_no_callback(*args.pop) {assert_no_callbacks(*args)}
+  end
+
+  def check_for_updates!
+    Sass::Util.silence_sass_warnings do
+      Sass::Plugin.check_for_updates
+    end
+  end
+
+  def assert_needs_update(*args)
+    assert(Sass::Plugin::StalenessChecker.stylesheet_needs_update?(tempfile_loc(*args), template_loc(*args)),
+      "Expected #{template_loc(*args)} to need an update.")
+  end
+
+  def assert_doesnt_need_update(*args)
+    assert(!Sass::Plugin::StalenessChecker.stylesheet_needs_update?(tempfile_loc(*args), 
template_loc(*args)),
+      "Expected #{template_loc(*args)} not to need an update.")
+  end
+
+  def touch(*args)
+    FileUtils.touch(template_loc(*args))
+  end
+
+  def reset_mtimes
+    Sass::Plugin::StalenessChecker.dependencies_cache = {}
+    atime = Time.now
+    mtime = Time.now - 5
+    Dir["{#{template_loc},#{tempfile_loc}}/**/*.{css,sass,scss}"].each do |f|
+      Sass::Util.retry_on_windows {File.utime(atime, mtime, f)}
+    end
+  end
+
+  def template_loc(name = nil, prefix = nil)
+    if name
+      scss = absolutize "#{prefix}templates/#{name}.scss"
+      File.exist?(scss) ? scss : absolutize("#{prefix}templates/#{name}.sass")
+    else
+      absolutize "#{prefix}templates"
+    end
+  end
+
+  def tempfile_loc(name = nil, prefix = nil)
+    if name
+      absolutize "#{prefix}tmp/#{name}.css"
+    else
+      absolutize "#{prefix}tmp"
+    end
+  end
+
+  def result_loc(name = nil, prefix = nil)
+    if name
+      absolutize "#{prefix}results/#{name}.css"
+    else
+      absolutize "#{prefix}results"
+    end
+  end
+
+  def set_plugin_opts(overrides = {})
+    Sass::Plugin.options.merge!(
+      :template_location => template_loc,
+      :css_location => tempfile_loc,
+      :style => :compact,
+      :always_update => true,
+      :never_update => false,
+      :full_exception => true,
+      :cache_store => @@cache_store,
+      :sourcemap => :none
+    )
+    Sass::Plugin.options.merge!(overrides)
+  end
+end
+
+class Sass::Engine
+  alias_method :old_render, :render
+
+  def render
+    raise "bork bork bork!" if @template[0] == "{bork now!}"
+    old_render
+  end
+end
diff --git a/backends/css/gems/sass-3.2.12/test/sass/results/alt.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/alt.css
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/results/alt.css
rename to backends/css/gems/sass-3.4.9/test/sass/results/alt.css
diff --git a/backends/css/gems/sass-3.2.12/test/sass/results/basic.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/basic.css
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/results/basic.css
rename to backends/css/gems/sass-3.4.9/test/sass/results/basic.css
diff --git a/backends/css/gems/sass-3.2.12/test/sass/results/cached_import_option.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/cached_import_option.css
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/results/cached_import_option.css
rename to backends/css/gems/sass-3.4.9/test/sass/results/cached_import_option.css
diff --git a/backends/css/gems/sass-3.4.9/test/sass/results/compact.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/compact.css
new file mode 100644
index 0000000..6a4dcb4
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/results/compact.css
@@ -0,0 +1,5 @@
+#main { width: 15em; color: #0000ff; }
+#main p { border-style: dotted; /* Nested comment More nested stuff */ border-width: 2px; }
+#main .cool { width: 100px; }
+
+#left { font-size: 2em; font-weight: bold; float: left; }
diff --git a/backends/css/gems/sass-3.4.9/test/sass/results/complex.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/complex.css
new file mode 100644
index 0000000..d632f1c
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/results/complex.css
@@ -0,0 +1,86 @@
+body { margin: 0; font: 0.85em "Lucida Grande", "Trebuchet MS", Verdana, sans-serif; color: #fff; 
background: url(/images/global_bg.gif); }
+
+#page { width: 900px; margin: 0 auto; background: #440008; border-top-width: 5px; border-top-style: solid; 
border-top-color: #ff8500; }
+
+#header { height: 75px; padding: 0; }
+#header h1 { float: left; width: 274px; height: 75px; margin: 0; background-image: 
url(/images/global_logo.gif); /* Crazy nested comment */ background-repeat: no-repeat; text-indent: -9999px; }
+#header .status { float: right; padding-top: 0.5em; padding-left: 0.5em; padding-right: 0.5em; 
padding-bottom: 0; }
+#header .status p { float: left; margin-top: 0; margin-right: 0.5em; margin-bottom: 0; margin-left: 0; }
+#header .status ul { float: left; margin: 0; padding: 0; }
+#header .status li { list-style-type: none; display: inline; margin: 0 5px; }
+#header .status a:link, #header .status a:visited { color: #ff8500; text-decoration: none; }
+#header .status a:hover { text-decoration: underline; }
+#header .search { float: right; clear: right; margin: 12px 0 0 0; }
+#header .search form { margin: 0; }
+#header .search input { margin: 0 3px 0 0; padding: 2px; border: none; }
+
+#menu { clear: both; text-align: right; height: 20px; border-bottom: 5px solid #006b95; background: #00a4e4; 
}
+#menu .contests ul { margin: 0 5px 0 0; padding: 0; }
+#menu .contests ul li { list-style-type: none; margin: 0 5px; padding: 5px 5px 0 5px; display: inline; 
font-size: 1.1em; color: #fff; background: #00a4e4; }
+#menu .contests a:link, #menu .contests a:visited { color: #fff; text-decoration: none; font-weight: bold; }
+#menu .contests a:hover { text-decoration: underline; }
+
+#content { clear: both; }
+#content .container { clear: both; }
+#content .container .column { float: left; }
+#content .container .column .right { float: right; }
+#content a:link, #content a:visited { color: #93d700; text-decoration: none; }
+#content a:hover { text-decoration: underline; }
+
+#content p, #content div { width: 40em; }
+#content p li, #content p dt, #content p dd, #content div li, #content div dt, #content div dd { color: 
#ddffdd; background-color: #4792bb; }
+#content .container.video .column.left { width: 200px; }
+#content .container.video .column.left .box { margin-top: 10px; }
+#content .container.video .column.left .box p { margin: 0 1em auto 1em; }
+#content .container.video .column.left .box.participants img { float: left; margin: 0 1em auto 1em; border: 
1px solid #6e000d; border-style: solid; }
+#content .container.video .column.left .box.participants h2 { margin: 0 0 10px 0; padding: 0.5em; /* The 
background image is a gif! */ background: #6e000d url(/images/hdr_participant.gif) 2px 2px no-repeat; /* Okay 
check this out Multiline comments Wow dude I mean seriously, WOW */ text-indent: -9999px; border-top-width: 
5px; border-top-style: solid; border-top-color: #a20013; border-right-width: 1px; border-right-style: dotted; 
}
+#content .container.video .column.middle { width: 500px; }
+#content .container.video .column.right { width: 200px; }
+#content .container.video .column.right .box { margin-top: 0; }
+#content .container.video .column.right .box p { margin: 0 1em auto 1em; }
+#content .container.video .column p { margin-top: 0; }
+
+#content.contests .container.information .column.right .box { margin: 1em 0; }
+#content.contests .container.information .column.right .box.videos .thumbnail img { width: 200px; height: 
150px; margin-bottom: 5px; }
+#content.contests .container.information .column.right .box.videos a:link, #content.contests 
.container.information .column.right .box.videos a:visited { color: #93d700; text-decoration: none; }
+#content.contests .container.information .column.right .box.videos a:hover { text-decoration: underline; }
+#content.contests .container.information .column.right .box.votes a { display: block; width: 200px; height: 
60px; margin: 15px 0; background: url(/images/btn_votenow.gif) no-repeat; text-indent: -9999px; outline: 
none; border: none; }
+#content.contests .container.information .column.right .box.votes h2 { margin: 52px 0 10px 0; padding: 
0.5em; background: #6e000d url(/images/hdr_videostats.gif) 2px 2px no-repeat; text-indent: -9999px; 
border-top: 5px solid #a20013; }
+
+#content.contests .container.video .box.videos h2 { margin: 0; padding: 0.5em; background: #6e000d 
url(/images/hdr_newestclips.gif) 2px 2px no-repeat; text-indent: -9999px; border-top: 5px solid #a20013; }
+#content.contests .container.video .box.videos table { width: 100; }
+#content.contests .container.video .box.videos table td { padding: 1em; width: 25; vertical-align: top; }
+#content.contests .container.video .box.videos table td p { margin: 0 0 5px 0; }
+#content.contests .container.video .box.videos table td a:link, #content.contests .container.video 
.box.videos table td a:visited { color: #93d700; text-decoration: none; }
+#content.contests .container.video .box.videos table td a:hover { text-decoration: underline; }
+#content.contests .container.video .box.videos .thumbnail { float: left; }
+#content.contests .container.video .box.videos .thumbnail img { width: 80px; height: 60px; margin: 0 10px 0 
0; border: 1px solid #6e000d; }
+
+#content .container.comments .column { margin-top: 15px; }
+#content .container.comments .column.left { width: 600px; }
+#content .container.comments .column.left .box ol { margin: 0; padding: 0; }
+#content .container.comments .column.left .box li { list-style-type: none; padding: 10px; margin: 0 0 1em 0; 
background: #6e000d; border-top: 5px solid #a20013; }
+#content .container.comments .column.left .box li div { margin-bottom: 1em; }
+#content .container.comments .column.left .box li ul { text-align: right; }
+#content .container.comments .column.left .box li ul li { display: inline; border: none; padding: 0; }
+#content .container.comments .column.right { width: 290px; padding-left: 10px; }
+#content .container.comments .column.right h2 { margin: 0; padding: 0.5em; background: #6e000d 
url(/images/hdr_addcomment.gif) 2px 2px no-repeat; text-indent: -9999px; border-top: 5px solid #a20013; }
+#content .container.comments .column.right .box textarea { width: 290px; height: 100px; border: none; }
+
+#footer { margin-top: 10px; padding: 1.2em 1.5em; background: #ff8500; }
+#footer ul { margin: 0; padding: 0; list-style-type: none; }
+#footer ul li { display: inline; margin: 0 0.5em; color: #440008; }
+#footer ul.links { float: left; }
+#footer ul.links a:link, #footer ul.links a:visited { color: #440008; text-decoration: none; }
+#footer ul.links a:hover { text-decoration: underline; }
+#footer ul.copyright { float: right; }
+
+.clear { clear: both; }
+
+.centered { text-align: center; }
+
+img { border: none; }
+
+button.short { width: 60px; height: 22px; padding: 0 0 2px 0; color: #fff; border: none; background: 
url(/images/btn_short.gif) no-repeat; }
+
+table { border-collapse: collapse; }
diff --git a/backends/css/gems/sass-3.2.12/test/sass/results/compressed.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/compressed.css
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/results/compressed.css
rename to backends/css/gems/sass-3.4.9/test/sass/results/compressed.css
diff --git a/backends/css/gems/sass-3.4.9/test/sass/results/expanded.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/expanded.css
new file mode 100644
index 0000000..05f91fa
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/results/expanded.css
@@ -0,0 +1,19 @@
+#main {
+  width: 15em;
+  color: #0000ff;
+}
+#main p {
+  border-style: dotted;
+  /* Nested comment
+   * More nested stuff */
+  border-width: 2px;
+}
+#main .cool {
+  width: 100px;
+}
+
+#left {
+  font-size: 2em;
+  font-weight: bold;
+  float: left;
+}
diff --git a/backends/css/gems/sass-3.2.12/test/sass/results/filename_fn.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/filename_fn.css
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/results/filename_fn.css
rename to backends/css/gems/sass-3.4.9/test/sass/results/filename_fn.css
diff --git a/backends/css/gems/sass-3.2.12/test/sass/results/if.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/if.css
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/results/if.css
rename to backends/css/gems/sass-3.4.9/test/sass/results/if.css
diff --git a/backends/css/gems/sass-3.4.9/test/sass/results/import.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/import.css
new file mode 100644
index 0000000..e728382
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/results/import.css
@@ -0,0 +1,31 @@
+ import url(basic.css);
+ import url(../results/complex.css);
+imported { otherconst: hello; myconst: goodbye; pre-mixin: here; }
+
+body { font: Arial; background: blue; }
+
+#page { width: 700px; height: 100; }
+#page #header { height: 300px; }
+#page #header h1 { font-size: 50px; color: blue; }
+
+#content.user.show #container.top #column.left { width: 100px; }
+#content.user.show #container.top #column.right { width: 600px; }
+#content.user.show #container.bottom { background: brown; }
+
+midrule { inthe: middle; }
+
+scss { imported: yes; }
+
+body { font: Arial; background: blue; }
+
+#page { width: 700px; height: 100; }
+#page #header { height: 300px; }
+#page #header h1 { font-size: 50px; color: blue; }
+
+#content.user.show #container.top #column.left { width: 100px; }
+#content.user.show #container.top #column.right { width: 600px; }
+#content.user.show #container.bottom { background: brown; }
+
+#foo { background-color: #baf; }
+
+nonimported { myconst: hello; otherconst: goodbye; post-mixin: here; }
diff --git a/backends/css/gems/sass-3.2.12/test/sass/results/import_charset.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/import_charset.css
similarity index 100%
copy from backends/css/gems/sass-3.2.12/test/sass/results/import_charset.css
copy to backends/css/gems/sass-3.4.9/test/sass/results/import_charset.css
diff --git a/backends/css/gems/sass-3.2.12/test/sass/results/import_charset_1_8.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/import_charset_1_8.css
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/results/import_charset_1_8.css
rename to backends/css/gems/sass-3.4.9/test/sass/results/import_charset_1_8.css
diff --git a/backends/css/gems/sass-3.2.12/test/sass/results/import_charset.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/import_charset_ibm866.css
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/results/import_charset.css
rename to backends/css/gems/sass-3.4.9/test/sass/results/import_charset_ibm866.css
diff --git a/backends/css/gems/sass-3.2.12/test/sass/results/import_content.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/import_content.css
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/results/import_content.css
rename to backends/css/gems/sass-3.4.9/test/sass/results/import_content.css
diff --git a/backends/css/gems/sass-3.2.12/test/sass/results/line_numbers.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/line_numbers.css
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/results/line_numbers.css
rename to backends/css/gems/sass-3.4.9/test/sass/results/line_numbers.css
diff --git a/backends/css/gems/sass-3.4.9/test/sass/results/mixins.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/mixins.css
new file mode 100644
index 0000000..5d87f98
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/results/mixins.css
@@ -0,0 +1,95 @@
+#main {
+  width: 15em;
+  color: #0000ff;
+}
+#main p {
+  border-top-width: 2px;
+  border-top-color: #fc0;
+  border-left-width: 1px;
+  border-left-color: #000;
+  -moz-border-radius: 10px;
+  border-style: dotted;
+  border-width: 2px;
+}
+#main .cool {
+  width: 100px;
+}
+
+#left {
+  border-top-width: 2px;
+  border-top-color: #fc0;
+  border-left-width: 1px;
+  border-left-color: #000;
+  -moz-border-radius: 10px;
+  font-size: 2em;
+  font-weight: bold;
+  float: left;
+}
+
+#right {
+  border-top-width: 2px;
+  border-top-color: #fc0;
+  border-left-width: 1px;
+  border-left-color: #000;
+  -moz-border-radius: 10px;
+  color: #f00;
+  font-size: 20px;
+  float: right;
+}
+
+.bordered {
+  border-top-width: 2px;
+  border-top-color: #fc0;
+  border-left-width: 1px;
+  border-left-color: #000;
+  -moz-border-radius: 10px;
+}
+
+.complex {
+  color: #f00;
+  font-size: 20px;
+  text-decoration: none;
+}
+.complex:after {
+  content: ".";
+  display: block;
+  height: 0;
+  clear: both;
+  visibility: hidden;
+}
+* html .complex {
+  height: 1px;
+  color: #f00;
+  font-size: 20px;
+}
+
+.more-complex {
+  color: #f00;
+  font-size: 20px;
+  text-decoration: none;
+  display: inline;
+  -webkit-nonsense-top-right: 1px;
+  -webkit-nonsense-bottom-left: 1px;
+}
+.more-complex:after {
+  content: ".";
+  display: block;
+  height: 0;
+  clear: both;
+  visibility: hidden;
+}
+* html .more-complex {
+  height: 1px;
+  color: #f00;
+  font-size: 20px;
+}
+.more-complex a:hover {
+  text-decoration: underline;
+  color: #f00;
+  font-size: 20px;
+  border-top-width: 2px;
+  border-top-color: #fc0;
+  border-left-width: 1px;
+  border-left-color: #000;
+  -moz-border-radius: 10px;
+}
diff --git a/backends/css/gems/sass-3.2.12/test/sass/results/multiline.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/multiline.css
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/results/multiline.css
rename to backends/css/gems/sass-3.4.9/test/sass/results/multiline.css
diff --git a/backends/css/gems/sass-3.4.9/test/sass/results/nested.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/nested.css
new file mode 100644
index 0000000..061e6c1
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/results/nested.css
@@ -0,0 +1,22 @@
+#main {
+  width: 15em;
+  color: #0000ff; }
+  #main p {
+    border-style: dotted;
+    /* Nested comment
+     * More nested stuff */
+    border-width: 2px; }
+  #main .cool {
+    width: 100px; }
+
+#left {
+  font-size: 2em;
+  font-weight: bold;
+  float: left; }
+
+#right .header {
+  border-style: solid; }
+#right .body {
+  border-style: dotted; }
+#right .footer {
+  border-style: dashed; }
diff --git a/backends/css/gems/sass-3.2.12/test/sass/results/options.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/options.css
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/results/options.css
rename to backends/css/gems/sass-3.4.9/test/sass/results/options.css
diff --git a/backends/css/gems/sass-3.4.9/test/sass/results/parent_ref.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/parent_ref.css
new file mode 100644
index 0000000..f384cfe
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/results/parent_ref.css
@@ -0,0 +1,13 @@
+a { color: #000; }
+a:hover { color: #f00; }
+
+p, div { width: 100em; }
+p foo, div foo { width: 10em; }
+p:hover, p bar, div:hover, div bar { height: 20em; }
+
+#cool { border-style: solid; border-width: 2em; }
+.ie7 #cool, .ie6 #cool { content: string("Totally not cool."); }
+.firefox #cool { content: string("Quite cool."); }
+
+.wow, .snazzy { font-family: fantasy; }
+.wow:hover, .wow:visited, .snazzy:hover, .snazzy:visited { font-weight: bold; }
diff --git a/backends/css/gems/sass-3.4.9/test/sass/results/script.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/script.css
new file mode 100644
index 0000000..8f39d29
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/results/script.css
@@ -0,0 +1,16 @@
+#main { content: Hello\!; qstr: 'Quo"ted"!'; hstr: Hyph-en\!; width: 30em; background-color: #000; color: 
#ffa; short-color: #123; named-color: olive; con: "foo" bar 9 hi there "boom"; con2: "noquo" quo; }
+#main #sidebar { background-color: #00ff98; num-normal: 10; num-dec: 10.2; num-dec0: 99; num-neg: -10; esc: 
10\+12; many: 6; order: 7; complex: #4c9db1hi16; }
+
+#plus { num-num: 7; num-num-un: 25em; num-num-un2: 23em; num-num-neg: 9.87; num-str: 100px; num-col: 
#b7b7b7; num-perc: 31%; str-str: "hi there"; str-str2: "hi there"; str-col: "14em solid #123"; str-num: 
"times: 13"; col-num: #ff7b9d; col-col: #5173ff; }
+
+#minus { num-num: 900; col-num: #f9f9f4; col-col: #000035; unary-num: -1; unary-const: 10; unary-paren: -11; 
unary-two: 12; unary-many: 12; unary-crazy: -15; }
+
+#times { num-num: 7; num-col: #7496b8; col-num: #092345; col-col: #243648; }
+
+#div { num-num: 3.33333; num-num2: 3.33333; col-num: #092345; col-col: #0b0d0f; comp: 1px; }
+
+#mod { num-num: 2; col-col: #0f0e05; col-num: #020001; }
+
+#const { escaped-quote: \$foo \!bar; default: Hello\! !important; }
+
+#regression { a: 4; }
diff --git a/backends/css/gems/sass-3.4.9/test/sass/results/scss_import.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/scss_import.css
new file mode 100644
index 0000000..e728382
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/results/scss_import.css
@@ -0,0 +1,31 @@
+ import url(basic.css);
+ import url(../results/complex.css);
+imported { otherconst: hello; myconst: goodbye; pre-mixin: here; }
+
+body { font: Arial; background: blue; }
+
+#page { width: 700px; height: 100; }
+#page #header { height: 300px; }
+#page #header h1 { font-size: 50px; color: blue; }
+
+#content.user.show #container.top #column.left { width: 100px; }
+#content.user.show #container.top #column.right { width: 600px; }
+#content.user.show #container.bottom { background: brown; }
+
+midrule { inthe: middle; }
+
+scss { imported: yes; }
+
+body { font: Arial; background: blue; }
+
+#page { width: 700px; height: 100; }
+#page #header { height: 300px; }
+#page #header h1 { font-size: 50px; color: blue; }
+
+#content.user.show #container.top #column.left { width: 100px; }
+#content.user.show #container.top #column.right { width: 600px; }
+#content.user.show #container.bottom { background: brown; }
+
+#foo { background-color: #baf; }
+
+nonimported { myconst: hello; otherconst: goodbye; post-mixin: here; }
diff --git a/backends/css/gems/sass-3.2.12/test/sass/results/scss_importee.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/scss_importee.css
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/results/scss_importee.css
rename to backends/css/gems/sass-3.4.9/test/sass/results/scss_importee.css
diff --git a/backends/css/gems/sass-3.2.12/test/sass/results/subdir/nested_subdir/nested_subdir.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/subdir/nested_subdir/nested_subdir.css
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/results/subdir/nested_subdir/nested_subdir.css
rename to backends/css/gems/sass-3.4.9/test/sass/results/subdir/nested_subdir/nested_subdir.css
diff --git a/backends/css/gems/sass-3.2.12/test/sass/results/subdir/subdir.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/subdir/subdir.css
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/results/subdir/subdir.css
rename to backends/css/gems/sass-3.4.9/test/sass/results/subdir/subdir.css
diff --git a/backends/css/gems/sass-3.2.12/test/sass/results/units.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/units.css
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/results/units.css
rename to backends/css/gems/sass-3.4.9/test/sass/results/units.css
diff --git a/backends/css/gems/sass-3.2.12/test/sass/results/warn.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/warn.css
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/results/warn.css
rename to backends/css/gems/sass-3.4.9/test/sass/results/warn.css
diff --git a/backends/css/gems/sass-3.2.12/test/sass/results/warn_imported.css 
b/backends/css/gems/sass-3.4.9/test/sass/results/warn_imported.css
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/results/warn_imported.css
rename to backends/css/gems/sass-3.4.9/test/sass/results/warn_imported.css
diff --git a/backends/css/gems/sass-3.4.9/test/sass/script_conversion_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/script_conversion_test.rb
new file mode 100755
index 0000000..cfe13e0
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/script_conversion_test.rb
@@ -0,0 +1,333 @@
+#!/usr/bin/env ruby
+# -*- coding: utf-8 -*-
+require File.dirname(__FILE__) + '/../test_helper'
+require 'sass/engine'
+
+class SassScriptConversionTest < MiniTest::Test
+  def test_bool
+    assert_renders "true"
+    assert_renders "false"
+  end
+
+  def test_color
+    assert_renders "#abcdef"
+    assert_renders "blue"
+    assert_renders "rgba(0, 1, 2, 0.2)"
+    assert_renders "#abc"
+    assert_renders "#0000ff"
+  end
+
+  def test_number
+    assert_renders "10"
+    assert_renders "10.35"
+    assert_renders "12px"
+    assert_renders "12.45px"
+
+    assert_equal "12.34568", render("12.345678901")
+  end
+
+  def test_string
+    assert_renders '"foo"'
+    assert_renders '"bar baz"'
+    assert_equal '"baz bang"', render("'baz bang'")
+  end
+
+  def test_string_quotes
+    assert_equal "'quote\"quote'", render('"quote\\"quote"')
+    assert_equal '"quote\'quote"', render("'quote\\'quote'")
+    assert_renders '"quote\'quote\\"quote"'
+    assert_equal '"quote\'quote\\"quote"', render("'quote\\'quote\"quote'")
+  end
+
+  def test_string_escapes
+    assert_renders '"foo\\\\bar"'
+  end
+
+  def test_funcall
+    assert_renders "foo(true, blue)"
+    assert_renders "hsla(20deg, 30%, 50%, 0.3)"
+    assert_renders "blam()"
+
+    assert_renders "-\xC3\xBFoo(12px)"
+    assert_renders "-foo(12px)"
+  end
+
+  def test_funcall_with_keyword_args
+    assert_renders "foo(arg1, arg2, $karg1: val, $karg2: val2)"
+    assert_renders "foo($karg1: val, $karg2: val2)"
+  end
+
+  def test_funcall_with_hyphen_conversion_keyword_arg
+    assert_renders "foo($a-b_c: val)"
+  end
+
+  def test_url
+    assert_renders "url(foo.gif)"
+    assert_renders "url($var)"
+    assert_renders "url(\#{$var}/flip.gif)"
+  end
+
+  def test_variable
+    assert_renders "$foo-bar"
+    assert_renders "$flaznicate"
+  end
+
+  def test_null
+    assert_renders "null"
+  end
+
+  def test_empty_list
+    assert_renders "()"
+  end
+
+  def test_list_in_args
+    assert_renders "foo((a, b, c))"
+    assert_renders "foo($arg: (a, b, c))"
+    assert_renders "foo(a, b, (a, b, c)...)"
+  end
+
+  def test_singleton_list
+    assert_renders "(1,)"
+    assert_renders "(1 2 3,)"
+    assert_renders "((1, 2, 3),)"
+  end
+
+  def test_map
+    assert_renders "(foo: bar)"
+    assert_renders "(foo: bar, baz: bip)"
+    assert_renders "(foo: bar, baz: (bip: bap))"
+  end
+
+  def test_map_in_list
+    assert_renders "(foo: bar) baz"
+    assert_renders "(foo: bar), (baz: bip)"
+  end
+
+  def test_list_in_map
+    assert_renders "(foo: bar baz)"
+    assert_renders "(foo: (bar, baz), bip: bop)"
+  end
+
+  def test_selector
+    assert_renders "&"
+  end
+
+  def self.test_precedence(outer, inner)
+    op_outer = Sass::Script::Lexer::OPERATORS_REVERSE[outer]
+    op_inner = Sass::Script::Lexer::OPERATORS_REVERSE[inner]
+    class_eval <<RUBY
+      def test_precedence_#{outer}_#{inner}
+        assert_renders "$foo #{op_outer} $bar #{op_inner} $baz"
+        assert_renders "$foo #{op_inner} $bar #{op_outer} $baz"
+
+        assert_renders "($foo #{op_outer} $bar) #{op_inner} $baz"
+        assert_renders "$foo #{op_inner} ($bar #{op_outer} $baz)"
+
+        assert_equal "$foo #{op_outer} $bar #{op_inner} $baz",
+          render("$foo #{op_outer} ($bar #{op_inner} $baz)")
+        assert_equal "$foo #{op_inner} $bar #{op_outer} $baz",
+          render("($foo #{op_inner} $bar) #{op_outer} $baz")
+      end
+RUBY
+  end
+
+  def self.assert_associative(op_name, sibling_name)
+    op = separator_for(op_name)
+    sibling = separator_for(sibling_name)
+    class_eval <<RUBY
+      def test_associative_#{op_name}_#{sibling_name}
+        assert_renders "$foo#{op}$bar#{op}$baz"
+
+        assert_equal "$foo#{op}$bar#{op}$baz",
+          render("$foo#{op}($bar#{op}$baz)")
+        assert_equal "$foo#{op}$bar#{op}$baz",
+          render("($foo#{op}$bar)#{op}$baz")
+
+        assert_equal "$foo#{op}$bar#{sibling}$baz",
+          render("$foo#{op}($bar#{sibling}$baz)")
+        assert_equal "$foo#{sibling}$bar#{op}$baz",
+          render("($foo#{sibling}$bar)#{op}$baz")
+      end
+RUBY
+  end
+
+  def self.separator_for(op_name)
+    case op_name
+    when :comma; ", "
+    when :space; " "
+    else; " #{Sass::Script::Lexer::OPERATORS_REVERSE[op_name]} "
+    end
+  end
+
+  def self.assert_non_associative(op_name, sibling_name)
+    op = Sass::Script::Lexer::OPERATORS_REVERSE[op_name]
+    sibling = Sass::Script::Lexer::OPERATORS_REVERSE[sibling_name]
+    class_eval <<RUBY
+      def test_non_associative_#{op_name}_#{sibling_name}
+        assert_renders "$foo #{op} $bar #{op} $baz"
+
+        assert_renders "$foo #{op} ($bar #{op} $baz)"
+        assert_equal "$foo #{op} $bar #{op} $baz",
+          render("($foo #{op} $bar) #{op} $baz")
+
+        assert_renders "$foo #{op} ($bar #{sibling} $baz)"
+        assert_equal "$foo #{sibling} $bar #{op} $baz",
+          render("($foo #{sibling} $bar) #{op} $baz")
+      end
+RUBY
+  end
+
+  test_precedence :or, :and
+  test_precedence :and, :eq
+  test_precedence :and, :neq
+  test_precedence :eq, :gt
+  test_precedence :eq, :gte
+  test_precedence :eq, :lt
+  test_precedence :eq, :lte
+  test_precedence :gt, :plus
+  test_precedence :gt, :minus
+  test_precedence :plus, :times
+  test_precedence :plus, :div
+  test_precedence :plus, :mod
+
+  assert_associative :plus, :minus
+  assert_associative :times, :div
+  assert_associative :times, :mod
+
+  assert_non_associative :minus, :plus
+  assert_non_associative :div, :times
+  assert_non_associative :mod, :times
+  assert_non_associative :gt, :gte
+  assert_non_associative :gte, :lt
+  assert_non_associative :lt, :lte
+  assert_non_associative :lte, :gt
+
+  def test_comma_precedence
+    assert_renders "$foo, $bar, $baz"
+
+    assert_renders "$foo ($bar, $baz)"
+    assert_renders "($foo, $bar) $baz"
+
+    assert_equal "$foo, $bar $baz", render("$foo, ($bar $baz)")
+    assert_equal "$foo $bar, $baz", render("($foo $bar), $baz")
+
+    assert_equal "$foo, ($bar, $baz)", render("$foo, ($bar, $baz)")
+    assert_equal "($foo, $bar), $baz", render("($foo, $bar), $baz")
+  end
+
+  def test_space_precedence
+    assert_renders "$foo $bar $baz"
+
+    assert_renders "$foo or ($bar $baz)"
+    assert_renders "($foo $bar) or $baz"
+
+    assert_equal "$foo $bar or $baz", render("$foo ($bar or $baz)")
+    assert_equal "$foo or $bar $baz", render("($foo or $bar) $baz")
+
+    assert_equal "$foo ($bar $baz)", render("$foo ($bar $baz)")
+    assert_equal "($foo $bar) $baz", render("($foo $bar) $baz")
+  end
+
+  def test_unary_op
+    assert_renders "-12px"
+    assert_renders '/"foo"'
+    assert_renders 'not true'
+
+    assert_renders "-(foo(12px))"
+    assert_renders "-(-foo(12px))"
+    assert_renders "-(_foo(12px))"
+    assert_renders "-(\xC3\xBFoo(12px))"
+    assert_renders "-(blue)"
+
+    assert_equal 'not true or false', render('(not true) or false')
+    assert_equal 'not (true or false)', render('not (true or false)')
+  end
+
+  def test_interpolation
+    assert_renders "$foo\#{$bar}$baz"
+    assert_renders "$foo\#{$bar} $baz"
+    assert_renders "$foo \#{$bar}$baz"
+    assert_renders "$foo \#{$bar} $baz"
+    assert_renders "$foo \#{$bar}\#{$bang} $baz"
+    assert_renders "$foo \#{$bar} \#{$bang} $baz"
+    assert_renders "\#{$bar}$baz"
+    assert_renders "$foo\#{$bar}"
+    assert_renders "\#{$bar}"
+  end
+
+  def test_interpolation_in_function
+    assert_renders 'flabnabbit(#{1 + "foo"})'
+    assert_renders 'flabnabbit($foo #{1 + "foo"}$baz)'
+    assert_renders 'flabnabbit($foo #{1 + "foo"}#{2 + "bar"} $baz)'
+  end
+
+  def test_interpolation_in_string_function
+    assert_renders 'calc(#{1 + "foo"})'
+    assert_renders 'calc(foo#{1 + "foo"}baz)'
+  end
+
+  def test_interpolation_near_operators
+    assert_renders '#{1 + 2} , #{3 + 4}'
+    assert_renders '#{1 + 2}, #{3 + 4}'
+    assert_renders '#{1 + 2} ,#{3 + 4}'
+    assert_renders '#{1 + 2},#{3 + 4}'
+    assert_renders '#{1 + 2}, #{3 + 4}, #{5 + 6}'
+    assert_renders '3, #{3 + 4}, 11'
+
+    assert_renders '3 / #{3 + 4}'
+    assert_renders '3 /#{3 + 4}'
+    assert_renders '3/ #{3 + 4}'
+    assert_renders '3/#{3 + 4}'
+
+    assert_renders '#{1 + 2} * 7'
+    assert_renders '#{1 + 2}* 7'
+    assert_renders '#{1 + 2} *7'
+    assert_renders '#{1 + 2}*7'
+
+    assert_renders '-#{1 + 2}'
+    assert_renders '- #{1 + 2}'
+
+    assert_renders '5 + #{1 + 2} * #{3 + 4}'
+    assert_renders '5 +#{1 + 2} * #{3 + 4}'
+    assert_renders '5+#{1 + 2} * #{3 + 4}'
+    assert_renders '#{1 + 2} * #{3 + 4} + 5'
+    assert_renders '#{1 + 2} * #{3 + 4}+ 5'
+    assert_renders '#{1 + 2} * #{3 + 4}+5'
+
+    assert_equal '5 / #{1 + 2} + #{3 + 4}', render('5 / (#{1 + 2} + #{3 + 4})')
+    assert_equal '5 / #{1 + 2} + #{3 + 4}', render('5 /(#{1 + 2} + #{3 + 4})')
+    assert_equal '5 / #{1 + 2} + #{3 + 4}', render('5 /( #{1 + 2} + #{3 + 4} )')
+    assert_equal '#{1 + 2} + #{3 + 4} / 5', render('(#{1 + 2} + #{3 + 4}) / 5')
+    assert_equal '#{1 + 2} + #{3 + 4} / 5', render('(#{1 + 2} + #{3 + 4})/ 5')
+    assert_equal '#{1 + 2} + #{3 + 4} / 5', render('( #{1 + 2} + #{3 + 4} )/ 5')
+
+    assert_renders '#{1 + 2} + 2 + 3'
+    assert_renders '#{1 + 2} +2 + 3'
+  end
+
+  def test_string_interpolation
+    assert_renders '"foo#{$bar}baz"'
+    assert_renders '"foo #{$bar}baz"'
+    assert_renders '"foo#{$bar} baz"'
+    assert_renders '"foo #{$bar} baz"'
+    assert_renders '"foo #{$bar}#{$bang} baz"'
+    assert_renders '"foo #{$bar} #{$bang} baz"'
+    assert_renders '"#{$bar}baz"'
+    assert_renders '"foo#{$bar}"'
+    assert_equal '#{$bar}', render('"#{$bar}"')
+
+    assert_equal '"foo#{$bar}baz"', render("'foo\#{$bar}baz'")
+  end
+
+  private
+
+  def assert_renders(script, options = {})
+    assert_equal(script, render(script, options))
+  end
+
+  def render(script, options = {})
+    munge_filename(options)
+    node = Sass::Script.parse(script, 1, 0, options)
+    node.to_sass
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/test/sass/script_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/script_test.rb
new file mode 100755
index 0000000..f679abb
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/script_test.rb
@@ -0,0 +1,1170 @@
+#!/usr/bin/env ruby
+# -*- coding: utf-8 -*-
+require File.dirname(__FILE__) + '/../test_helper'
+require 'sass/engine'
+
+module Sass::Script::Functions::UserFunctions
+  def assert_options(val)
+    val.options[:foo]
+    Sass::Script::Value::String.new("Options defined!")
+  end
+
+  def arg_error
+    assert_options
+  end
+end
+
+module Sass::Script::Functions
+  include Sass::Script::Functions::UserFunctions
+end
+
+class SassScriptTest < MiniTest::Test
+  include Sass::Script
+
+  def test_color_clamps_input
+    assert_equal 0, Sass::Script::Value::Color.new([1, 2, -1]).blue
+    assert_equal 255, Sass::Script::Value::Color.new([256, 2, 3]).red
+  end
+
+  def test_color_clamps_rgba_input
+    assert_equal 1, Sass::Script::Value::Color.new([1, 2, 3, 1.1]).alpha
+    assert_equal 0, Sass::Script::Value::Color.new([1, 2, 3, -0.1]).alpha
+  end
+
+  def test_string_escapes
+    assert_equal "'", resolve("\"'\"")
+    assert_equal '"', resolve("\"\\\"\"")
+    assert_equal "\\", resolve("\"\\\\\"")
+    assert_equal "☃", resolve("\"\\2603\"")
+    assert_equal "☃f", resolve("\"\\2603 f\"")
+    assert_equal "☃x", resolve("\"\\2603x\"")
+    assert_equal "\\2603", resolve("\"\\\\2603\"")
+
+    # U+FFFD is the replacement character, "�".
+    assert_equal [0xFFFD].pack("U"), resolve("\"\\0\"")
+    assert_equal [0xFFFD].pack("U"), resolve("\"\\FFFFFF\"")
+    assert_equal [0xFFFD].pack("U"), resolve("\"\\D800\"")
+    assert_equal [0xD7FF].pack("U"), resolve("\"\\D7FF\"")
+    assert_equal [0xFFFD].pack("U"), resolve("\"\\DFFF\"")
+    assert_equal [0xE000].pack("U"), resolve("\"\\E000\"")
+  end
+
+  def test_string_escapes_are_resolved_before_operators
+    assert_equal "true", resolve('"abc" == "\61\62\63"')
+  end
+
+  def test_string_quote
+    assert_equal '"foo"', resolve_quoted('"foo"')
+    assert_equal "'f\"oo'", resolve_quoted('"f\"oo"')
+    assert_equal "\"f'oo\"", resolve_quoted("'f\\'oo'")
+    assert_equal "\"f'o\\\"o\"", resolve_quoted("'f\\'o\"o'")
+    assert_equal '"foo bar"', resolve_quoted('"foo\20 bar"')
+    assert_equal '"foo\a bar"', resolve_quoted('"foo\a bar"')
+    assert_equal '"x\ay"', resolve_quoted('"x\a y"')
+    assert_equal '"\a  "', resolve_quoted('"\a\20"')
+    assert_equal '"\a abcdef"', resolve_quoted('"\a abcdef"')
+    assert_equal '"☃abcdef"', resolve_quoted('"\2603 abcdef"')
+    assert_equal '"\\\\"', resolve_quoted('"\\\\"')
+    assert_equal '"foobar"', resolve_quoted("\"foo\\\nbar\"")
+  end
+
+  def test_color_names
+    assert_equal "white", resolve("white")
+    assert_equal "#ffffff", resolve("#ffffff")
+    assert_equal "#fffffe", resolve("white - #000001")
+    assert_equal "transparent", resolve("transparent")
+    assert_equal "transparent", resolve("rgba(0, 0, 0, 0)")
+  end
+
+  def test_rgba_color_literals
+    assert_equal Sass::Script::Value::Color.new([1, 2, 3, 0.75]), eval("rgba(1, 2, 3, 0.75)")
+    assert_equal "rgba(1, 2, 3, 0.75)", resolve("rgba(1, 2, 3, 0.75)")
+
+    assert_equal Sass::Script::Value::Color.new([1, 2, 3, 0]), eval("rgba(1, 2, 3, 0)")
+    assert_equal "rgba(1, 2, 3, 0)", resolve("rgba(1, 2, 3, 0)")
+
+    assert_equal Sass::Script::Value::Color.new([1, 2, 3]), eval("rgba(1, 2, 3, 1)")
+    assert_equal Sass::Script::Value::Color.new([1, 2, 3, 1]), eval("rgba(1, 2, 3, 1)")
+    assert_equal "#010203", resolve("rgba(1, 2, 3, 1)")
+    assert_equal "white", resolve("rgba(255, 255, 255, 1)")
+  end
+
+  def test_rgba_color_math
+    assert_equal "rgba(50, 50, 100, 0.35)", resolve("rgba(1, 1, 2, 0.35) * rgba(50, 50, 50, 0.35)")
+    assert_equal "rgba(52, 52, 52, 0.25)", resolve("rgba(2, 2, 2, 0.25) + rgba(50, 50, 50, 0.25)")
+
+    assert_raise_message(Sass::SyntaxError, "Alpha channels must be equal: rgba(1, 2, 3, 0.15) + rgba(50, 
50, 50, 0.75)") do
+      resolve("rgba(1, 2, 3, 0.15) + rgba(50, 50, 50, 0.75)")
+    end
+    assert_raise_message(Sass::SyntaxError, "Alpha channels must be equal: #123456 * rgba(50, 50, 50, 
0.75)") do
+      resolve("#123456 * rgba(50, 50, 50, 0.75)")
+    end
+    assert_raise_message(Sass::SyntaxError, "Alpha channels must be equal: rgba(50, 50, 50, 0.75) / 
#123456") do
+      resolve("rgba(50, 50, 50, 0.75) / #123456")
+    end
+  end
+
+  def test_rgba_number_math
+    assert_equal "rgba(49, 49, 49, 0.75)", resolve("rgba(50, 50, 50, 0.75) - 1")
+    assert_equal "rgba(100, 100, 100, 0.75)", resolve("rgba(50, 50, 50, 0.75) * 2")
+  end
+
+  def test_rgba_rounding
+    assert_equal "rgba(10, 1, 0, 0.12346)", resolve("rgba(10.0, 1.23456789, 0.0, 0.1234567)")
+  end
+
+  def test_compressed_colors
+    assert_equal "#123456", resolve("#123456", :style => :compressed)
+    assert_equal "rgba(1,2,3,0.5)", resolve("rgba(1, 2, 3, 0.5)", :style => :compressed)
+    assert_equal "#123", resolve("#112233", :style => :compressed)
+    assert_equal "#000", resolve("black", :style => :compressed)
+    assert_equal "red", resolve("#f00", :style => :compressed)
+    assert_equal "blue", resolve("blue", :style => :compressed)
+    assert_equal "navy", resolve("#000080", :style => :compressed)
+    assert_equal "navy #fff", resolve("#000080 white", :style => :compressed)
+    assert_equal "This color is #fff", resolve('"This color is #{ white }"', :style => :compressed)
+    assert_equal "transparent", resolve("rgba(0, 0, 0, 0)", :style => :compressed)
+  end
+
+  def test_compressed_comma
+    # assert_equal "foo,bar,baz", resolve("foo, bar, baz", :style => :compressed)
+    # assert_equal "foo,#baf,baz", resolve("foo, #baf, baz", :style => :compressed)
+    assert_equal "foo,#baf,red", resolve("foo, #baf, #f00", :style => :compressed)
+  end
+
+  def test_implicit_strings
+    assert_equal Sass::Script::Value::String.new("foo"), eval("foo")
+    assert_equal Sass::Script::Value::String.new("foo/bar"), eval("foo/bar")
+  end
+
+  def test_basic_interpolation
+    assert_equal "foo3bar", resolve("foo\#{1 + 2}bar")
+    assert_equal "foo3 bar", resolve("foo\#{1 + 2} bar")
+    assert_equal "foo 3bar", resolve("foo \#{1 + 2}bar")
+    assert_equal "foo 3 bar", resolve("foo \#{1 + 2} bar")
+    assert_equal "foo 35 bar", resolve("foo \#{1 + 2}\#{2 + 3} bar")
+    assert_equal "foo 3 5 bar", resolve("foo \#{1 + 2} \#{2 + 3} bar")
+    assert_equal "3bar", resolve("\#{1 + 2}bar")
+    assert_equal "foo3", resolve("foo\#{1 + 2}")
+    assert_equal "3", resolve("\#{1 + 2}")
+  end
+
+  def test_interpolation_in_function
+    assert_equal 'flabnabbit(1foo)', resolve('flabnabbit(#{1 + "foo"})')
+    assert_equal 'flabnabbit(foo 1foobaz)', resolve('flabnabbit(foo #{1 + "foo"}baz)')
+    assert_equal('flabnabbit(foo 1foo2bar baz)',
+      resolve('flabnabbit(foo #{1 + "foo"}#{2 + "bar"} baz)'))
+  end
+
+  def test_interpolation_near_operators
+    assert_equal '3 , 7', resolve('#{1 + 2} , #{3 + 4}')
+    assert_equal '3, 7', resolve('#{1 + 2}, #{3 + 4}')
+    assert_equal '3 ,7', resolve('#{1 + 2} ,#{3 + 4}')
+    assert_equal '3,7', resolve('#{1 + 2},#{3 + 4}')
+    assert_equal '3, 7, 11', resolve('#{1 + 2}, #{3 + 4}, #{5 + 6}')
+    assert_equal '3, 7, 11', resolve('3, #{3 + 4}, 11')
+    assert_equal '3, 7, 11', resolve('3, 7, #{5 + 6}')
+
+    assert_equal '3 / 7', resolve('3 / #{3 + 4}')
+    assert_equal '3 /7', resolve('3 /#{3 + 4}')
+    assert_equal '3/ 7', resolve('3/ #{3 + 4}')
+    assert_equal '3/7', resolve('3/#{3 + 4}')
+
+    assert_equal '3 * 7', resolve('#{1 + 2} * 7')
+    assert_equal '3* 7', resolve('#{1 + 2}* 7')
+    assert_equal '3 *7', resolve('#{1 + 2} *7')
+    assert_equal '3*7', resolve('#{1 + 2}*7')
+
+    assert_equal '-3', resolve('-#{1 + 2}')
+    assert_equal '- 3', resolve('- #{1 + 2}')
+
+    assert_equal '5 + 3 * 7', resolve('5 + #{1 + 2} * #{3 + 4}')
+    assert_equal '5 +3 * 7', resolve('5 +#{1 + 2} * #{3 + 4}')
+    assert_equal '5+3 * 7', resolve('5+#{1 + 2} * #{3 + 4}')
+    assert_equal '3 * 7 + 5', resolve('#{1 + 2} * #{3 + 4} + 5')
+    assert_equal '3 * 7+ 5', resolve('#{1 + 2} * #{3 + 4}+ 5')
+    assert_equal '3 * 7+5', resolve('#{1 + 2} * #{3 + 4}+5')
+
+    assert_equal '5/3 + 7', resolve('5 / (#{1 + 2} + #{3 + 4})')
+    assert_equal '5/3 + 7', resolve('5 /(#{1 + 2} + #{3 + 4})')
+    assert_equal '5/3 + 7', resolve('5 /( #{1 + 2} + #{3 + 4} )')
+    assert_equal '3 + 7/5', resolve('(#{1 + 2} + #{3 + 4}) / 5')
+    assert_equal '3 + 7/5', resolve('(#{1 + 2} + #{3 + 4})/ 5')
+    assert_equal '3 + 7/5', resolve('( #{1 + 2} + #{3 + 4} )/ 5')
+
+    assert_equal '3 + 5', resolve('#{1 + 2} + 2 + 3')
+    assert_equal '3 +5', resolve('#{1 + 2} +2 + 3')
+  end
+
+  def test_string_interpolation
+    assert_equal "foo bar, baz bang", resolve('"foo #{"bar"}, #{"baz"} bang"')
+    assert_equal "foo bar baz bang", resolve('"foo #{"#{"ba" + "r"} baz"} bang"')
+    assert_equal 'foo #{bar baz} bang', resolve('"foo \#{#{"ba" + "r"} baz} bang"')
+    assert_equal 'foo #{baz bang', resolve('"foo #{"\#{" + "baz"} bang"')
+    assert_equal "foo2bar", resolve('\'foo#{1 + 1}bar\'')
+    assert_equal "foo2bar", resolve('"foo#{1 + 1}bar"')
+    assert_equal "foo1bar5baz4bang", resolve('\'foo#{1 + "bar#{2 + 3}baz" + 4}bang\'')
+  end
+
+  def test_interpolation_with_newline
+    assert_equal "\nbang", resolve('"#{"\a "}bang"')
+    assert_equal "\n\nbang", resolve('"#{"\a "}\a bang"')
+  end
+
+  def test_rule_interpolation
+    assert_equal(<<CSS, render(<<SASS))
+foo bar baz bang {
+  a: b; }
+CSS
+foo \#{"\#{"ba" + "r"} baz"} bang
+  a: b
+SASS
+    assert_equal(<<CSS, render(<<SASS))
+foo [bar="\#{bar baz}"] bang {
+  a: b; }
+CSS
+foo [bar="\\\#{\#{"ba" + "r"} baz}"] bang
+  a: b
+SASS
+    assert_equal(<<CSS, render(<<SASS))
+foo [bar="\#{baz"] bang {
+  a: b; }
+CSS
+foo [bar="\#{"\\\#{" + "baz"}"] bang
+  a: b
+SASS
+  end
+
+  def test_inaccessible_functions
+    assert_equal "send(to_s)", resolve("send(to_s)", :line => 2)
+    assert_equal "public_instance_methods()", resolve("public_instance_methods()")
+  end
+
+  def test_adding_functions_directly_to_functions_module
+    assert !Functions.callable?('nonexistant')
+    Functions.class_eval { def nonexistant; end }
+    assert Functions.callable?('nonexistant')
+    Functions.send :remove_method, :nonexistant
+  end
+
+  def test_default_functions
+    assert_equal "url(12)", resolve("url(12)")
+    assert_equal 'blam("foo")', resolve('blam("foo")')
+  end
+
+  def test_function_results_have_options
+    assert_equal "Options defined!", resolve("assert_options(abs(1))")
+    assert_equal "Options defined!", resolve("assert_options(round(1.2))")
+  end
+
+  def test_funcall_requires_no_whitespace_before_lparen
+    assert_equal "no-repeat 15px", resolve("no-repeat (7px + 8px)")
+    assert_equal "no-repeat(15px)", resolve("no-repeat(7px + 8px)")
+  end
+
+  def test_dynamic_url
+    assert_equal "url(foo-bar)", resolve("url($foo)", {}, env('foo' => 
Sass::Script::Value::String.new("foo-bar")))
+    assert_equal "url(foo-bar baz)", resolve("url($foo $bar)", {}, env('foo' => 
Sass::Script::Value::String.new("foo-bar"), 'bar' => Sass::Script::Value::String.new("baz")))
+    assert_equal "url(foo baz)", resolve("url(foo $bar)", {}, env('bar' => 
Sass::Script::Value::String.new("baz")))
+    assert_equal "url(foo bar)", resolve("url(foo    bar)")
+  end
+
+  def test_url_with_interpolation
+    assert_equal "url(http://sass-lang.com/images/foo-bar)", 
resolve("url(http://sass-lang.com/images/\#{foo-bar})")
+    assert_equal 'url("http://sass-lang.com/images/foo-bar";)', 
resolve("url('http://sass-lang.com/images/\#{foo-bar}')")
+    assert_equal 'url("http://sass-lang.com/images/foo-bar";)', 
resolve('url("http://sass-lang.com/images/#{foo-bar}";)')
+    assert_unquoted "url(http://sass-lang.com/images/\#{foo-bar})"
+  end
+
+  def test_hyphenated_variables
+    assert_equal("a-b", resolve("$a-b", {}, env("a-b" => Sass::Script::Value::String.new("a-b"))))
+  end
+
+  def test_ruby_equality
+    assert_equal eval('"foo"'), eval('"foo"')
+    assert_equal eval('1'), eval('1.0')
+    assert_equal eval('1 2 3.0'), eval('1 2 3')
+    assert_equal eval('1, 2, 3.0'), eval('1, 2, 3')
+    assert_equal eval('(1 2), (3, 4), (5 6)'), eval('(1 2), (3, 4), (5 6)')
+    refute_equal eval('1, 2, 3'), eval('1 2 3')
+    refute_equal eval('1'), eval('"1"')
+  end
+
+  def test_booleans
+    assert_equal "true", resolve("true")
+    assert_equal "false", resolve("false")
+  end
+
+  def test_null
+    assert_equal "", resolve("null")
+  end
+
+  def test_boolean_ops
+    assert_equal "true", resolve("true and true")
+    assert_equal "true", resolve("false or true")
+    assert_equal "true", resolve("true or false")
+    assert_equal "true", resolve("true or true")
+    assert_equal "false", resolve("false or false")
+    assert_equal "false", resolve("false and true")
+    assert_equal "false", resolve("true and false")
+    assert_equal "false", resolve("false and false")
+
+    assert_equal "true", resolve("not false")
+    assert_equal "false", resolve("not true")
+    assert_equal "true", resolve("not not true")
+
+    assert_equal "1", resolve("false or 1")
+    assert_equal "false", resolve("false and 1")
+    assert_equal "2", resolve("2 or 3")
+    assert_equal "3", resolve("2 and 3")
+
+    assert_equal "true", resolve("null or true")
+    assert_equal "true", resolve("true or null")
+    assert_equal "", resolve("null or null")
+    assert_equal "", resolve("null and true")
+    assert_equal "", resolve("true and null")
+    assert_equal "", resolve("null and null")
+
+    assert_equal "true", resolve("not null")
+
+    assert_equal "1", resolve("null or 1")
+    assert_equal "", resolve("null and 1")
+  end
+
+  def test_arithmetic_ops
+    assert_equal "2", resolve("1 + 1")
+    assert_equal "0", resolve("1 - 1")
+    assert_equal "8", resolve("2 * 4")
+    assert_equal "0.5", resolve("(2 / 4)")
+    assert_equal "2", resolve("(4 / 2)")
+
+    assert_equal "-1", resolve("-1")
+  end
+
+  def test_string_ops
+    assert_equal '"foo" "bar"', resolve('"foo" "bar"')
+    assert_equal "true 1", resolve('true 1')
+    assert_equal '"foo", "bar"', resolve("'foo' , 'bar'")
+    assert_equal "true, 1", resolve('true , 1')
+    assert_equal "foobar", resolve('"foo" + "bar"')
+    assert_equal "\nfoo\nxyz", resolve('"\a foo" + "\axyz"')
+    assert_equal "true1", resolve('true + 1')
+    assert_equal '"foo"-"bar"', resolve("'foo' - 'bar'")
+    assert_equal "true-1", resolve('true - 1')
+    assert_equal '"foo"/"bar"', resolve('"foo" / "bar"')
+    assert_equal "true/1", resolve('true / 1')
+
+    assert_equal '-"bar"', resolve("- 'bar'")
+    assert_equal "-true", resolve('- true')
+    assert_equal '/"bar"', resolve('/ "bar"')
+    assert_equal "/true", resolve('/ true')
+  end
+
+  def test_relational_ops
+    assert_equal "false", resolve("1 > 2")
+    assert_equal "false", resolve("2 > 2")
+    assert_equal "true", resolve("3 > 2")
+    assert_equal "false", resolve("1 >= 2")
+    assert_equal "true", resolve("2 >= 2")
+    assert_equal "true", resolve("3 >= 2")
+    assert_equal "true", resolve("1 < 2")
+    assert_equal "false", resolve("2 < 2")
+    assert_equal "false", resolve("3 < 2")
+    assert_equal "true", resolve("1 <= 2")
+    assert_equal "true", resolve("2 <= 2")
+    assert_equal "false", resolve("3 <= 2")
+  end
+
+  def test_null_ops
+    assert_raise_message(Sass::SyntaxError,
+      'Invalid null operation: "null plus 1".') {eval("null + 1")}
+    assert_raise_message(Sass::SyntaxError,
+      'Invalid null operation: "null minus 1".') {eval("null - 1")}
+    assert_raise_message(Sass::SyntaxError,
+      'Invalid null operation: "null times 1".') {eval("null * 1")}
+    assert_raise_message(Sass::SyntaxError,
+      'Invalid null operation: "null div 1".') {eval("null / 1")}
+    assert_raise_message(Sass::SyntaxError,
+      'Invalid null operation: "null mod 1".') {eval("null % 1")}
+    assert_raise_message(Sass::SyntaxError,
+      'Invalid null operation: "1 plus null".') {eval("1 + null")}
+    assert_raise_message(Sass::SyntaxError,
+      'Invalid null operation: "1 minus null".') {eval("1 - null")}
+    assert_raise_message(Sass::SyntaxError,
+      'Invalid null operation: "1 times null".') {eval("1 * null")}
+    assert_raise_message(Sass::SyntaxError,
+      'Invalid null operation: "1 div null".') {eval("1 / null")}
+    assert_raise_message(Sass::SyntaxError,
+      'Invalid null operation: "1 mod null".') {eval("1 % null")}
+    assert_raise_message(Sass::SyntaxError,
+      'Invalid null operation: "1 gt null".') {eval("1 > null")}
+    assert_raise_message(Sass::SyntaxError,
+      'Invalid null operation: "null lt 1".') {eval("null < 1")}
+    assert_raise_message(Sass::SyntaxError,
+      'Invalid null operation: "null plus null".') {eval("null + null")}
+    assert_raise_message(Sass::SyntaxError,
+      'Invalid null operation: ""foo" plus null".') {eval("foo + null")}
+  end
+
+  def test_equals
+    assert_equal("true", resolve('"foo" == $foo', {},
+        env("foo" => Sass::Script::Value::String.new("foo"))))
+    assert_equal "true", resolve("1 == 1.0")
+    assert_equal "true", resolve("false != true")
+    assert_equal "false", resolve("1em == 1px")
+    assert_equal "false", resolve("12 != 12")
+    assert_equal "true", resolve("(foo bar baz) == (foo bar baz)")
+    assert_equal "true", resolve("(foo, bar, baz) == (foo, bar, baz)")
+    assert_equal "true", resolve('((1 2), (3, 4), (5 6)) == ((1 2), (3, 4), (5 6))')
+    assert_equal "true", resolve('((1 2), (3 4)) == (1 2, 3 4)')
+    assert_equal "false", resolve('((1 2) 3) == (1 2 3)')
+    assert_equal "false", resolve('(1 (2 3)) == (1 2 3)')
+    assert_equal "false", resolve('((1, 2) (3, 4)) == (1, 2 3, 4)')
+    assert_equal "false", resolve('(1 2 3) == (1, 2, 3)')
+
+    assert_equal "true", resolve('null == null')
+    assert_equal "false", resolve('"null" == null')
+    assert_equal "false", resolve('0 == null')
+    assert_equal "false", resolve('() == null')
+
+    assert_equal "false", resolve('null != null')
+    assert_equal "true", resolve('"null" != null')
+    assert_equal "true", resolve('0 != null')
+    assert_equal "true", resolve('() != null')
+  end
+
+  def test_mod
+    assert_equal "5", resolve("29 % 12")
+    assert_equal "5px", resolve("29px % 12")
+    assert_equal "5px", resolve("29px % 12px")
+  end
+
+  def test_operation_precedence
+    assert_equal "false true", resolve("true and false false or true")
+    assert_equal "true", resolve("false and true or true and true")
+    assert_equal "true", resolve("1 == 2 or 3 == 3")
+    assert_equal "true", resolve("1 < 2 == 3 >= 3")
+    assert_equal "true", resolve("1 + 3 > 4 - 2")
+    assert_equal "11", resolve("1 + 2 * 3 + 4")
+  end
+
+  def test_functions
+    assert_equal "#80ff80", resolve("hsl(120, 100%, 75%)")
+    assert_equal "#81ff81", resolve("hsl(120, 100%, 75%) + #010001")
+  end
+
+  def test_operator_unit_conversion
+    assert_equal "1.1cm", resolve("1cm + 1mm")
+    assert_equal "2in", resolve("1in + 96px")
+    assert_equal "true", resolve("2mm < 1cm")
+    assert_equal "true", resolve("10mm == 1cm")
+    assert_equal "true", resolve("1.1cm == 11mm")
+
+    assert_warning(<<WARNING) {assert_equal "true", resolve("1 == 1cm")}
+DEPRECATION WARNING on line 1 of test_operator_unit_conversion_inline.sass:
+The result of `1 == 1cm` will be `false` in future releases of Sass.
+Unitless numbers will no longer be equal to the same numbers with units.
+WARNING
+  end
+
+  def test_length_units
+    assert_equal "2.54", resolve("(1in/1cm)")
+    assert_equal "2.3622", resolve("(1cm/1pc)")
+    assert_equal "4.23333", resolve("(1pc/1mm)")
+    assert_equal "2.83465", resolve("(1mm/1pt)")
+    assert_equal "1.33333", resolve("(1pt/1px)")
+    assert_equal "0.01042", resolve("(1px/1in)")
+  end
+
+  def test_angle_units
+    assert_equal "1.11111", resolve("(1deg/1grad)")
+    assert_equal "0.01571", resolve("(1grad/1rad)")
+    assert_equal "0.15915", resolve("(1rad/1turn)")
+    assert_equal "360", resolve("(1turn/1deg)")
+  end
+
+  def test_time_units
+    assert_equal "1000", resolve("(1s/1ms)")
+  end
+
+  def test_frequency_units
+    assert_equal "0.001", resolve("(1Hz/1kHz)")
+  end
+
+  def test_resolution_units
+    assert_equal "2.54", resolve("(1dpi/1dpcm)")
+    assert_equal "37.79528", resolve("(1dpcm/1dppx)")
+    assert_equal "0.01042", resolve("(1dppx/1dpi)")
+  end
+
+  def test_operations_have_options
+    assert_equal "Options defined!", resolve("assert_options(1 + 1)")
+    assert_equal "Options defined!", resolve("assert_options('bar' + 'baz')")
+  end
+
+  def test_slash_compiles_literally_when_left_alone
+    assert_equal "1px/2px", resolve("1px/2px")
+    assert_equal "1px/2px/3px/4px", resolve("1px/2px/3px/4px")
+
+    assert_equal "1px/2px redpx bluepx", resolve("1px/2px redpx bluepx")
+    assert_equal "foo 1px/2px/3px bar", resolve("foo 1px/2px/3px bar")
+  end
+
+  def test_slash_divides_with_parens
+    assert_equal "0.5", resolve("(1px/2px)")
+    assert_equal "0.5", resolve("(1px)/2px")
+    assert_equal "0.5", resolve("1px/(2px)")
+  end
+
+  def test_slash_divides_with_other_arithmetic
+    assert_equal "0.5px", resolve("1px*1px/2px")
+    assert_equal "0.5px", resolve("1px/2px*1px")
+    assert_equal "0.5", resolve("0+1px/2px")
+    assert_equal "0.5", resolve("1px/2px+0")
+  end
+
+  def test_slash_divides_with_variable
+    assert_equal "0.5", resolve("$var/2px", {}, env("var" => eval("1px")))
+    assert_equal "0.5", resolve("1px/$var", {}, env("var" => eval("2px")))
+    assert_equal "0.5", resolve("$var", {}, env("var" => eval("1px/2px")))
+  end
+
+  def test_non_ident_colors_with_wrong_number_of_digits
+    assert_raise_message(Sass::SyntaxError,
+      'Invalid CSS after "": expected expression (e.g. 1px, bold), was "#1"') {eval("#1")}
+    assert_raise_message(Sass::SyntaxError,
+      'Invalid CSS after "": expected expression (e.g. 1px, bold), was "#12"') {eval("#12")}
+    assert_raise_message(Sass::SyntaxError,
+      'Invalid CSS after "": expected expression (e.g. 1px, bold), was "#1234"') {eval("#1234")}
+    assert_raise_message(Sass::SyntaxError,
+      'Invalid CSS after "": expected expression (e.g. 1px, bold), was "#12345"') {eval("#12345")}
+    assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "": expected expression (e.g. ' \
+      '1px, bold), was "#1234567"') {eval("#1234567")}
+  end
+
+  def test_case_insensitive_color_names
+    assert_equal "BLUE", resolve("BLUE")
+    assert_equal "rEd", resolve("rEd")
+    assert_equal "#7f4000", resolve("mix(GrEeN, ReD)")
+  end
+
+  def test_empty_list
+    assert_equal "1 2 3", resolve("1 2 () 3")
+    assert_equal "1 2 3", resolve("1 2 3 ()")
+    assert_equal "1 2 3", resolve("() 1 2 3")
+    assert_raise_message(Sass::SyntaxError, "() isn't a valid CSS value.") {resolve("()")}
+    assert_raise_message(Sass::SyntaxError, "() isn't a valid CSS value.") {resolve("nth(append((), ()), 
1)")}
+  end
+
+  def test_list_with_nulls
+    assert_equal "1, 2, 3", resolve("1, 2, null, 3")
+    assert_equal "1 2 3", resolve("1 2 null 3")
+    assert_equal "1, 2, 3", resolve("1, 2, 3, null")
+    assert_equal "1 2 3", resolve("1 2 3 null")
+    assert_equal "1, 2, 3", resolve("null, 1, 2, 3")
+    assert_equal "1 2 3", resolve("null 1 2 3")
+  end
+
+  def test_map_can_have_trailing_comma
+    assert_equal("(foo: 1, bar: 2)", eval("(foo: 1, bar: 2,)").to_sass)
+  end
+
+  def test_list_can_have_trailing_comma
+    assert_equal("1, 2, 3", resolve("1, 2, 3,"))
+  end
+
+  def test_trailing_comma_defines_singleton_list
+    assert_equal("1 2 3", resolve("nth((1 2 3,), 1)"))
+  end
+
+  def test_map_cannot_have_duplicate_keys
+    assert_raise_message(Sass::SyntaxError, 'Duplicate key "foo" in map (foo: bar, foo: baz).') do
+      eval("(foo: bar, foo: baz)")
+    end
+    assert_raise_message(Sass::SyntaxError, 'Duplicate key "foo" in map (foo: bar, fo + o: baz).') do
+      eval("(foo: bar, fo + o: baz)")
+    end
+    assert_raise_message(Sass::SyntaxError, 'Duplicate key "foo" in map (foo: bar, "foo": baz).') do
+      eval("(foo: bar, 'foo': baz)")
+    end
+    assert_raise_message(Sass::SyntaxError, 'Duplicate key 2px in map (2px: bar, 1px + 1px: baz).') do
+      eval("(2px: bar, 1px + 1px: baz)")
+    end
+    assert_raise_message(Sass::SyntaxError, 'Duplicate key #0000ff in map (blue: bar, #00f: baz).') do
+      eval("(blue: bar, #00f: baz)")
+    end
+  end
+
+  def test_non_duplicate_map_keys
+    # These shouldn't throw errors
+    eval("(foo: foo, bar: bar)")
+    eval("(2px: foo, 2: bar)")
+    eval("(2px: foo, 2em: bar)")
+    eval("('2px': foo, 2px: bar)")
+  end
+
+  def test_map_syntax_errors
+    assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "(foo:": expected expression (e.g. 1px, 
bold), was ")"') do
+      eval("(foo:)")
+    end
+    assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "(": expected ")", was ":bar)"') do
+      eval("(:bar)")
+    end
+    assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "(foo, bar": expected ")", was ": baz)"') do
+      eval("(foo, bar: baz)")
+    end
+    assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "(foo: bar, baz": expected ":", was ")"') do
+      eval("(foo: bar, baz)")
+    end
+  end
+
+  def test_deep_argument_error_not_unwrapped
+    # JRuby (as of 1.6.7.2) offers no way of distinguishing between
+    # argument errors caused by programming errors in a function and
+    # argument errors explicitly thrown within that function.
+    return if RUBY_PLATFORM =~ /java/
+
+    # Don't validate the message; it's different on Rubinius.
+    assert_raises(ArgumentError) {resolve("arg-error()")}
+  end
+
+  def test_shallow_argument_error_unwrapped
+    assert_raise_message(Sass::SyntaxError, "wrong number of arguments (1 for 0) for `arg-error'") 
{resolve("arg-error(1)")}
+  end
+
+  def test_boolean_ops_short_circuit
+    assert_equal "false", resolve("$ie and $ie <= 7", {}, env('ie' => Sass::Script::Value::Bool.new(false)))
+    assert_equal "true", resolve("$ie or $undef", {}, env('ie' => Sass::Script::Value::Bool.new(true)))
+  end
+
+  def test_selector
+    env = Sass::Environment.new
+    assert_equal "true", resolve("& == null", {}, env)
+
+    env.selector = selector('.foo.bar .baz.bang, .bip.bop')
+    assert_equal ".foo.bar .baz.bang, .bip.bop", resolve("&", {}, env)
+    assert_equal ".foo.bar .baz.bang", resolve("nth(&, 1)", {}, env)
+    assert_equal ".bip.bop", resolve("nth(&, 2)", {}, env)
+    assert_equal ".foo.bar", resolve("nth(nth(&, 1), 1)", {}, env)
+    assert_equal ".baz.bang", resolve("nth(nth(&, 1), 2)", {}, env)
+    assert_equal ".bip.bop", resolve("nth(nth(&, 2), 1)", {}, env)
+    assert_equal "string", resolve("type-of(nth(nth(&, 1), 1))", {}, env)
+
+    env.selector = selector('.foo > .bar')
+    assert_equal ".foo > .bar", resolve("&", {}, env)
+    assert_equal ".foo > .bar", resolve("nth(&, 1)", {}, env)
+    assert_equal ".foo", resolve("nth(nth(&, 1), 1)", {}, env)
+    assert_equal ">", resolve("nth(nth(&, 1), 2)", {}, env)
+    assert_equal ".bar", resolve("nth(nth(&, 1), 3)", {}, env)
+  end
+
+  def test_selector_with_newlines
+    env = Sass::Environment.new
+    env.selector = selector(".foo.bar\n.baz.bang,\n\n.bip.bop")
+    assert_equal ".foo.bar .baz.bang, .bip.bop", resolve("&", {}, env)
+    assert_equal ".foo.bar .baz.bang", resolve("nth(&, 1)", {}, env)
+    assert_equal ".bip.bop", resolve("nth(&, 2)", {}, env)
+    assert_equal ".foo.bar", resolve("nth(nth(&, 1), 1)", {}, env)
+    assert_equal ".baz.bang", resolve("nth(nth(&, 1), 2)", {}, env)
+    assert_equal ".bip.bop", resolve("nth(nth(&, 2), 1)", {}, env)
+    assert_equal "string", resolve("type-of(nth(nth(&, 1), 1))", {}, env)
+  end
+
+  def test_setting_global_variable_globally
+    assert_no_warning {assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))}
+.foo {
+  a: 1; }
+
+.bar {
+  b: 2; }
+CSS
+$var: 1;
+
+.foo {
+  a: $var;
+}
+
+$var: 2;
+
+.bar {
+  b: $var;
+}
+SCSS
+  end
+
+  def test_setting_global_variable_locally
+    assert_no_warning {assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))}
+.bar {
+  a: x;
+  b: y;
+  c: z; }
+CSS
+$var1: 1;
+$var3: 3;
+
+.foo {
+  $var1: x !global;
+  $var2: y !global;
+  @each $var3 in _ {
+    $var3: z !global;
+  }
+}
+
+.bar {
+  a: $var1;
+  b: $var2;
+  c: $var3;
+}
+SCSS
+  end
+
+  def test_setting_global_variable_locally_with_default
+    assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))
+.bar {
+  a: 1;
+  b: y;
+  c: z; }
+CSS
+$var1: 1;
+
+.foo {
+  $var1: x !global !default;
+  $var2: y !global !default;
+  @each $var3 in _ {
+    $var3: z !global !default;
+  }
+}
+
+.bar {
+  a: $var1;
+  b: $var2;
+  c: $var3;
+}
+SCSS
+  end
+
+  def test_setting_local_variable
+    assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))
+.a {
+  value: inside; }
+
+.b {
+  value: outside; }
+CSS
+$var: outside;
+
+.a {
+  $var: inside;
+  value: $var;
+}
+
+.b {
+  value: $var;
+}
+SCSS
+  end
+
+  def test_setting_local_variable_from_inner_scope
+    assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))
+.a .b {
+  value: inside; }
+.a .c {
+  value: inside; }
+CSS
+.a {
+  $var: outside;
+
+  .b {
+    $var: inside;
+    value: $var;
+  }
+
+  .c {
+    value: $var;
+  }
+}
+SCSS
+  end
+
+  def test_if_can_assign_to_global_variables
+    assert_equal <<CSS, render(<<SCSS, :syntax => :scss)
+.a {
+  b: 2; }
+CSS
+$var: 1;
+ if true {$var: 2}
+.a {b: $var}
+SCSS
+  end
+
+  def test_else_can_assign_to_global_variables
+    assert_equal <<CSS, render(<<SCSS, :syntax => :scss)
+.a {
+  b: 2; }
+CSS
+$var: 1;
+ if false {}
+ else {$var: 2}
+.a {b: $var}
+SCSS
+  end
+
+  def test_for_can_assign_to_global_variables
+    assert_equal <<CSS, render(<<SCSS, :syntax => :scss)
+.a {
+  b: 2; }
+CSS
+$var: 1;
+ for $i from 1 to 2 {$var: 2}
+.a {b: $var}
+SCSS
+  end
+
+  def test_each_can_assign_to_global_variables
+    assert_equal <<CSS, render(<<SCSS, :syntax => :scss)
+.a {
+  b: 2; }
+CSS
+$var: 1;
+ each $a in 1 {$var: 2}
+.a {b: $var}
+SCSS
+  end
+
+  def test_while_can_assign_to_global_variables
+    assert_equal <<CSS, render(<<SCSS, :syntax => :scss)
+.a {
+  b: 2; }
+CSS
+$var: 1;
+ while $var != 2 {$var: 2}
+.a {b: $var}
+SCSS
+  end
+
+  def test_if_doesnt_leak_local_variables
+    assert_raise_message(Sass::SyntaxError, 'Undefined variable: "$var".') do
+      render(<<SCSS, :syntax => :scss)
+ if true {$var: 1}
+.a {b: $var}
+SCSS
+    end
+  end
+
+  def test_else_doesnt_leak_local_variables
+    assert_raise_message(Sass::SyntaxError, 'Undefined variable: "$var".') do
+      render(<<SCSS, :syntax => :scss)
+ if false {}
+ else {$var: 1}
+.a {b: $var}
+SCSS
+    end
+  end
+
+  def test_for_doesnt_leak_local_variables
+    assert_raise_message(Sass::SyntaxError, 'Undefined variable: "$var".') do
+      render(<<SCSS, :syntax => :scss)
+ for $i from 1 to 2 {$var: 1}
+.a {b: $var}
+SCSS
+    end
+  end
+
+  def test_each_doesnt_leak_local_variables
+    assert_raise_message(Sass::SyntaxError, 'Undefined variable: "$var".') do
+      render(<<SCSS, :syntax => :scss)
+ each $a in 1 {$var: 1}
+.a {b: $var}
+SCSS
+    end
+  end
+
+  def test_while_doesnt_leak_local_variables
+    assert_raise_message(Sass::SyntaxError, 'Undefined variable: "$var".') do
+      render(<<SCSS, :syntax => :scss)
+$iter: true;
+ while $iter {
+  $var: 1;
+  $iter: false;
+}
+.a {b: $var}
+SCSS
+    end
+  end
+
+  def test_color_format_is_preserved_by_default
+    assert_equal "blue", resolve("blue")
+    assert_equal "bLuE", resolve("bLuE")
+    assert_equal "#00f", resolve("#00f")
+    assert_equal "blue #00F", resolve("blue #00F")
+    assert_equal "blue", resolve("nth(blue #00F, 1)")
+    assert_equal "#00F", resolve("nth(blue #00F, 2)")
+  end
+
+  def test_color_format_isnt_always_preserved_in_compressed_style
+    assert_equal "red", resolve("red", :style => :compressed)
+    assert_equal "red", resolve("#f00", :style => :compressed)
+    assert_equal "red red", resolve("red #f00", :style => :compressed)
+    assert_equal "red", resolve("nth(red #f00, 2)", :style => :compressed)
+  end
+
+  def test_color_format_is_sometimes_preserved_in_compressed_style
+    assert_equal "ReD", resolve("ReD", :style => :compressed)
+    assert_equal "blue", resolve("blue", :style => :compressed)
+    assert_equal "#00f", resolve("#00f", :style => :compressed)
+  end
+
+  def test_color_format_isnt_preserved_when_modified
+    assert_equal "magenta", resolve("#f00 + #00f")
+  end
+
+  def test_ids
+    assert_equal "#foo", resolve("#foo")
+    assert_equal "#abcd", resolve("#abcd")
+    assert_equal "#abc-def", resolve("#abc-def")
+    assert_equal "#abc_def", resolve("#abc_def")
+    assert_equal "#uvw-xyz", resolve("#uvw-xyz")
+    assert_equal "#uvw_xyz", resolve("#uvw_xyz")
+    assert_equal "#uvwxyz", resolve("#uvw + xyz")
+  end
+
+  def test_scientific_notation
+    assert_equal "2000", resolve("2e3")
+    assert_equal "2000", resolve("2E3")
+    assert_equal "2000", resolve("2e+3")
+    assert_equal "2000em", resolve("2e3em")
+    assert_equal "25000000000", resolve("2.5e10")
+    assert_equal "0.1234", resolve("1234e-4")
+    assert_equal "12.34", resolve("1.234e1")
+  end
+
+  def test_identifier_units
+    assert_equal "5-foo", resolve("2-foo + 3-foo")
+    assert_equal "5-foo-", resolve("2-foo- + 3-foo-")
+    assert_equal "5-\\u2603", resolve("2-\\u2603 + 3-\\u2603")
+  end
+
+  def test_backslash_newline_in_string
+    assert_equal 'foobar', resolve("\"foo\\\nbar\"")
+    assert_equal 'foobar', resolve("'foo\\\nbar'")
+  end
+
+  def test_unclosed_special_fun
+    assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "calc(foo()": expected ")", was ""') do
+      resolve("calc(foo()")
+    end
+    assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "calc(#{\')\'}": expected ")", was ""') do
+      resolve("calc(\#{')'}")
+    end
+    assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "calc(#{foo": expected "}", was ""') do
+      resolve("calc(\#{foo")
+    end
+  end
+
+  def test_special_fun_with_interpolation
+    assert_equal "calc())", resolve("calc(\#{')'})")
+    assert_equal "calc(# {foo})", resolve("calc(# {foo})")
+  end
+
+  # Regression Tests
+
+  def test_interpolation_after_string
+    assert_equal '"foobar" 2', resolve('"foobar" #{2}')
+    assert_equal "calc(1 + 2) 3", resolve('calc(1 + 2) #{3}')
+  end
+
+  def test_repeatedly_modified_color
+    assert_equal(<<CSS, render(<<SASS))
+a {
+  link-color: #161C14;
+  link-color-hover: black;
+  link-color-tap: rgba(22, 28, 20, 0.3); }
+CSS
+$green: #161C14
+$link-color: $green
+$link-color-hover: darken($link-color, 10%)
+$link-color-tap: rgba($green, 0.3)
+
+a
+  link-color: $link-color
+  link-color-hover: $link-color-hover
+  link-color-tap: $link-color-tap
+SASS
+  end
+
+  def test_inspect_divided_numbers
+    assert_equal "1px/2px", resolve("inspect(1px/2px)")
+    assert_equal "0.5", resolve("inspect((1px/2px))")
+  end
+
+  def test_minus_without_whitespace
+    assert_equal "5px", resolve("15px-10px")
+    assert_equal "5px-", resolve("15px--10px-")
+  end
+
+  def test_minus_preceded_by_comment
+    assert_equal "15px -10px", resolve("15px/**/-10px")
+  end
+
+  def test_user_defined_function_forces_division
+    assert_equal(<<CSS, render(<<SASS))
+a {
+  b: 10px; }
+CSS
+ function foo()
+  @return 20px
+
+a
+  b: (foo() / 2)
+SASS
+
+    assert_equal(<<CSS, render(<<SASS))
+a {
+  b: 10px; }
+CSS
+ function foo()
+  @return 20px
+
+a
+  b: foo() / 2
+SASS
+end
+
+  def test_funcall_has_higher_precedence_than_color_name
+    assert_equal "teal(12)", resolve("teal(12)")
+    assert_equal "tealbang(12)", resolve("tealbang(12)")
+    assert_equal "teal-bang(12)", resolve("teal-bang(12)")
+    assert_equal "teal\\+bang(12)", resolve("teal\\+bang(12)")
+  end
+
+  def test_funcall_has_higher_precedence_than_true_false_null
+    assert_equal "teal(12)", resolve("teal(12)")
+    assert_equal "tealbang(12)", resolve("tealbang(12)")
+    assert_equal "teal-bang(12)", resolve("teal-bang(12)")
+    assert_equal "teal\\+bang(12)", resolve("teal\\+bang(12)")
+  end
+
+  def test_and_or_not_disallowed_as_function_names
+    %w[and or not].each do |name|
+      assert_raise_message(Sass::SyntaxError, "Invalid function name \"#{name}\".") do
+        render(<<SASS)
+ function #{name}()
+  @return null
+SASS
+      end
+    end
+  end
+
+  def test_interpolation_after_hash
+    assert_equal "#2", resolve('"##{1 + 1}"')
+  end
+
+  def test_misplaced_comma_in_funcall
+    assert_raise_message(Sass::SyntaxError,
+      'Invalid CSS after "foo(bar, ": expected function argument, was ")"') {eval('foo(bar, )')}
+  end
+
+  def test_color_prefixed_identifier
+    assert_equal "tealbang", resolve("tealbang")
+    assert_equal "teal-bang", resolve("teal-bang")
+  end
+
+  def test_op_prefixed_identifier
+    assert_equal "notbang", resolve("notbang")
+    assert_equal "not-bang", resolve("not-bang")
+    assert_equal "or-bang", resolve("or-bang")
+    assert_equal "and-bang", resolve("and-bang")
+  end
+
+  def test_number_initialization
+    assert_equal Sass::Script::Value::Number.new(10, ["px"]), Sass::Script::Value::Number.new(10, "px")
+    assert_equal Sass::Script::Value::Number.new(10, ["px"], ["em"]), Sass::Script::Value::Number.new(10, 
"px", "em")
+  end
+
+  def test_is_unit
+    assert Sass::Script::Value::Number.new(10, "px").is_unit?("px")
+    assert Sass::Script::Value::Number.new(10).is_unit?(nil)
+    assert !Sass::Script::Value::Number.new(10, "px", "em").is_unit?("px")
+    assert !Sass::Script::Value::Number.new(10, [], "em").is_unit?("em")
+    assert !Sass::Script::Value::Number.new(10, ["px", "em"]).is_unit?("px")
+  end
+
+  def test_rename_redirect
+    assert_no_warning do
+      assert_equal Sass::Script::Value::Base, Sass::Script::Literal
+      assert_equal Sass::Script::Tree::Node, Sass::Script::Node
+      assert_equal Sass::Script::Tree::Operation, Sass::Script::Operation
+      assert_equal Sass::Script::Value::String, Sass::Script::String
+    end
+  end
+
+  def test_number_printing
+    assert_equal "1", resolve("1")
+    assert_equal "1", resolve("1.0")
+    assert_equal "1000000000", resolve("1000000000")
+    assert_equal "0.00001", resolve("0.00001")
+    assert_equal "1.12121", resolve("1.121214")
+    assert_equal "1.12122", resolve("1.121215")
+    assert_equal "Infinity", resolve("(1.0/0.0)")
+    assert_equal "-Infinity", resolve("(-1.0/0.0)")
+    assert_equal "NaN", resolve("(0.0/0.0)")
+  end
+
+  private
+
+  def resolve(str, opts = {}, environment = env)
+    munge_filename opts
+    val = eval(str, opts, environment)
+    assert_kind_of Sass::Script::Value::Base, val
+    val.is_a?(Sass::Script::Value::String) ? val.value : val.to_s
+  end
+
+  def resolve_quoted(str, opts = {}, environment = env)
+    munge_filename opts
+    val = eval(str, opts, environment)
+    assert_kind_of Sass::Script::Value::Base, val
+    val.to_s
+  end
+
+  def assert_unquoted(str, opts = {}, environment = env)
+    munge_filename opts
+    val = eval(str, opts, environment)
+    assert_kind_of Sass::Script::Value::String, val
+    assert_equal :identifier, val.type
+  end
+
+  def assert_quoted(str, opts = {}, environment = env)
+    munge_filename opts
+    val = eval(str, opts, environment)
+    assert_kind_of Sass::Script::Value::String, val
+    assert_equal :string, val.type
+  end
+
+  def eval(str, opts = {}, environment = env)
+    munge_filename opts
+    Sass::Script.parse(str, opts.delete(:line) || 1,
+      opts.delete(:offset) || 0, opts).
+      perform(Sass::Environment.new(environment, opts))
+  end
+
+  def render(sass, options = {})
+    munge_filename options
+    Sass::Engine.new(sass, options).render
+  end
+
+  def env(hash = {})
+    env = Sass::Environment.new
+    hash.each {|k, v| env.set_var(k, v)}
+    env
+  end
+
+  def selector(str)
+    parser = Sass::SCSS::StaticParser.new(
+      str, filename_for_test, Sass::Importers::Filesystem.new('.'))
+    parser.parse_selector
+  end
+
+  def test_null_is_a_singleton
+    assert_same Sass::Script::Value::Null.new, Sass::Script::Value::Null.new
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/test/sass/scss/css_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/scss/css_test.rb
new file mode 100755
index 0000000..dd47988
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/scss/css_test.rb
@@ -0,0 +1,1256 @@
+#!/usr/bin/env ruby
+# -*- coding: utf-8 -*-
+require File.dirname(__FILE__) + '/test_helper'
+require 'sass/scss/css_parser'
+
+# These tests just test the parsing of CSS
+# (both standard and any hacks we intend to support).
+# Tests of SCSS-specific behavior go in scss_test.rb.
+class ScssCssTest < MiniTest::Test
+  include ScssTestHelper
+
+  def test_basic_scss
+    assert_parses <<SCSS
+selector {
+  property: value;
+  property2: value; }
+SCSS
+
+    assert_equal <<CSS, render('sel{p:v}')
+sel {
+  p: v; }
+CSS
+  end
+
+  def test_empty_rule
+    assert_equal "", render("#foo .bar {}")
+    assert_equal "", render(<<SCSS)
+#foo .bar {
+}
+SCSS
+  end
+
+  def test_cdo_and_cdc_ignored_at_toplevel
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  bar: baz; }
+
+bar {
+  bar: baz; }
+
+baz {
+  bar: baz; }
+CSS
+foo {bar: baz}
+<!--
+bar {bar: baz}
+-->
+baz {bar: baz}
+SCSS
+  end
+
+  if Sass::Util.ruby1_8?
+    def test_unicode
+      assert_parses <<SCSS
+ charset "UTF-8";
+foo {
+  bar: föö bâr; }
+SCSS
+      assert_parses <<SCSS
+foo {
+  bar: föö bâr; }
+SCSS
+    end
+  else
+    def test_unicode
+      assert_parses <<SCSS
+ charset "UTF-8";
+foo {
+  bar: föö bâr; }
+SCSS
+      assert_equal <<CSS, render(<<SCSS)
+ charset "UTF-8";
+foo {
+  bar: föö bâr; }
+CSS
+foo {
+  bar: föö bâr; }
+SCSS
+    end
+  end
+
+  def test_invisible_comments
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  a: d; }
+CSS
+foo {a: /* b; c: */ d}
+SCSS
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  a: d; }
+CSS
+foo {a /*: b; c */: d}
+SCSS
+  end
+
+  def test_crazy_comments
+    # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/t040109-c17-comments-00-b.xht
+    assert_equal <<CSS, render(<<SCSS)
+/* This is a CSS comment. */
+.one {
+  color: green; }
+
+/* Another comment */
+/* The following should not be used:
+.two {color: red;} */
+.three {
+  color: green;
+  /* color: red; */ }
+
+/**
+.four {color: red;} */
+.five {
+  color: green; }
+
+/**/
+.six {
+  color: green; }
+
+/*********/
+.seven {
+  color: green; }
+
+/* a comment **/
+.eight {
+  color: green; }
+CSS
+/* This is a CSS comment. */
+.one {color: green;} /* Another comment */
+/* The following should not be used:
+.two {color: red;} */
+.three {color: green; /* color: red; */}
+/**
+.four {color: red;} */
+.five {color: green;}
+/**/
+.six {color: green;}
+/*********/
+.seven {color: green;}
+/* a comment **/
+.eight {color: green;}
+SCSS
+  end
+
+  def test_rule_comments
+    assert_parses <<SCSS
+/* Foo */
+.foo {
+  a: b; }
+SCSS
+    assert_equal <<CSS, render(<<SCSS)
+/* Foo
+ * Bar */
+.foo {
+  a: b; }
+CSS
+/* Foo
+ * Bar */.foo {
+  a: b; }
+SCSS
+  end
+
+  def test_property_comments
+    assert_parses <<SCSS
+.foo {
+  /* Foo */
+  a: b; }
+SCSS
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  /* Foo
+   * Bar */
+  a: b; }
+CSS
+.foo {
+  /* Foo
+   * Bar */a: b; }
+SCSS
+  end
+
+  def test_selector_comments
+    assert_equal <<CSS, render(<<SCSS)
+.foo #bar:baz(bip) {
+  a: b; }
+CSS
+.foo /* .a #foo */ #bar:baz(/* bang )*/ bip) {
+  a: b; }
+SCSS
+  end
+
+  def test_lonely_comments
+    assert_parses <<SCSS
+/* Foo
+ * Bar */
+SCSS
+    assert_parses <<SCSS
+.foo {
+  /* Foo
+   * Bar */ }
+SCSS
+  end
+
+  def test_multiple_comments
+    assert_parses <<SCSS
+/* Foo
+ * Bar */
+/* Baz
+ * Bang */
+SCSS
+    assert_parses <<SCSS
+.foo {
+  /* Foo
+   * Bar */
+  /* Baz
+   * Bang */ }
+SCSS
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  /* Foo Bar */
+  /* Baz Bang */ }
+CSS
+.foo {
+  /* Foo Bar *//* Baz Bang */ }
+SCSS
+  end
+
+  def test_bizarrely_formatted_comments
+    assert_parses <<SCSS
+.foo {
+  /* Foo
+Bar
+  Baz */
+  a: b; }
+SCSS
+    assert_parses <<SCSS
+.foo {
+    /* Foo
+Bar
+  Baz */
+  a: b; }
+SCSS
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+   /* Foo
+Bar */
+  a: b; }
+CSS
+.foo {/* Foo
+   Bar */
+  a: b; }
+SCSS
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+    /* Foo
+ Bar
+Baz */
+  a: b; }
+CSS
+.foo {/* Foo
+   Bar
+  Baz */
+  a: b; }
+SCSS
+  end
+
+  ## Declarations
+
+  def test_vendor_properties
+    assert_parses <<SCSS
+foo {
+  -moz-foo-bar: blat;
+  -o-flat-blang: wibble; }
+SCSS
+  end
+
+  def test_empty_declarations
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  bar: baz; }
+CSS
+foo {;;;;
+  bar: baz;;;;
+  ;;}
+SCSS
+  end
+
+  def test_basic_property_types
+    assert_parses <<SCSS
+foo {
+  a: 2;
+  b: 2.3em;
+  c: 50%;
+  d: "fraz bran";
+  e: flanny-blanny-blan;
+  f: url(http://sass-lang.com);
+  g: U+ffa?;
+  h: #aabbcc; }
+SCSS
+  end
+
+  def test_functions
+    assert_parses <<SCSS
+foo {
+  a: foo-bar(12);
+  b: -foo-bar-baz(13, 14 15); }
+SCSS
+  end
+
+  def test_unary_minus
+    assert_parses <<SCSS
+foo {
+  a: -2;
+  b: -2.3em;
+  c: -50%;
+  d: -foo(bar baz); }
+SCSS
+  end
+
+  def test_operators
+    assert_parses <<SCSS
+foo {
+  a: foo bar baz;
+  b: foo, #aabbcc, -12;
+  c: 1px/2px/-3px;
+  d: foo bar, baz/bang; }
+SCSS
+  end
+
+  def test_important
+    assert_parses <<SCSS
+foo {
+  a: foo !important;
+  b: foo bar !important;
+  b: foo, bar !important; }
+SCSS
+  end
+
+  def test_initial_hyphen
+    assert_parses <<SCSS
+foo {
+  a: -moz-bar-baz;
+  b: foo -o-bar-baz; }
+SCSS
+  end
+
+  def test_ms_long_filter_syntax
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=1, startColorstr=#c0ff3300, 
endColorstr=#ff000000);
+  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=1, startColorstr=#c0ff3300, 
endColorstr=#ff000000); }
+CSS
+foo {
+  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=1, startColorstr=#c0ff3300, 
endColorstr=#ff000000);
+  filter:progid:DXImageTransform.Microsoft.gradient(GradientType=1, startColorstr=#c0ff3300, 
endColorstr=#ff000000); }
+SCSS
+  end
+
+  def test_ms_short_filter_syntax
+    assert_parses <<SCSS
+foo {
+  filter: alpha(opacity=20);
+  filter: alpha(opacity=20, enabled=true);
+  filter: blaznicate(foo=bar, baz=bang bip, bart=#fa4600); }
+SCSS
+  end
+
+  def test_declaration_hacks
+    assert_parses <<SCSS
+foo {
+  _name: val;
+  *name: val;
+  :name: val;
+  .name: val;
+  #name: val;
+  name/**/: val;
+  name/*\\**/: val;
+  name: val; }
+SCSS
+  end
+
+  def test_trailing_hash_hack
+    assert_parses <<SCSS
+foo {
+  foo: bar;
+  #baz: bang;
+  #bip: bop; }
+SCSS
+  end
+
+  def test_zero_arg_functions
+    assert_parses <<SCSS
+foo {
+  a: foo();
+  b: bar baz-bang() bip; }
+SCSS
+  end
+
+  def test_expression_function
+    assert_parses <<SCSS
+foo {
+  a: 12px expression(1 + (3 / Foo.bar("baz" + "bang") + function() {return 12;}) % 12); }
+SCSS
+  end
+
+  def test_calc_function
+    assert_parses <<SCSS
+foo {
+  a: 12px calc(100%/3 - 2*1em - 2*1px);
+  b: 12px -moz-calc(100%/3 - 2*1em - 2*1px);
+  b: 12px -webkit-calc(100%/3 - 2*1em - 2*1px);
+  b: 12px -foobar-calc(100%/3 - 2*1em - 2*1px); }
+SCSS
+  end
+
+  def test_element_function
+    assert_parses <<SCSS
+foo {
+  a: -moz-element(#foo);
+  b: -webkit-element(#foo);
+  b: -foobar-element(#foo); }
+SCSS
+  end
+
+  def test_unary_ops
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  a: -0.5em;
+  b: +0.5em;
+  c: -foo(12px);
+  d: +foo(12px); }
+CSS
+foo {
+  a: -0.5em;
+  b: +0.5em;
+  c: -foo(12px);
+  d: +foo(12px); }
+SCSS
+  end
+
+  def test_css_string_escapes
+    assert_parses <<SCSS
+foo {
+  a: "\\foo bar";
+  b: "foo\\ bar";
+  c: "\\2022 \\0020";
+  d: "foo\\\\bar";
+  e: "foo\\"'bar"; }
+SCSS
+  end
+
+  def test_css_ident_escapes
+    assert_parses <<SCSS
+foo {
+  a: \\foo bar;
+  b: foo\\ bar;
+  c: \\2022 \\0020;
+  d: foo\\\\bar;
+  e: foo\\"\\'bar; }
+SCSS
+  end
+
+  ## Directives
+
+  def test_namespace_directive
+    assert_parses '@namespace "http://www.w3.org/Profiles/xhtml1-strict";;'
+    assert_parses '@namespace url(http://www.w3.org/Profiles/xhtml1-strict);'
+    assert_parses '@namespace html url("http://www.w3.org/Profiles/xhtml1-strict";);'
+  end
+
+  def test_media_directive
+    assert_parses <<SCSS
+ media all {
+  rule1 {
+    prop: val; }
+
+  rule2 {
+    prop: val; } }
+SCSS
+    assert_parses <<SCSS
+ media screen, print {
+  rule1 {
+    prop: val; }
+
+  rule2 {
+    prop: val; } }
+SCSS
+  end
+
+  def test_media_directive_with_keywords
+    assert_parses <<SCSS
+ media screen and (-webkit-min-device-pixel-ratio: 0) {
+  a: b; }
+SCSS
+    assert_parses <<SCSS
+ media only screen, print and (foo: 0px) and (bar: flam(12px solid)) {
+  a: b; }
+SCSS
+  end
+
+  def test_import_directive
+    assert_parses '@import "foo.css";'
+    assert_parses '@import url("foo.css");'
+    assert_parses "@import url('foo.css');"
+    assert_parses '@import url(foo.css);'
+
+    assert_equal <<CSS, render(<<SCSS)
+ import "foo.css";
+CSS
+ import 'foo.css';
+SCSS
+  end
+
+  def test_import_directive_with_backslash_newline
+    assert_equal <<CSS, render(<<SCSS)
+ import "foobar.css";
+CSS
+ import "foo\\
+bar.css";
+SCSS
+  end
+
+  def test_string_import_directive_with_media
+    assert_parses '@import "foo.css" screen;'
+    assert_parses '@import "foo.css" screen, print;'
+    assert_parses '@import "foo.css" screen, print and (foo: 0);'
+    assert_parses '@import "foo.css" screen, only print, screen and (foo: 0);'
+  end
+
+  def test_url_import_directive_with_media
+    assert_parses '@import url("foo.css") screen;'
+    assert_parses '@import url("foo.css") screen, print;'
+    assert_parses '@import url("foo.css") screen, print and (foo: 0);'
+    assert_parses '@import url("foo.css") screen, only print, screen and (foo: 0);'
+  end
+
+  def test_page_directive
+    assert_parses <<SCSS
+ page {
+  prop1: val;
+  prop2: val; }
+SCSS
+    assert_parses <<SCSS
+ page flap {
+  prop1: val;
+  prop2: val; }
+SCSS
+    assert_parses <<SCSS
+ page :first {
+  prop1: val;
+  prop2: val; }
+SCSS
+    assert_parses <<SCSS
+ page flap:first {
+  prop1: val;
+  prop2: val; }
+SCSS
+  end
+
+  def test_blockless_directive_without_semicolon
+    assert_equal "@foo \"bar\";\n", render('@foo "bar"')
+  end
+
+  def test_directive_with_lots_of_whitespace
+    assert_equal "@foo \"bar\";\n", render('@foo    "bar"  ;')
+  end
+
+  def test_empty_blockless_directive
+    assert_parses "@foo;"
+  end
+
+  def test_multiple_blockless_directives
+    assert_parses <<SCSS
+ foo bar;
+ bar baz;
+SCSS
+  end
+
+  def test_empty_block_directive
+    assert_parses "@foo {}"
+    assert_equal "@foo {}\n", render(<<SCSS)
+ foo {
+}
+SCSS
+  end
+
+  def test_multiple_block_directives
+    assert_parses <<SCSS
+ foo bar {
+  a: b; }
+ bar baz {
+  c: d; }
+SCSS
+  end
+
+  def test_block_directive_with_rule_and_property
+    assert_parses <<SCSS
+ foo {
+  rule {
+    a: b; }
+
+  a: b; }
+SCSS
+  end
+
+  def test_block_directive_with_semicolon
+    assert_equal <<CSS, render(<<SCSS)
+ foo {
+  a: b; }
+ bar {
+  a: b; }
+CSS
+ foo {a:b};
+ bar {a:b};
+SCSS
+  end
+
+  def test_moz_document_directive
+    assert_equal <<CSS, render(<<SCSS)
+ -moz-document url(http://www.w3.org/),
+               url-prefix(http://www.w3.org/Style/),
+               domain(mozilla.org),
+               regexp("^https:.*") {
+  .foo {
+    a: b; } }
+CSS
+ -moz-document url(http://www.w3.org/),
+               url-prefix(http://www.w3.org/Style/),
+               domain(mozilla.org),
+               regexp("^https:.*") {
+  .foo {a: b}
+}
+SCSS
+  end
+
+  def test_supports
+    assert_equal <<CSS, render(<<SCSS)
+ supports (a: b) and (c: d) or (not (d: e)) and ((not (f: g)) or (not ((h: i) and (j: k)))) {
+  .foo {
+    a: b; } }
+ supports (a: b) {
+  .foo {
+    a: b; } }
+CSS
+ supports (a: b) and (c: d) or (not (d: e)) and ((not (f: g)) or (not ((h: i) and (j: k)))) {
+  .foo {
+    a: b;
+  }
+}
+
+ supports (a: b) {
+  .foo {
+    a: b;
+  }
+}
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+ -prefix-supports (a: b) and (c: d) or (not (d: e)) and ((not (f: g)) or (not ((h: i) and (j: k)))) {
+  .foo {
+    a: b; } }
+CSS
+ -prefix-supports (a: b) and (c: d) or (not (d: e)) and ((not (f: g)) or (not ((h: i) and (j: k)))) {
+  .foo {
+    a: b;
+  }
+}
+SCSS
+  end
+
+  def test_keyframes
+    assert_equal <<CSS, render(<<SCSS)
+ keyframes identifier {
+  0% {
+    top: 0;
+    left: 0; }
+  30% {
+    top: 50px; }
+  68%, 72% {
+    left: 50px; }
+  100% {
+    top: 100px;
+    left: 100%; } }
+CSS
+ keyframes identifier {
+  0% {top: 0; left: 0}
+  30% {top: 50px}
+  68%, 72% {left: 50px}
+  100% {top: 100px; left: 100%}
+}
+SCSS
+  end
+
+  def test_keyframes_with_empty_rules
+    assert_equal <<CSS, render(<<SCSS)
+ keyframes identifier {
+  50% {
+    background-color: black; } }
+CSS
+ keyframes identifier {
+  0% {}
+  50% {background-color: black}
+  100% {}
+}
+SCSS
+  end
+
+  def test_keyframes_with_custom_identifiers
+    assert_equal <<CSS, render(<<SCSS)
+ -skrollr-keyframes identifier {
+  center-top {
+    left: 100%; }
+  top-bottom {
+    left: 0%; } }
+CSS
+ -skrollr-keyframes identifier {
+  center-top {
+    left: 100%;
+  }
+
+  top-bottom {
+    left: 0%;
+  }
+}
+
+SCSS
+  end
+
+  ## Selectors
+
+  # Taken from http://dev.w3.org/csswg/selectors4/#overview
+  def test_summarized_selectors_with_element
+    assert_selector_parses('*')
+    assert_selector_parses('E')
+    assert_selector_parses('E:not(s)')
+    assert_selector_parses('E:not(s1, s2)')
+    assert_selector_parses('E:matches(s1, s2)')
+    assert_selector_parses('E:has(s1, s2)')
+    assert_selector_parses('E:has(> s1, > s2)')
+    assert_selector_parses('E.warning')
+    assert_selector_parses('E#myid')
+    assert_selector_parses('E[foo]')
+    assert_selector_parses('E[foo="bar"]')
+    assert_selector_parses('E[foo="bar" i]')
+    assert_selector_parses('E[foo~="bar"]')
+    assert_selector_parses('E[foo^="bar"]')
+    assert_selector_parses('E[foo$="bar"]')
+    assert_selector_parses('E[foo*="bar"]')
+    assert_selector_parses('E[foo|="en"]')
+    assert_selector_parses('E:dir(ltr)')
+    assert_selector_parses('E:lang(fr)')
+    assert_selector_parses('E:lang(zh, *-hant)')
+    assert_selector_parses('E:any-link')
+    assert_selector_parses('E:link')
+    assert_selector_parses('E:visited')
+    assert_selector_parses('E:local-link')
+    assert_selector_parses('E:local-link(0)')
+    assert_selector_parses('E:target')
+    assert_selector_parses('E:scope')
+    assert_selector_parses('E:current')
+    assert_selector_parses('E:current(s)')
+    assert_selector_parses('E:past')
+    assert_selector_parses('E:future')
+    assert_selector_parses('E:active')
+    assert_selector_parses('E:hover')
+    assert_selector_parses('E:focus')
+    assert_selector_parses('E:enabled')
+    assert_selector_parses('E:disabled')
+    assert_selector_parses('E:checked')
+    assert_selector_parses('E:indeterminate')
+    assert_selector_parses('E:default')
+    assert_selector_parses('E:in-range')
+    assert_selector_parses('E:out-of-range')
+    assert_selector_parses('E:required')
+    assert_selector_parses('E:optional')
+    assert_selector_parses('E:read-only')
+    assert_selector_parses('E:read-write')
+    assert_selector_parses('E:root')
+    assert_selector_parses('E:empty')
+    assert_selector_parses('E:first-child')
+    assert_selector_parses('E:nth-child(n)')
+    assert_selector_parses('E:last-child')
+    assert_selector_parses('E:nth-last-child(n)')
+    assert_selector_parses('E:only-child')
+    assert_selector_parses('E:first-of-type')
+    assert_selector_parses('E:nth-of-type(n)')
+    assert_selector_parses('E:last-of-type')
+    assert_selector_parses('E:nth-last-of-type(n)')
+    assert_selector_parses('E:only-of-type')
+    assert_selector_parses('E:nth-child(n of selector)')
+    assert_selector_parses('E:nth-last-child(n of selector)')
+    assert_selector_parses('E:nth-child(n)')
+    assert_selector_parses('E:nth-last-child(n)')
+    assert_selector_parses('E F')
+    assert_selector_parses('E > F')
+    assert_selector_parses('E + F')
+    assert_selector_parses('E ~ F')
+    assert_selector_parses('E /foo/ F')
+    silence_warnings {assert_selector_parses('E! > F')}
+
+    assert_selector_parses('E /ns|foo/ F')
+
+    # From http://dev.w3.org/csswg/css-scoping-1/
+    assert_selector_parses('E:host(s)')
+    assert_selector_parses('E:host-context(s)')
+  end
+
+  # Taken from http://dev.w3.org/csswg/selectors4/#overview, but without element
+  # names.
+  def test_more_summarized_selectors
+    assert_selector_parses(':not(s)')
+    assert_selector_parses(':not(s1, s2)')
+    assert_selector_parses(':matches(s1, s2)')
+    assert_selector_parses(':has(s1, s2)')
+    assert_selector_parses(':has(> s1, > s2)')
+    assert_selector_parses('.warning')
+    assert_selector_parses('#myid')
+    assert_selector_parses('[foo]')
+    assert_selector_parses('[foo="bar"]')
+    assert_selector_parses('[foo="bar" i]')
+    assert_selector_parses('[foo~="bar"]')
+    assert_selector_parses('[foo^="bar"]')
+    assert_selector_parses('[foo$="bar"]')
+    assert_selector_parses('[foo*="bar"]')
+    assert_selector_parses('[foo|="en"]')
+    assert_selector_parses(':dir(ltr)')
+    assert_selector_parses(':lang(fr)')
+    assert_selector_parses(':lang(zh, *-hant)')
+    assert_selector_parses(':any-link')
+    assert_selector_parses(':link')
+    assert_selector_parses(':visited')
+    assert_selector_parses(':local-link')
+    assert_selector_parses(':local-link(0)')
+    assert_selector_parses(':target')
+    assert_selector_parses(':scope')
+    assert_selector_parses(':current')
+    assert_selector_parses(':current(s)')
+    assert_selector_parses(':past')
+    assert_selector_parses(':future')
+    assert_selector_parses(':active')
+    assert_selector_parses(':hover')
+    assert_selector_parses(':focus')
+    assert_selector_parses(':enabled')
+    assert_selector_parses(':disabled')
+    assert_selector_parses(':checked')
+    assert_selector_parses(':indeterminate')
+    assert_selector_parses(':default')
+    assert_selector_parses(':in-range')
+    assert_selector_parses(':out-of-range')
+    assert_selector_parses(':required')
+    assert_selector_parses(':optional')
+    assert_selector_parses(':read-only')
+    assert_selector_parses(':read-write')
+    assert_selector_parses(':root')
+    assert_selector_parses(':empty')
+    assert_selector_parses(':first-child')
+    assert_selector_parses(':nth-child(n)')
+    assert_selector_parses(':last-child')
+    assert_selector_parses(':nth-last-child(n)')
+    assert_selector_parses(':only-child')
+    assert_selector_parses(':first-of-type')
+    assert_selector_parses(':nth-of-type(n)')
+    assert_selector_parses(':last-of-type')
+    assert_selector_parses(':nth-last-of-type(n)')
+    assert_selector_parses(':only-of-type')
+    assert_selector_parses(':nth-child(n of selector)')
+    assert_selector_parses(':nth-last-child(n of selector)')
+    assert_selector_parses(':nth-child(n)')
+    assert_selector_parses(':nth-last-child(n)')
+
+    # From http://dev.w3.org/csswg/css-scoping-1/
+    assert_selector_parses(':host(s)')
+    assert_selector_parses(':host-context(s)')
+  end
+
+  def test_attribute_selectors_with_identifiers
+    assert_selector_parses('[foo~=bar]')
+    assert_selector_parses('[foo^=bar]')
+    assert_selector_parses('[foo$=bar]')
+    assert_selector_parses('[foo*=bar]')
+    assert_selector_parses('[foo|=en]')
+  end
+
+  def test_nth_selectors
+    assert_selector_parses(':nth-child(-n)')
+    assert_selector_parses(':nth-child(+n)')
+
+    assert_selector_parses(':nth-child(even)')
+    assert_selector_parses(':nth-child(odd)')
+
+    assert_selector_parses(':nth-child(50)')
+    assert_selector_parses(':nth-child(-50)')
+    assert_selector_parses(':nth-child(+50)')
+
+    assert_selector_parses(':nth-child(2n+3)')
+    assert_selector_parses(':nth-child(2n-3)')
+    assert_selector_parses(':nth-child(+2n-3)')
+    assert_selector_parses(':nth-child(-2n+3)')
+    assert_selector_parses(':nth-child(-2n+ 3)')
+
+    assert_equal(<<CSS, render(<<SCSS))
+:nth-child(2n + 3) {
+  a: b; }
+CSS
+:nth-child( 2n + 3 ) {
+  a: b; }
+SCSS
+  end
+
+  def test_selectors_containing_selectors
+    assert_selector_can_contain_selectors(':not(<sel>)')
+    assert_selector_can_contain_selectors(':current(<sel>)')
+    assert_selector_can_contain_selectors(':nth-child(n of <sel>)')
+    assert_selector_can_contain_selectors(':nth-last-child(n of <sel>)')
+    assert_selector_can_contain_selectors(':-moz-any(<sel>)')
+    assert_selector_can_contain_selectors(':has(<sel>)')
+    assert_selector_can_contain_selectors(':has(+ <sel>)')
+    assert_selector_can_contain_selectors(':host(<sel>)')
+    assert_selector_can_contain_selectors(':host-context(<sel>)')
+  end
+
+  def assert_selector_can_contain_selectors(sel)
+    try = lambda {|subsel| assert_selector_parses(sel.gsub('<sel>', subsel))}
+
+    try['foo|bar']
+    try['*|bar']
+
+    try['foo|*']
+    try['*|*']
+
+    try['#blah']
+    try['.blah']
+
+    try['[foo]']
+    try['[foo^="bar"]']
+    try['[baz|foo~="bar"]']
+
+    try[':hover']
+    try[':nth-child(2n + 3)']
+
+    try['h1, h2, h3']
+    try['#foo, bar, [baz]']
+
+    # Not technically allowed for most selectors, but what the heck
+    try[':not(#foo)']
+    try['a#foo.bar']
+    try['#foo .bar > baz']
+  end
+
+  def test_namespaced_selectors
+    assert_selector_parses('foo|E')
+    assert_selector_parses('*|E')
+    assert_selector_parses('foo|*')
+    assert_selector_parses('*|*')
+  end
+
+  def test_namespaced_attribute_selectors
+    assert_selector_parses('[foo|bar=baz]')
+    assert_selector_parses('[*|bar=baz]')
+    assert_selector_parses('[foo|bar|=baz]')
+  end
+
+  def test_comma_selectors
+    assert_selector_parses('E, F')
+    assert_selector_parses('E F, G H')
+    assert_selector_parses('E > F, G > H')
+  end
+
+  def test_selectors_with_newlines
+    assert_selector_parses("E,\nF")
+    assert_selector_parses("E\nF")
+    assert_selector_parses("E, F\nG, H")
+  end
+
+  def test_expression_fallback_selectors
+    assert_directive_parses('0%')
+    assert_directive_parses('60%')
+    assert_directive_parses('100%')
+    assert_directive_parses('12px')
+    assert_directive_parses('"foo"')
+  end
+
+  def test_functional_pseudo_selectors
+    assert_selector_parses(':foo("bar")')
+    assert_selector_parses(':foo(bar)')
+    assert_selector_parses(':foo(12px)')
+    assert_selector_parses(':foo(+)')
+    assert_selector_parses(':foo(-)')
+    assert_selector_parses(':foo(+"bar")')
+    assert_selector_parses(':foo(-++--baz-"bar"12px)')
+  end
+
+  def test_selector_hacks
+    assert_selector_parses('> E')
+    assert_selector_parses('+ E')
+    assert_selector_parses('~ E')
+    assert_selector_parses('> > E')
+    assert_equal <<CSS, render(<<SCSS)
+> > E {
+  a: b; }
+CSS
+>> E {
+  a: b; }
+SCSS
+
+    assert_selector_parses('E*')
+    assert_selector_parses('E*.foo')
+    assert_selector_parses('E*:hover')
+  end
+
+  def test_spaceless_combo_selectors
+    assert_equal "E > F {\n  a: b; }\n", render("E>F { a: b;} ")
+    assert_equal "E ~ F {\n  a: b; }\n", render("E~F { a: b;} ")
+    assert_equal "E + F {\n  a: b; }\n", render("E+F { a: b;} ")
+  end
+
+  def test_escapes_in_selectors
+    assert_selector_parses('.\!foo')
+    assert_selector_parses('.\66 foo')
+    assert_selector_parses('.\21 foo')
+  end
+
+  def test_subject_selector_deprecation
+    assert_warning(<<WARNING) {render(".foo .bar! .baz {a: b}")}
+DEPRECATION WARNING on line 1, column 1:
+The subject selector operator "!" is deprecated and will be removed in a future release.
+This operator has been replaced by ":has()" in the CSS spec.
+For example: .foo .bar:has(.baz)
+WARNING
+
+    assert_warning(<<WARNING) {render(".foo .bar! > .baz {a: b}")}
+DEPRECATION WARNING on line 1, column 1:
+The subject selector operator "!" is deprecated and will be removed in a future release.
+This operator has been replaced by ":has()" in the CSS spec.
+For example: .foo .bar:has(> .baz)
+WARNING
+
+    assert_warning(<<WARNING) {render(".foo .bar! {a: b}")}
+DEPRECATION WARNING on line 1, column 1:
+The subject selector operator "!" is deprecated and will be removed in a future release.
+This operator has been replaced by ":has()" in the CSS spec.
+For example: .foo .bar
+WARNING
+  end
+
+  ## Errors
+
+  def test_invalid_directives
+    assert_not_parses("identifier", '@<err> import "foo";')
+    assert_not_parses("identifier", '@<err>12 "foo";')
+  end
+
+  def test_invalid_classes
+    assert_not_parses("class name", 'p.<err> foo {a: b}')
+    assert_not_parses("class name", 'p.<err>1foo {a: b}')
+  end
+
+  def test_invalid_ids
+    assert_not_parses("id name", 'p#<err> foo {a: b}')
+  end
+
+  def test_no_properties_at_toplevel
+    assert_not_parses('pseudoclass or pseudoelement', 'a:<err> b;')
+  end
+
+  def test_no_scss_directives
+    assert_parses('@import "foo.sass";')
+    assert_parses <<SCSS
+ mixin foo {
+  a: b; }
+SCSS
+  end
+
+  def test_no_variables
+    assert_not_parses("selector or at-rule", "<err>$var = 12;")
+    assert_not_parses('"}"', "foo { <err>!var = 12; }")
+  end
+
+  def test_no_parent_selectors
+    assert_not_parses('"{"', "foo <err>&.bar {a: b}")
+  end
+
+  def test_no_selector_interpolation
+    assert_not_parses('"{"', 'foo <err>#{"bar"}.baz {a: b}')
+  end
+
+  def test_no_prop_name_interpolation
+    assert_not_parses('":"', 'foo {a<err>#{"bar"}baz: b}')
+  end
+
+  def test_no_prop_val_interpolation
+    assert_not_parses('"}"', 'foo {a: b <err>#{"bar"} c}')
+  end
+
+  def test_no_string_interpolation
+    assert_parses <<SCSS
+foo {
+  a: "bang \#{1 +    " bar "} bip"; }
+SCSS
+  end
+
+  def test_no_sass_script_values
+    assert_not_parses('"}"', 'foo {a: b <err>* c}')
+  end
+
+  def test_no_nested_rules
+    assert_not_parses('":"', 'foo {bar <err>{a: b}}')
+    assert_not_parses('"}"', 'foo {<err>[bar=baz] {a: b}}')
+  end
+
+  def test_no_nested_properties
+    assert_not_parses('expression (e.g. 1px, bold)', 'foo {bar: <err>{a: b}}')
+    assert_not_parses('expression (e.g. 1px, bold)', 'foo {bar: bang <err>{a: b}}')
+  end
+
+  def test_no_nested_directives
+    assert_not_parses('"}"', 'foo {<err>@bar {a: b}}')
+  end
+
+  def test_error_with_windows_newlines
+    render <<SCSS
+foo {bar}\r
+baz {a: b}
+SCSS
+    assert(false, "Expected syntax error")
+  rescue Sass::SyntaxError => e
+    assert_equal 'Invalid CSS after "foo {bar": expected ":", was "}"', e.message
+    assert_equal 1, e.sass_line
+  end
+
+  def test_newline_in_property_value
+    assert_equal(<<CSS, render(<<SCSS))
+.foo {
+  bar: "bazbang"; }
+CSS
+.foo {
+  bar: "baz\\
+bang";
+}
+SCSS
+  end
+
+  ## Regressions
+
+  def test_very_long_comment_doesnt_take_forever
+    string = 'asdf' * (100000)
+    assert_equal(<<CSS, render(<<SCSS))
+/*
+  #{string}
+*/
+CSS
+/*
+  #{string}
+*/
+SCSS
+  end
+
+  def test_long_unclosed_comment_doesnt_take_forever
+    assert_raise_message(Sass::SyntaxError,
+      'Invalid CSS after "/*": expected "/", was "//*************..."') {render(<<SCSS)}
+/*
+//**************************************************************************
+SCSS
+  end
+
+  def test_double_space_string
+    assert_equal(<<CSS, render(<<SCSS))
+.a {
+  content: "  a"; }
+CSS
+.a {
+  content: "  a";
+}
+SCSS
+  end
+
+  def test_very_long_number_with_important_doesnt_take_forever
+    assert_equal(<<CSS, render(<<SCSS))
+.foo {
+  width: 97.916666666666666666666666666667% !important; }
+CSS
+.foo {
+  width: 97.916666666666666666666666666667% !important;
+}
+SCSS
+  end
+
+  def test_selector_without_closing_bracket
+    assert_not_parses('"]"', "foo[bar <err>{a: b}")
+  end
+
+  def test_closing_line_comment_end_with_compact_output
+    assert_equal(<<CSS, render(<<SCSS, :style => :compact))
+/* foo */
+bar { baz: bang; }
+CSS
+/*
+ * foo
+ */
+bar {baz: bang}
+SCSS
+  end
+
+  def test_single_line_comment_within_multiline_comment
+    assert_equal(<<CSS, render(<<SCSS))
+body {
+  /*
+  //comment here
+  */ }
+CSS
+body {
+  /*
+  //comment here
+  */
+}
+SCSS
+  end
+
+  def test_malformed_media
+    render <<SCSS
+ media {
+  margin: 0;
+}
+SCSS
+    assert(false, "Expected syntax error")
+  rescue Sass::SyntaxError => e
+    assert_equal 'Invalid CSS after "@media ": expected media query (e.g. print, screen, print and screen), 
was "{"', e.message
+    assert_equal 1, e.sass_line
+  end
+
+  private
+
+  def assert_selector_parses(selector)
+    assert_parses <<SCSS
+#{selector} {
+  a: b; }
+SCSS
+
+    assert_parses <<SCSS
+:not(#{selector}) {
+  a: b; }
+SCSS
+  end
+
+  def assert_directive_parses(param)
+    assert_parses <<SCSS
+ keyframes #{param} {
+  a: b; }
+SCSS
+  end
+
+  def render(scss, options = {})
+    tree = Sass::SCSS::CssParser.new(scss, options[:filename], nil).parse
+    tree.options = Sass::Engine::DEFAULT_OPTIONS.merge(options)
+    tree.render
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/test/sass/scss/rx_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/scss/rx_test.rb
new file mode 100755
index 0000000..f45e61b
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/scss/rx_test.rb
@@ -0,0 +1,156 @@
+#!/usr/bin/env ruby
+# -*- coding: utf-8 -*-
+require File.dirname(__FILE__) + '/../../test_helper'
+require 'sass/engine'
+
+class ScssRxTest < MiniTest::Test
+  include Sass::SCSS::RX
+
+  def test_identifiers
+    assert_match IDENT, "foo"
+    assert_match IDENT, "\xC3\xBFoo" # Initial char can be nonascii
+    assert_match IDENT, "\\123abcoo" # Initial char can be unicode escape
+    assert_match IDENT, "\\f oo" # Unicode escapes can be followed by whitespace
+    assert_match IDENT, "\\fa\too"
+    assert_match IDENT, "\\ff2\roo"
+    assert_match IDENT, "\\f13a\foo"
+    assert_match IDENT, "\\f13abcoo"
+    assert_match IDENT, "\\ oo" # Initial char can be a plain escape as well
+    assert_match IDENT, "\\~oo"
+    assert_match IDENT, "\\\\oo"
+    assert_match IDENT, "\\{oo"
+    assert_match IDENT, "\\\xC3\xBFoo"
+    assert_match IDENT, "-foo" # Can put a - before anything
+    assert_match IDENT, "-\xC3\xBFoo"
+    assert_match IDENT, "-\\f oo"
+    assert_match IDENT, "_foo" # Can put a _ before anything
+    assert_match IDENT, "_\xC3\xBFoo"
+    assert_match IDENT, "_\\f oo"
+    assert_match IDENT, "--foo" # "Custom" identifier
+
+    assert_match IDENT, "foo-bar"
+    assert_match IDENT, "f012-23"
+    assert_match IDENT, "foo_-_bar"
+    assert_match IDENT, "f012_23"
+
+    # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/escapes-003.xht
+    assert_match IDENT, "c\\lass"
+    # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/escapes-004.xht
+    assert_match IDENT, "c\\00006Cas\\000073"
+    # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/ident-001.xht
+    assert_match IDENT, "IdE6n-3t0_6"
+    # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/ident-006.xht
+    assert_match IDENT, "\\6000ident"
+    # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/ident-007.xht
+    assert_match IDENT, "iden\\6000t\\6000"
+    # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/ident-013.xht
+    assert_match IDENT, "\\-ident"
+  end
+
+  def test_underscores_in_identifiers
+    assert_match IDENT, "foo_bar"
+    assert_match IDENT, "_\xC3\xBFfoo"
+    assert_match IDENT, "__foo"
+    assert_match IDENT, "_1foo"
+    assert_match IDENT, "-_foo"
+    assert_match IDENT, "_-foo"
+  end
+
+  def test_invalid_identifiers
+    assert_no_match IDENT, ""
+    assert_no_match IDENT, "1foo"
+    assert_no_match IDENT, "-1foo"
+    assert_no_match IDENT, "foo bar"
+    assert_no_match IDENT, "foo~bar"
+
+    # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/escapes-008.xht
+    assert_no_match IDENT, "c\\06C  ass"
+    assert_no_match IDENT, "back\\67\n round"
+  end
+
+  def test_double_quote_strings
+    assert_match STRING, '"foo bar"'
+    assert_match STRING, '"foo\\\nbar"'
+    assert_match STRING, "\"\\\"\""
+    assert_match STRING, '"\t !#$%&(-~()*+,-./0123456789~"'
+  end
+
+  def test_single_quote_strings
+    assert_match STRING, "'foo bar'"
+    assert_match STRING, "'foo\\\nbar'"
+    assert_match STRING, "'\\''"
+    assert_match STRING, "'\t !#\$%&(-~()*+,-./0123456789~'"
+  end
+
+  def test_invalid_strings
+    assert_no_match STRING, "\"foo\nbar\""
+    assert_no_match STRING, "\"foo\"bar\""
+    assert_no_match STRING, "'foo\nbar'"
+    assert_no_match STRING, "'foo'bar'"
+  end
+
+  def test_uri
+    assert_match URI, 'url("foo bar)")'
+    assert_match URI, "url('foo bar)')"
+    assert_match URI, 'url( "foo bar)" )'
+    assert_match URI, "url(#\\%&**+,-./0123456789~)"
+  end
+
+  def test_invalid_uri
+    assert_no_match URI, 'url(foo)bar)'
+  end
+
+  def test_unicode_range
+    assert_match UNICODERANGE, 'U+00-Ff'
+    assert_match UNICODERANGE, 'u+980-9FF'
+    assert_match UNICODERANGE, 'U+9aF??'
+    assert_match UNICODERANGE, 'U+??'
+  end
+
+  def test_escape_empty_ident
+    assert_equal "", Sass::SCSS::RX.escape_ident("")
+  end
+
+  def test_escape_just_prefix_ident
+    assert_equal "\\-", Sass::SCSS::RX.escape_ident("-")
+    assert_equal "\\_", Sass::SCSS::RX.escape_ident("_")
+  end
+
+  def test_escape_plain_ident
+    assert_equal "foo", Sass::SCSS::RX.escape_ident("foo")
+    assert_equal "foo-1bar", Sass::SCSS::RX.escape_ident("foo-1bar")
+    assert_equal "-foo-bar", Sass::SCSS::RX.escape_ident("-foo-bar")
+    assert_equal "f2oo_bar", Sass::SCSS::RX.escape_ident("f2oo_bar")
+    assert_equal "_foo_bar", Sass::SCSS::RX.escape_ident("_foo_bar")
+  end
+
+  def test_escape_initial_funky_ident
+    assert_equal "\\000035foo", Sass::SCSS::RX.escape_ident("5foo")
+    assert_equal "-\\000035foo", Sass::SCSS::RX.escape_ident("-5foo")
+    assert_equal "_\\000035foo", Sass::SCSS::RX.escape_ident("_5foo")
+
+    assert_equal "\\&foo", Sass::SCSS::RX.escape_ident("&foo")
+    assert_equal "-\\&foo", Sass::SCSS::RX.escape_ident("-&foo")
+
+    assert_equal "-\\ foo", Sass::SCSS::RX.escape_ident("- foo")
+  end
+
+  def test_escape_mid_funky_ident
+    assert_equal "foo\\&bar", Sass::SCSS::RX.escape_ident("foo&bar")
+    assert_equal "foo\\ \\ bar", Sass::SCSS::RX.escape_ident("foo  bar")
+    assert_equal "foo\\00007fbar", Sass::SCSS::RX.escape_ident("foo\177bar")
+  end
+
+  private
+
+  def assert_match(rx, str)
+    refute_nil(match = rx.match(str))
+    assert_equal str.size, match[0].size
+  end
+
+  def assert_no_match(rx, str)
+    match = rx.match(str)
+    refute_equal str.size, match && match[0].size
+  end
+
+end
diff --git a/backends/css/gems/sass-3.4.9/test/sass/scss/scss_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/scss/scss_test.rb
new file mode 100755
index 0000000..9d5a02d
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/scss/scss_test.rb
@@ -0,0 +1,4008 @@
+#!/usr/bin/env ruby
+# -*- coding: utf-8 -*-
+require File.dirname(__FILE__) + '/test_helper'
+
+class ScssTest < MiniTest::Test
+  include ScssTestHelper
+
+  ## One-Line Comments
+
+  def test_one_line_comments
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  baz: bang; }
+CSS
+.foo {// bar: baz;}
+  baz: bang; //}
+}
+SCSS
+    assert_equal <<CSS, render(<<SCSS)
+.foo bar[val="//"] {
+  baz: bang; }
+CSS
+.foo bar[val="//"] {
+  baz: bang; //}
+}
+SCSS
+  end
+
+  ## Script
+
+  def test_variables
+    assert_equal <<CSS, render(<<SCSS)
+blat {
+  a: foo; }
+CSS
+$var: foo;
+
+blat {a: $var}
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  a: 2;
+  b: 6; }
+CSS
+foo {
+  $var: 2;
+  $another-var: 4;
+  a: $var;
+  b: $var + $another-var;}
+SCSS
+  end
+
+  def test_unicode_variables
+    assert_equal <<CSS, render(<<SCSS)
+blat {
+  a: foo; }
+CSS
+$vär: foo;
+
+blat {a: $vär}
+SCSS
+  end
+
+  def test_guard_assign
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  a: 1; }
+CSS
+$var: 1;
+$var: 2 !default;
+
+foo {a: $var}
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  a: 2; }
+CSS
+$var: 2 !default;
+
+foo {a: $var}
+SCSS
+  end
+
+  def test_sass_script
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  a: 3;
+  b: -1;
+  c: foobar;
+  d: 12px; }
+CSS
+foo {
+  a: 1 + 2;
+  b: 1 - 2;
+  c: foo + bar;
+  d: floor(12.3px); }
+SCSS
+  end
+
+  def test_debug_directive
+    assert_warning "test_debug_directive_inline.scss:2 DEBUG: hello world!" do
+      assert_equal <<CSS, render(<<SCSS)
+foo {
+  a: b; }
+
+bar {
+  c: d; }
+CSS
+foo {a: b}
+ debug "hello world!";
+bar {c: d}
+SCSS
+    end
+  end
+
+  def test_error_directive
+    assert_raise_message(Sass::SyntaxError, "hello world!") {render(<<SCSS)}
+foo {a: b}
+ error "hello world!";
+bar {c: d}
+SCSS
+  end
+
+  def test_warn_directive
+    expected_warning = <<EXPECTATION
+WARNING: this is a warning
+         on line 2 of test_warn_directive_inline.scss
+
+WARNING: this is a mixin
+         on line 1 of test_warn_directive_inline.scss, in `foo'
+         from line 3 of test_warn_directive_inline.scss
+EXPECTATION
+    assert_warning expected_warning do
+      assert_equal <<CSS, render(<<SCSS)
+bar {
+  c: d; }
+CSS
+ mixin foo { @warn "this is a mixin";}
+ warn "this is a warning";
+bar {c: d; @include foo;}
+SCSS
+    end
+  end
+
+  def test_for_directive
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: 1;
+  a: 2;
+  a: 3;
+  a: 4; }
+CSS
+.foo {
+  @for $var from 1 to 5 {a: $var;}
+}
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: 1;
+  a: 2;
+  a: 3;
+  a: 4;
+  a: 5; }
+CSS
+.foo {
+  @for $var from 1 through 5 {a: $var;}
+}
+SCSS
+  end
+
+  def test_for_directive_with_same_start_and_end
+    assert_equal <<CSS, render(<<SCSS)
+CSS
+.foo {
+  @for $var from 1 to 1 {a: $var;}
+}
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: 1; }
+CSS
+.foo {
+  @for $var from 1 through 1 {a: $var;}
+}
+SCSS
+  end
+
+  def test_decrementing_estfor_directive
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: 5;
+  a: 4;
+  a: 3;
+  a: 2;
+  a: 1; }
+CSS
+.foo {
+  @for $var from 5 through 1 {a: $var;}
+}
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: 5;
+  a: 4;
+  a: 3;
+  a: 2; }
+CSS
+.foo {
+  @for $var from 5 to 1 {a: $var;}
+}
+SCSS
+  end
+
+  def test_if_directive
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  a: b; }
+CSS
+ if "foo" == "foo" {foo {a: b}}
+ if "foo" != "foo" {bar {a: b}}
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+bar {
+  a: b; }
+CSS
+ if "foo" != "foo" {foo {a: b}}
+ else if "foo" == "foo" {bar {a: b}}
+ else if true {baz {a: b}}
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+bar {
+  a: b; }
+CSS
+ if "foo" != "foo" {foo {a: b}}
+ else {bar {a: b}}
+SCSS
+  end
+
+  def test_comment_after_if_directive
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  a: b;
+  /* This is a comment */
+  c: d; }
+CSS
+foo {
+  @if true {a: b}
+  /* This is a comment */
+  c: d }
+SCSS
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  a: b;
+  /* This is a comment */
+  c: d; }
+CSS
+foo {
+  @if true {a: b}
+  @else {x: y}
+  /* This is a comment */
+  c: d }
+SCSS
+  end
+
+  def test_while_directive
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: 1;
+  a: 2;
+  a: 3;
+  a: 4; }
+CSS
+$i: 1;
+
+.foo {
+  @while $i != 5 {
+    a: $i;
+    $i: $i + 1 !global;
+  }
+}
+SCSS
+  end
+
+  def test_each_directive
+    assert_equal <<CSS, render(<<SCSS)
+a {
+  b: 1px;
+  b: 2px;
+  b: 3px;
+  b: 4px; }
+
+c {
+  d: foo;
+  d: bar;
+  d: baz;
+  d: bang; }
+CSS
+a {
+  @each $number in 1px 2px 3px 4px {
+    b: $number;
+  }
+}
+c {
+  @each $str in foo, bar, baz, bang {
+    d: $str;
+  }
+}
+SCSS
+  end
+
+  def test_destructuring_each_directive
+    assert_equal <<CSS, render(<<SCSS)
+a {
+  foo: 1px;
+  bar: 2px;
+  baz: 3px; }
+
+c {
+  foo: "Value is bar";
+  bar: "Value is baz";
+  bang: "Value is "; }
+CSS
+a {
+  @each $name, $number in (foo: 1px, bar: 2px, baz: 3px) {
+    \#{$name}: $number;
+  }
+}
+c {
+  @each $key, $value in (foo bar) (bar, baz) bang {
+    \#{$key}: "Value is \#{$value}";
+  }
+}
+SCSS
+  end
+
+  def test_css_import_directive
+    assert_equal "@import url(foo.css);\n", render('@import "foo.css";')
+    assert_equal "@import url(foo.css);\n", render("@import 'foo.css';")
+    assert_equal "@import url(\"foo.css\");\n", render('@import url("foo.css");')
+    assert_equal "@import url(\"foo.css\");\n", render('@import url("foo.css");')
+    assert_equal "@import url(foo.css);\n", render('@import url(foo.css);')
+  end
+
+  def test_css_string_import_directive_with_media
+    assert_parses '@import "foo.css" screen;'
+    assert_parses '@import "foo.css" screen, print;'
+    assert_parses '@import "foo.css" screen, print and (foo: 0);'
+    assert_parses '@import "foo.css" screen, only print, screen and (foo: 0);'
+  end
+
+  def test_css_url_import_directive_with_media
+    assert_parses '@import url("foo.css") screen;'
+    assert_parses '@import url("foo.css") screen, print;'
+    assert_parses '@import url("foo.css") screen, print and (foo: 0);'
+    assert_parses '@import url("foo.css") screen, only print, screen and (foo: 0);'
+  end
+
+  def test_media_import
+    assert_equal("@import \"./fonts.sass\" all;\n", render("@import \"./fonts.sass\" all;"))
+  end
+
+  def test_dynamic_media_import
+    assert_equal(<<CSS, render(<<SCSS))
+ import "foo" print and (-webkit-min-device-pixel-ratio-foo: 25);
+CSS
+$media: print;
+$key: -webkit-min-device-pixel-ratio;
+$value: 20;
+ import "foo" \#{$media} and ($key + "-foo": $value + 5);
+SCSS
+  end
+
+  def test_http_import
+    assert_equal("@import \"http://fonts.googleapis.com/css?family=Droid+Sans\";\n";,
+      render("@import \"http://fonts.googleapis.com/css?family=Droid+Sans\";";))
+  end
+
+  def test_protocol_relative_import
+    assert_equal("@import \"//fonts.googleapis.com/css?family=Droid+Sans\";\n",
+      render("@import \"//fonts.googleapis.com/css?family=Droid+Sans\";"))
+  end
+
+  def test_import_with_interpolation
+    assert_equal <<CSS, render(<<SCSS)
+ import url("http://fonts.googleapis.com/css?family=Droid+Sans";);
+CSS
+$family: unquote("Droid+Sans");
+ import url("http://fonts.googleapis.com/css?family=\#{$family}";);
+SCSS
+  end
+
+  def test_url_import
+    assert_equal("@import url(fonts.sass);\n", render("@import url(fonts.sass);"))
+  end
+
+  def test_css_import_doesnt_move_through_comments
+    assert_equal <<CSS, render(<<SCSS)
+/* Comment 1 */
+ import url("foo.css");
+/* Comment 2 */
+ import url("bar.css");
+CSS
+/* Comment 1 */
+ import url("foo.css");
+
+/* Comment 2 */
+ import url("bar.css");
+SCSS
+  end
+
+  def test_css_import_movement_stops_at_comments
+    assert_equal <<CSS, render(<<SCSS)
+/* Comment 1 */
+ import url("foo.css");
+/* Comment 2 */
+ import url("bar.css");
+.foo {
+  a: b; }
+
+/* Comment 3 */
+CSS
+/* Comment 1 */
+ import url("foo.css");
+
+/* Comment 2 */
+
+.foo {a: b}
+
+/* Comment 3 */
+ import url("bar.css");
+SCSS
+  end
+
+  def test_block_comment_in_script
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  a: 1bar; }
+CSS
+foo {a: 1 + /* flang */ bar}
+SCSS
+  end
+
+  def test_line_comment_in_script
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  a: 1blang; }
+CSS
+foo {a: 1 + // flang }
+  blang }
+SCSS
+  end
+
+  ## Nested Rules
+
+  def test_nested_rules
+    assert_equal <<CSS, render(<<SCSS)
+foo bar {
+  a: b; }
+CSS
+foo {bar {a: b}}
+SCSS
+    assert_equal <<CSS, render(<<SCSS)
+foo bar {
+  a: b; }
+foo baz {
+  b: c; }
+CSS
+foo {
+  bar {a: b}
+  baz {b: c}}
+SCSS
+    assert_equal <<CSS, render(<<SCSS)
+foo bar baz {
+  a: b; }
+foo bang bip {
+  a: b; }
+CSS
+foo {
+  bar {baz {a: b}}
+  bang {bip {a: b}}}
+SCSS
+  end
+
+  def test_nested_rules_with_declarations
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  a: b; }
+  foo bar {
+    c: d; }
+CSS
+foo {
+  a: b;
+  bar {c: d}}
+SCSS
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  a: b; }
+  foo bar {
+    c: d; }
+CSS
+foo {
+  bar {c: d}
+  a: b}
+SCSS
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  ump: nump;
+  grump: clump; }
+  foo bar {
+    blat: bang;
+    habit: rabbit; }
+    foo bar baz {
+      a: b; }
+    foo bar bip {
+      c: d; }
+  foo bibble bap {
+    e: f; }
+CSS
+foo {
+  ump: nump;
+  grump: clump;
+  bar {
+    blat: bang;
+    habit: rabbit;
+    baz {a: b}
+    bip {c: d}}
+  bibble {
+    bap {e: f}}}
+SCSS
+  end
+
+  def test_nested_rules_with_fancy_selectors
+    assert_equal <<CSS, render(<<SCSS)
+foo .bar {
+  a: b; }
+foo :baz {
+  c: d; }
+foo bang:bop {
+  e: f; }
+foo ::qux {
+  g: h; }
+foo zap::fblthp {
+  i: j; }
+CSS
+foo {
+  .bar {a: b}
+  :baz {c: d}
+  bang:bop {e: f}
+  ::qux {g: h}
+  zap::fblthp {i: j}}
+SCSS
+  end
+
+  def test_almost_ambiguous_nested_rules_and_declarations
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  bar: baz bang bop biddle woo look at all these elems; }
+  foo bar:baz:bang:bop:biddle:woo:look:at:all:these:pseudoclasses {
+    a: b; }
+  foo bar:baz bang bop biddle woo look at all these elems {
+    a: b; }
+CSS
+foo {
+  bar:baz:bang:bop:biddle:woo:look:at:all:these:pseudoclasses {a: b};
+  bar:baz bang bop biddle woo look at all these elems {a: b};
+  bar:baz bang bop biddle woo look at all these elems; }
+SCSS
+  end
+
+  def test_newlines_in_selectors
+    assert_equal <<CSS, render(<<SCSS)
+foo
+bar {
+  a: b; }
+CSS
+foo
+bar {a: b}
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+foo baz,
+foo bang,
+bar baz,
+bar bang {
+  a: b; }
+CSS
+foo,
+bar {
+  baz,
+  bang {a: b}}
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+foo
+bar baz
+bang {
+  a: b; }
+foo
+bar bip bop {
+  c: d; }
+CSS
+foo
+bar {
+  baz
+  bang {a: b}
+
+  bip bop {c: d}}
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+foo bang, foo bip
+bop, bar
+baz bang, bar
+baz bip
+bop {
+  a: b; }
+CSS
+foo, bar
+baz {
+  bang, bip
+  bop {a: b}}
+SCSS
+  end
+
+  def test_trailing_comma_in_selector
+    assert_equal <<CSS, render(<<SCSS)
+#foo #bar,
+#baz #boom {
+  a: b; }
+
+#bip #bop {
+  c: d; }
+CSS
+#foo #bar,,
+,#baz #boom, {a: b}
+
+#bip #bop, ,, {c: d}
+SCSS
+  end
+
+  def test_parent_selectors
+    assert_equal <<CSS, render(<<SCSS)
+foo:hover {
+  a: b; }
+bar foo.baz {
+  c: d; }
+CSS
+foo {
+  &:hover {a: b}
+  bar &.baz {c: d}}
+SCSS
+  end
+
+  def test_parent_selector_with_subject
+    silence_warnings {assert_equal <<CSS, render(<<SCSS)}
+bar foo.baz! .bip {
+  a: b; }
+
+bar foo bar.baz! .bip {
+  c: d; }
+CSS
+foo {
+  bar &.baz! .bip {a: b}}
+
+foo bar {
+  bar &.baz! .bip {c: d}}
+SCSS
+  end
+
+  def test_parent_selector_with_suffix
+    assert_equal <<CSS, render(<<SCSS)
+.foo-bar {
+  a: b; }
+.foo_bar {
+  c: d; }
+.foobar {
+  e: f; }
+.foo123 {
+  e: f; }
+
+:hover-suffix {
+  g: h; }
+CSS
+.foo {
+  &-bar {a: b}
+  &_bar {c: d}
+  &bar {e: f}
+  &123 {e: f}
+}
+
+:hover {
+  &-suffix {g: h}
+}
+SCSS
+  end
+
+  def test_unknown_directive_bubbling
+    assert_equal(<<CSS, render(<<SCSS, :style => :nested))
+ fblthp {
+  .foo .bar {
+    a: b; } }
+CSS
+.foo {
+  @fblthp {
+    .bar {a: b}
+  }
+}
+SCSS
+  end
+
+  def test_keyframe_bubbling
+    assert_equal(<<CSS, render(<<SCSS, :style => :nested))
+ keyframes spin {
+  0% {
+    transform: rotate(0deg); } }
+ -webkit-keyframes spin {
+  0% {
+    transform: rotate(0deg); } }
+CSS
+.foo {
+  @keyframes spin {
+    0% {transform: rotate(0deg)}
+  }
+  @-webkit-keyframes spin {
+    0% {transform: rotate(0deg)}
+  }
+}
+SCSS
+  end
+
+  ## Namespace Properties
+
+  def test_namespace_properties
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  bar: baz;
+  bang-bip: 1px;
+  bang-bop: bar; }
+CSS
+foo {
+  bar: baz;
+  bang: {
+    bip: 1px;
+    bop: bar;}}
+SCSS
+  end
+
+  def test_several_namespace_properties
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  bar: baz;
+  bang-bip: 1px;
+  bang-bop: bar;
+  buzz-fram: "foo";
+  buzz-frum: moo; }
+CSS
+foo {
+  bar: baz;
+  bang: {
+    bip: 1px;
+    bop: bar;}
+  buzz: {
+    fram: "foo";
+    frum: moo;
+  }
+}
+SCSS
+  end
+
+  def test_nested_namespace_properties
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  bar: baz;
+  bang-bip: 1px;
+  bang-bop: bar;
+  bang-blat-baf: bort; }
+CSS
+foo {
+  bar: baz;
+  bang: {
+    bip: 1px;
+    bop: bar;
+    blat:{baf:bort}}}
+SCSS
+  end
+
+  def test_namespace_properties_with_value
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  bar: baz;
+    bar-bip: bop;
+    bar-bing: bop; }
+CSS
+foo {
+  bar: baz {
+    bip: bop;
+    bing: bop; }}
+SCSS
+  end
+
+  def test_namespace_properties_with_script_value
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  bar: bazbang;
+    bar-bip: bop;
+    bar-bing: bop; }
+CSS
+foo {
+  bar: baz + bang {
+    bip: bop;
+    bing: bop; }}
+SCSS
+  end
+
+  def test_no_namespace_properties_without_space
+    assert_equal <<CSS, render(<<SCSS)
+foo bar:baz {
+  bip: bop; }
+CSS
+foo {
+  bar:baz {
+    bip: bop }}
+SCSS
+  end
+
+  def test_no_namespace_properties_without_space_even_when_its_unambiguous
+    render(<<SCSS)
+foo {
+  bar:baz calc(1 + 2) {
+    bip: bop }}
+SCSS
+    assert(false, "Expected syntax error")
+  rescue Sass::SyntaxError => e
+    assert_equal 'Invalid CSS after "bar:baz calc": expected selector, was "(1 + 2)"', e.message
+    assert_equal 2, e.sass_line
+  end
+
+  def test_namespace_properties_without_space_allowed_for_non_identifier
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  bar: 1px;
+    bar-bip: bop; }
+CSS
+foo {
+  bar:1px {
+    bip: bop }}
+SCSS
+  end
+
+  ## Mixins
+
+  def test_basic_mixins
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: b; }
+CSS
+ mixin foo {
+  .foo {a: b}}
+
+ include foo;
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+bar {
+  c: d; }
+  bar .foo {
+    a: b; }
+CSS
+ mixin foo {
+  .foo {a: b}}
+
+bar {
+  @include foo;
+  c: d; }
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+bar {
+  a: b;
+  c: d; }
+CSS
+ mixin foo {a: b}
+
+bar {
+  @include foo;
+  c: d; }
+SCSS
+  end
+
+  def test_mixins_with_empty_args
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: b; }
+CSS
+ mixin foo() {a: b}
+
+.foo { include foo();}
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: b; }
+CSS
+ mixin foo() {a: b}
+
+.foo { include foo;}
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: b; }
+CSS
+ mixin foo {a: b}
+
+.foo { include foo();}
+SCSS
+  end
+
+  def test_mixins_with_args
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: bar; }
+CSS
+ mixin foo($a) {a: $a}
+
+.foo { include foo(bar)}
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: bar;
+  b: 12px; }
+CSS
+ mixin foo($a, $b) {
+  a: $a;
+  b: $b; }
+
+.foo { include foo(bar, 12px)}
+SCSS
+  end
+
+  def test_keyframes_rules_in_content
+    assert_equal <<CSS, render(<<SCSS)
+ keyframes identifier {
+  0% {
+    top: 0;
+    left: 0; }
+  30% {
+    top: 50px; }
+  68%, 72% {
+    left: 50px; }
+  100% {
+    top: 100px;
+    left: 100%; } }
+CSS
+ mixin keyframes {
+  @keyframes identifier { @content }
+}
+
+ include keyframes {
+  0% {top: 0; left: 0}
+  \#{"30%"} {top: 50px}
+  68%, 72% {left: 50px}
+  100% {top: 100px; left: 100%}
+}
+SCSS
+  end
+
+  ## Functions
+
+  def test_basic_function
+    assert_equal(<<CSS, render(<<SASS))
+bar {
+  a: 3; }
+CSS
+ function foo() {
+  @return 1 + 2;
+}
+
+bar {
+  a: foo();
+}
+SASS
+  end
+
+  def test_function_args
+    assert_equal(<<CSS, render(<<SASS))
+bar {
+  a: 3; }
+CSS
+ function plus($var1, $var2) {
+  @return $var1 + $var2;
+}
+
+bar {
+  a: plus(1, 2);
+}
+SASS
+  end
+
+  ## Var Args
+
+  def test_mixin_var_args
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: 1;
+  b: 2, 3, 4; }
+CSS
+ mixin foo($a, $b...) {
+  a: $a;
+  b: $b;
+}
+
+.foo { include foo(1, 2, 3, 4)}
+SCSS
+  end
+
+  def test_mixin_empty_var_args
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: 1;
+  b: 0; }
+CSS
+ mixin foo($a, $b...) {
+  a: $a;
+  b: length($b);
+}
+
+.foo { include foo(1)}
+SCSS
+  end
+
+  def test_mixin_var_args_act_like_list
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: 3;
+  b: 3; }
+CSS
+ mixin foo($a, $b...) {
+  a: length($b);
+  b: nth($b, 2);
+}
+
+.foo { include foo(1, 2, 3, 4)}
+SCSS
+  end
+
+  def test_mixin_splat_args
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: 1;
+  b: 2;
+  c: 3;
+  d: 4; }
+CSS
+ mixin foo($a, $b, $c, $d) {
+  a: $a;
+  b: $b;
+  c: $c;
+  d: $d;
+}
+
+$list: 2, 3, 4;
+.foo { include foo(1, $list...)}
+SCSS
+  end
+
+  def test_mixin_splat_expression
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: 1;
+  b: 2;
+  c: 3;
+  d: 4; }
+CSS
+ mixin foo($a, $b, $c, $d) {
+  a: $a;
+  b: $b;
+  c: $c;
+  d: $d;
+}
+
+.foo { include foo(1, (2, 3, 4)...)}
+SCSS
+  end
+
+  def test_mixin_splat_args_with_var_args
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: 1;
+  b: 2, 3, 4; }
+CSS
+ mixin foo($a, $b...) {
+  a: $a;
+  b: $b;
+}
+
+$list: 2, 3, 4;
+.foo { include foo(1, $list...)}
+SCSS
+  end
+
+  def test_mixin_splat_args_with_var_args_and_normal_args
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: 1;
+  b: 2;
+  c: 3, 4; }
+CSS
+ mixin foo($a, $b, $c...) {
+  a: $a;
+  b: $b;
+  c: $c;
+}
+
+$list: 2, 3, 4;
+.foo { include foo(1, $list...)}
+SCSS
+  end
+
+  def test_mixin_splat_args_with_var_args_preserves_separator
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: 1;
+  b: 2 3 4 5; }
+CSS
+ mixin foo($a, $b...) {
+  a: $a;
+  b: $b;
+}
+
+$list: 3 4 5;
+.foo { include foo(1, 2, $list...)}
+SCSS
+  end
+
+  def test_mixin_var_and_splat_args_pass_through_keywords
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: 3;
+  b: 1;
+  c: 2; }
+CSS
+ mixin foo($a...) {
+  @include bar($a...);
+}
+
+ mixin bar($b, $c, $a) {
+  a: $a;
+  b: $b;
+  c: $c;
+}
+
+.foo { include foo(1, $c: 2, $a: 3)}
+SCSS
+  end
+
+  def test_mixin_var_keyword_args
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: 1;
+  b: 2;
+  c: 3; }
+CSS
+ mixin foo($args...) {
+  a: map-get(keywords($args), a);
+  b: map-get(keywords($args), b);
+  c: map-get(keywords($args), c);
+}
+
+.foo { include foo($a: 1, $b: 2, $c: 3)}
+SCSS
+  end
+
+  def test_mixin_empty_var_keyword_args
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  length: 0; }
+CSS
+ mixin foo($args...) {
+  length: length(keywords($args));
+}
+
+.foo { include foo}
+SCSS
+  end
+
+  def test_mixin_map_splat
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: 1;
+  b: 2;
+  c: 3; }
+CSS
+ mixin foo($a, $b, $c) {
+  a: $a;
+  b: $b;
+  c: $c;
+}
+
+.foo {
+  $map: (a: 1, b: 2, c: 3);
+  @include foo($map...);
+}
+SCSS
+  end
+
+  def test_mixin_map_and_list_splat
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: x;
+  b: y;
+  c: z;
+  d: 1;
+  e: 2;
+  f: 3; }
+CSS
+ mixin foo($a, $b, $c, $d, $e, $f) {
+  a: $a;
+  b: $b;
+  c: $c;
+  d: $d;
+  e: $e;
+  f: $f;
+}
+
+.foo {
+  $list: x y z;
+  $map: (d: 1, e: 2, f: 3);
+  @include foo($list..., $map...);
+}
+SCSS
+  end
+
+  def test_mixin_map_splat_takes_precedence_over_pass_through
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: 1;
+  b: 2;
+  c: z; }
+CSS
+ mixin foo($args...) {
+  $map: (c: z);
+  @include bar($args..., $map...);
+}
+
+ mixin bar($a, $b, $c) {
+  a: $a;
+  b: $b;
+  c: $c;
+}
+
+.foo {
+  @include foo(1, $b: 2, $c: 3);
+}
+SCSS
+  end
+
+  def test_mixin_list_of_pairs_splat_treated_as_list
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: a 1;
+  b: b 2;
+  c: c 3; }
+CSS
+ mixin foo($a, $b, $c) {
+  a: $a;
+  b: $b;
+  c: $c;
+}
+
+.foo {
+  @include foo((a 1, b 2, c 3)...);
+}
+SCSS
+  end
+
+  def test_mixin_splat_after_keyword_args
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: 1;
+  b: 2;
+  c: 3; }
+CSS
+ mixin foo($a, $b, $c) {
+  a: 1;
+  b: 2;
+  c: 3;
+}
+
+.foo {
+  @include foo(1, $c: 3, 2...);
+}
+SCSS
+  end
+
+  def test_mixin_keyword_args_after_splat
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: 1;
+  b: 2;
+  c: 3; }
+CSS
+ mixin foo($a, $b, $c) {
+  a: 1;
+  b: 2;
+  c: 3;
+}
+
+.foo {
+  @include foo(1, 2..., $c: 3);
+}
+SCSS
+  end
+
+  def test_mixin_keyword_splat_after_keyword_args
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: 1;
+  b: 2;
+  c: 3; }
+CSS
+ mixin foo($a, $b, $c) {
+  a: 1;
+  b: 2;
+  c: 3;
+}
+
+.foo {
+  @include foo(1, $b: 2, (c: 3)...);
+}
+SCSS
+  end
+
+  def test_mixin_triple_keyword_splat_merge
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  foo: 1;
+  bar: 2;
+  kwarg: 3;
+  a: 3;
+  b: 2;
+  c: 3; }
+CSS
+ mixin foo($foo, $bar, $kwarg, $a, $b, $c) {
+  foo: $foo;
+  bar: $bar;
+  kwarg: $kwarg;
+  a: $a;
+  b: $b;
+  c: $c;
+}
+
+ mixin bar($args...) {
+  @include foo($args..., $bar: 2, $a: 2, $b: 2, (kwarg: 3, a: 3, c: 3)...);
+}
+
+.foo {
+  @include bar($foo: 1, $a: 1, $b: 1, $c: 1);
+}
+SCSS
+  end
+
+  def test_mixin_map_splat_converts_hyphens_and_underscores_for_real_args
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: 1;
+  b: 2;
+  c: 3;
+  d: 4; }
+CSS
+ mixin foo($a-1, $b-2, $c_3, $d_4) {
+  a: $a-1;
+  b: $b-2;
+  c: $c_3;
+  d: $d_4;
+}
+
+.foo {
+  $map: (a-1: 1, b_2: 2, c-3: 3, d_4: 4);
+  @include foo($map...);
+}
+SCSS
+  end
+
+  def test_mixin_map_splat_doesnt_convert_hyphens_and_underscores_for_var_args
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a-1: 1;
+  b_2: 2;
+  c-3: 3;
+  d_4: 4; }
+CSS
+ mixin foo($args...) {
+  @each $key, $value in keywords($args) {
+    \#{$key}: $value;
+  }
+}
+
+.foo {
+  $map: (a-1: 1, b_2: 2, c-3: 3, d_4: 4);
+  @include foo($map...);
+}
+SCSS
+  end
+
+  def test_mixin_conflicting_splat_after_keyword_args
+    assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
+Mixin foo was passed argument $b both by position and by name.
+MESSAGE
+ mixin foo($a, $b, $c) {
+  a: 1;
+  b: 2;
+  c: 3;
+}
+
+.foo {
+  @include foo(1, $b: 2, 3...);
+}
+SCSS
+  end
+
+  def test_mixin_keyword_splat_must_have_string_keys
+    assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
+Variable keyword argument map must have string keys.
+12 is not a string in (12: 1).
+MESSAGE
+ mixin foo($a) {
+  a: $a;
+}
+
+.foo { include foo((12: 1)...)}
+SCSS
+  end
+
+  def test_mixin_positional_arg_after_splat
+    assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
+Only keyword arguments may follow variable arguments (...).
+MESSAGE
+ mixin foo($a, $b, $c) {
+  a: 1;
+  b: 2;
+  c: 3;
+}
+
+.foo {
+  @include foo(1, 2..., 3);
+}
+SCSS
+  end
+
+  def test_mixin_var_args_with_keyword
+    assert_raise_message(Sass::SyntaxError, "Positional arguments must come before keyword arguments.") 
{render <<SCSS}
+ mixin foo($a, $b...) {
+  a: $a;
+  b: $b;
+}
+
+.foo { include foo($a: 1, 2, 3, 4)}
+SCSS
+  end
+
+  def test_mixin_keyword_for_var_arg
+    assert_raise_message(Sass::SyntaxError, "Argument $b of mixin foo cannot be used as a named argument.") 
{render <<SCSS}
+ mixin foo($a, $b...) {
+  a: $a;
+  b: $b;
+}
+
+.foo { include foo(1, $b: 2 3 4)}
+SCSS
+  end
+
+  def test_mixin_keyword_for_unknown_arg_with_var_args
+    assert_raise_message(Sass::SyntaxError, "Mixin foo doesn't have an argument named $c.") {render <<SCSS}
+ mixin foo($a, $b...) {
+  a: $a;
+  b: $b;
+}
+
+.foo { include foo(1, $c: 2 3 4)}
+SCSS
+  end
+
+  def test_mixin_map_splat_before_list_splat
+    assert_raise_message(Sass::SyntaxError, "Variable keyword arguments must be a map (was (2 3)).") {render 
<<SCSS}
+ mixin foo($a, $b, $c) {
+  a: $a;
+  b: $b;
+  c: $c;
+}
+
+.foo {
+  @include foo((a: 1)..., (2 3)...);
+}
+SCSS
+  end
+
+  def test_mixin_map_splat_with_unknown_keyword
+    assert_raise_message(Sass::SyntaxError, "Mixin foo doesn't have an argument named $c.") {render <<SCSS}
+ mixin foo($a, $b) {
+  a: $a;
+  b: $b;
+}
+
+.foo {
+  @include foo(1, 2, (c: 1)...);
+}
+SCSS
+  end
+
+  def test_mixin_map_splat_with_wrong_type
+    assert_raise_message(Sass::SyntaxError, "Variable keyword arguments must be a map (was 12).") {render 
<<SCSS}
+ mixin foo($a, $b) {
+  a: $a;
+  b: $b;
+}
+
+.foo {
+  @include foo((1, 2)..., 12...);
+}
+SCSS
+  end
+
+  def test_mixin_splat_too_many_args
+    assert_warning(<<WARNING) {render <<SCSS}
+WARNING: Mixin foo takes 2 arguments but 4 were passed.
+        on line 2 of #{filename_for_test(:scss)}
+This will be an error in future versions of Sass.
+WARNING
+ mixin foo($a, $b) {}
+ include foo((1, 2, 3, 4)...);
+SCSS
+  end
+
+  def test_function_var_args
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  val: "a: 1, b: 2, 3, 4"; }
+CSS
+ function foo($a, $b...) {
+  @return "a: \#{$a}, b: \#{$b}";
+}
+
+.foo {val: foo(1, 2, 3, 4)}
+SCSS
+  end
+
+  def test_function_empty_var_args
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  val: "a: 1, b: 0"; }
+CSS
+ function foo($a, $b...) {
+  @return "a: \#{$a}, b: \#{length($b)}";
+}
+
+.foo {val: foo(1)}
+SCSS
+  end
+
+  def test_function_var_args_act_like_list
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  val: "a: 3, b: 3"; }
+CSS
+ function foo($a, $b...) {
+  @return "a: \#{length($b)}, b: \#{nth($b, 2)}";
+}
+
+.foo {val: foo(1, 2, 3, 4)}
+SCSS
+  end
+
+  def test_function_splat_args
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  val: "a: 1, b: 2, c: 3, d: 4"; }
+CSS
+ function foo($a, $b, $c, $d) {
+  @return "a: \#{$a}, b: \#{$b}, c: \#{$c}, d: \#{$d}";
+}
+
+$list: 2, 3, 4;
+.foo {val: foo(1, $list...)}
+SCSS
+  end
+
+  def test_function_splat_expression
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  val: "a: 1, b: 2, c: 3, d: 4"; }
+CSS
+ function foo($a, $b, $c, $d) {
+  @return "a: \#{$a}, b: \#{$b}, c: \#{$c}, d: \#{$d}";
+}
+
+.foo {val: foo(1, (2, 3, 4)...)}
+SCSS
+  end
+
+  def test_function_splat_args_with_var_args
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  val: "a: 1, b: 2, 3, 4"; }
+CSS
+ function foo($a, $b...) {
+  @return "a: \#{$a}, b: \#{$b}";
+}
+
+$list: 2, 3, 4;
+.foo {val: foo(1, $list...)}
+SCSS
+  end
+
+  def test_function_splat_args_with_var_args_and_normal_args
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  val: "a: 1, b: 2, c: 3, 4"; }
+CSS
+ function foo($a, $b, $c...) {
+  @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
+}
+
+$list: 2, 3, 4;
+.foo {val: foo(1, $list...)}
+SCSS
+  end
+
+  def test_function_splat_args_with_var_args_preserves_separator
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  val: "a: 1, b: 2 3 4 5"; }
+CSS
+ function foo($a, $b...) {
+  @return "a: \#{$a}, b: \#{$b}";
+}
+
+$list: 3 4 5;
+.foo {val: foo(1, 2, $list...)}
+SCSS
+  end
+
+  def test_function_var_and_splat_args_pass_through_keywords
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  val: "a: 3, b: 1, c: 2"; }
+CSS
+ function foo($a...) {
+  @return bar($a...);
+}
+
+ function bar($b, $c, $a) {
+  @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
+}
+
+.foo {val: foo(1, $c: 2, $a: 3)}
+SCSS
+  end
+
+  def test_function_var_keyword_args
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  val: "a: 1, b: 2, c: 3"; }
+CSS
+ function foo($args...) {
+  @return "a: \#{map-get(keywords($args), a)}, " +
+    "b: \#{map-get(keywords($args), b)}, " +
+    "c: \#{map-get(keywords($args), c)}";
+}
+
+.foo {val: foo($a: 1, $b: 2, $c: 3)}
+SCSS
+  end
+
+  def test_function_empty_var_keyword_args
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  length: 0; }
+CSS
+ function foo($args...) {
+  @return length(keywords($args));
+}
+
+.foo {length: foo()}
+SCSS
+  end
+
+  def test_function_map_splat
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  val: "a: 1, b: 2, c: 3"; }
+CSS
+ function foo($a, $b, $c) {
+  @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
+}
+
+.foo {
+  $map: (a: 1, b: 2, c: 3);
+  val: foo($map...);
+}
+SCSS
+  end
+
+  def test_function_map_and_list_splat
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  val: "a: x, b: y, c: z, d: 1, e: 2, f: 3"; }
+CSS
+ function foo($a, $b, $c, $d, $e, $f) {
+  @return "a: \#{$a}, b: \#{$b}, c: \#{$c}, d: \#{$d}, e: \#{$e}, f: \#{$f}";
+}
+
+.foo {
+  $list: x y z;
+  $map: (d: 1, e: 2, f: 3);
+  val: foo($list..., $map...);
+}
+SCSS
+  end
+
+  def test_function_map_splat_takes_precedence_over_pass_through
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  val: "a: 1, b: 2, c: z"; }
+CSS
+ function foo($args...) {
+  $map: (c: z);
+  @return bar($args..., $map...);
+}
+
+ function bar($a, $b, $c) {
+  @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
+}
+
+.foo {
+  val: foo(1, $b: 2, $c: 3);
+}
+SCSS
+  end
+
+  def test_ruby_function_map_splat_takes_precedence_over_pass_through
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  val: 1 2 3 z; }
+CSS
+ function foo($args...) {
+  $map: (val: z);
+  @return append($args..., $map...);
+}
+
+.foo {
+  val: foo(1 2 3, $val: 4)
+}
+SCSS
+  end
+
+  def test_function_list_of_pairs_splat_treated_as_list
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  val: "a: a 1, b: b 2, c: c 3"; }
+CSS
+ function foo($a, $b, $c) {
+  @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
+}
+
+.foo {
+  val: foo((a 1, b 2, c 3)...);
+}
+SCSS
+  end
+
+  def test_function_splat_after_keyword_args
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  val: "a: 1, b: 2, c: 3"; }
+CSS
+ function foo($a, $b, $c) {
+  @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
+}
+
+.foo {
+  val: foo(1, $c: 3, 2...);
+}
+SCSS
+  end
+
+  def test_function_keyword_args_after_splat
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  val: "a: 1, b: 2, c: 3"; }
+CSS
+ function foo($a, $b, $c) {
+  @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
+}
+
+.foo {
+  val: foo(1, 2..., $c: 3);
+}
+SCSS
+  end
+
+  def test_function_keyword_splat_after_keyword_args
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  val: "a: 1, b: 2, c: 3"; }
+CSS
+ function foo($a, $b, $c) {
+  @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
+}
+
+.foo {
+  val: foo(1, $b: 2, (c: 3)...);
+}
+SCSS
+  end
+
+  def test_function_triple_keyword_splat_merge
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  val: "foo: 1, bar: 2, kwarg: 3, a: 3, b: 2, c: 3"; }
+CSS
+ function foo($foo, $bar, $kwarg, $a, $b, $c) {
+  @return "foo: \#{$foo}, bar: \#{$bar}, kwarg: \#{$kwarg}, a: \#{$a}, b: \#{$b}, c: \#{$c}";
+}
+
+ function bar($args...) {
+  @return foo($args..., $bar: 2, $a: 2, $b: 2, (kwarg: 3, a: 3, c: 3)...);
+}
+
+.foo {
+  val: bar($foo: 1, $a: 1, $b: 1, $c: 1);
+}
+SCSS
+  end
+
+  def test_function_conflicting_splat_after_keyword_args
+    assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
+Function foo was passed argument $b both by position and by name.
+MESSAGE
+ function foo($a, $b, $c) {
+  @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
+}
+
+.foo {
+  val: foo(1, $b: 2, 3...);
+}
+SCSS
+  end
+
+  def test_function_positional_arg_after_splat
+    assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
+Only keyword arguments may follow variable arguments (...).
+MESSAGE
+ function foo($a, $b, $c) {
+  @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
+}
+
+.foo {
+  val: foo(1, 2..., 3);
+}
+SCSS
+  end
+
+  def test_function_var_args_with_keyword
+    assert_raise_message(Sass::SyntaxError, "Positional arguments must come before keyword arguments.") 
{render <<SCSS}
+ function foo($a, $b...) {
+  @return "a: \#{$a}, b: \#{$b}";
+}
+
+.foo {val: foo($a: 1, 2, 3, 4)}
+SCSS
+  end
+
+  def test_function_keyword_for_var_arg
+    assert_raise_message(Sass::SyntaxError, "Argument $b of function foo cannot be used as a named 
argument.") {render <<SCSS}
+ function foo($a, $b...) {
+  @return "a: \#{$a}, b: \#{$b}";
+}
+
+.foo {val: foo(1, $b: 2 3 4)}
+SCSS
+  end
+
+  def test_function_keyword_for_unknown_arg_with_var_args
+    assert_raise_message(Sass::SyntaxError, "Function foo doesn't have an argument named $c.") {render 
<<SCSS}
+ function foo($a, $b...) {
+  @return "a: \#{$a}, b: \#{length($b)}";
+}
+
+.foo {val: foo(1, $c: 2 3 4)}
+SCSS
+  end
+
+  def test_function_var_args_passed_to_native
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  val: #102035; }
+CSS
+ function foo($args...) {
+  @return adjust-color($args...);
+}
+
+.foo {val: foo(#102030, $blue: 5)}
+SCSS
+  end
+
+  def test_function_map_splat_before_list_splat
+    assert_raise_message(Sass::SyntaxError, "Variable keyword arguments must be a map (was (2 3)).") {render 
<<SCSS}
+ function foo($a, $b, $c) {
+  @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
+}
+
+.foo {
+  val: foo((a: 1)..., (2 3)...);
+}
+SCSS
+  end
+
+  def test_function_map_splat_with_unknown_keyword
+    assert_raise_message(Sass::SyntaxError, "Function foo doesn't have an argument named $c.") {render 
<<SCSS}
+ function foo($a, $b) {
+  @return "a: \#{$a}, b: \#{$b}";
+}
+
+.foo {
+  val: foo(1, 2, (c: 1)...);
+}
+SCSS
+  end
+
+  def test_function_map_splat_with_wrong_type
+    assert_raise_message(Sass::SyntaxError, "Variable keyword arguments must be a map (was 12).") {render 
<<SCSS}
+ function foo($a, $b) {
+  @return "a: \#{$a}, b: \#{$b}";
+}
+
+.foo {
+  val: foo((1, 2)..., 12...);
+}
+SCSS
+  end
+
+  def test_function_keyword_splat_must_have_string_keys
+    assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
+Variable keyword argument map must have string keys.
+12 is not a string in (12: 1).
+MESSAGE
+ function foo($a) {
+  @return $a;
+}
+
+.foo {val: foo((12: 1)...)}
+SCSS
+  end
+
+  def test_function_splat_too_many_args
+    assert_warning(<<WARNING) {render <<SCSS}
+WARNING: Function foo takes 2 arguments but 4 were passed.
+        on line 2 of #{filename_for_test(:scss)}
+This will be an error in future versions of Sass.
+WARNING
+ function foo($a, $b) { return null}
+$var: foo((1, 2, 3, 4)...);
+SCSS
+  end
+
+  ## Interpolation
+
+  def test_basic_selector_interpolation
+    assert_equal <<CSS, render(<<SCSS)
+foo ab baz {
+  a: b; }
+CSS
+foo \#{'a' + 'b'} baz {a: b}
+SCSS
+    assert_equal <<CSS, render(<<SCSS)
+foo.bar baz {
+  a: b; }
+CSS
+foo\#{".bar"} baz {a: b}
+SCSS
+    assert_equal <<CSS, render(<<SCSS)
+foo.bar baz {
+  a: b; }
+CSS
+\#{"foo"}.bar baz {a: b}
+SCSS
+  end
+
+  def test_selector_only_interpolation
+    assert_equal <<CSS, render(<<SCSS)
+foo bar {
+  a: b; }
+CSS
+\#{"foo" + " bar"} {a: b}
+SCSS
+  end
+
+  def test_selector_interpolation_before_element_name
+    assert_equal <<CSS, render(<<SCSS)
+foo barbaz {
+  a: b; }
+CSS
+\#{"foo" + " bar"}baz {a: b}
+SCSS
+  end
+
+  def test_selector_interpolation_in_string
+    assert_equal <<CSS, render(<<SCSS)
+foo[val="bar foo bar baz"] {
+  a: b; }
+CSS
+foo[val="bar \#{"foo" + " bar"} baz"] {a: b}
+SCSS
+  end
+
+  def test_selector_interpolation_in_pseudoclass
+    assert_equal <<CSS, render(<<SCSS)
+foo:nth-child(5n) {
+  a: b; }
+CSS
+foo:nth-child(\#{5 + "n"}) {a: b}
+SCSS
+  end
+
+  def test_selector_interpolation_at_class_begininng
+    assert_equal <<CSS, render(<<SCSS)
+.zzz {
+  a: b; }
+CSS
+$zzz: zzz;
+.\#{$zzz} { a: b; }
+SCSS
+  end
+
+  def test_selector_interpolation_at_id_begininng
+    assert_equal <<CSS, render(<<SCSS)
+#zzz {
+  a: b; }
+CSS
+$zzz: zzz;
+#\#{$zzz} { a: b; }
+SCSS
+  end
+
+  def test_selector_interpolation_at_pseudo_begininng
+    assert_equal <<CSS, render(<<SCSS)
+:zzz::zzz {
+  a: b; }
+CSS
+$zzz: zzz;
+:\#{$zzz}::\#{$zzz} { a: b; }
+SCSS
+  end
+
+  def test_selector_interpolation_at_attr_beginning
+    assert_equal <<CSS, render(<<SCSS)
+[zzz=foo] {
+  a: b; }
+CSS
+$zzz: zzz;
+[\#{$zzz}=foo] { a: b; }
+SCSS
+  end
+
+  def test_selector_interpolation_at_attr_end
+    assert_equal <<CSS, render(<<SCSS)
+[foo=zzz] {
+  a: b; }
+CSS
+$zzz: zzz;
+[foo=\#{$zzz}] { a: b; }
+SCSS
+  end
+
+  def test_selector_interpolation_at_dashes
+    assert_equal <<CSS, render(<<SCSS)
+div {
+  -foo-a-b-foo: foo; }
+CSS
+$a : a;
+$b : b;
+div { -foo-\#{$a}-\#{$b}-foo: foo }
+SCSS
+  end
+
+  def test_selector_interpolation_in_reference_combinator
+    assert_equal <<CSS, render(<<SCSS)
+.foo /a/ .bar /b|c/ .baz {
+  a: b; }
+CSS
+$a: a;
+$b: b;
+$c: c;
+.foo /\#{$a}/ .bar /\#{$b}|\#{$c}/ .baz {a: b}
+SCSS
+  end
+
+  def test_parent_selector_with_parent_and_subject
+    silence_warnings {assert_equal <<CSS, render(<<SCSS)}
+bar foo.baz! .bip {
+  c: d; }
+CSS
+$subject: "!";
+foo {
+  bar &.baz\#{$subject} .bip {c: d}}
+SCSS
+  end
+
+  def test_basic_prop_name_interpolation
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  barbazbang: blip; }
+CSS
+foo {bar\#{"baz" + "bang"}: blip}
+SCSS
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  bar3: blip; }
+CSS
+foo {bar\#{1 + 2}: blip}
+SCSS
+  end
+
+  def test_prop_name_only_interpolation
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  bazbang: blip; }
+CSS
+foo {\#{"baz" + "bang"}: blip}
+SCSS
+  end
+
+  def test_directive_interpolation
+    assert_equal <<CSS, render(<<SCSS)
+ foo bar12 qux {
+  a: b; }
+CSS
+$baz: 12;
+ foo bar\#{$baz} qux {a: b}
+SCSS
+  end
+
+  def test_media_interpolation
+    assert_equal <<CSS, render(<<SCSS)
+ media bar12 {
+  a: b; }
+CSS
+$baz: 12;
+ media bar\#{$baz} {a: b}
+SCSS
+  end
+
+  def test_script_in_media
+    assert_equal <<CSS, render(<<SCSS)
+ media screen and (-webkit-min-device-pixel-ratio: 20), only print {
+  a: b; }
+CSS
+$media1: screen;
+$media2: print;
+$var: -webkit-min-device-pixel-ratio;
+$val: 20;
+ media \#{$media1} and ($var: $val), only \#{$media2} {a: b}
+SCSS
+
+    assert_equal <<CSS, render(<<SCSS)
+ media screen and (-webkit-min-device-pixel-ratio: 13) {
+  a: b; }
+CSS
+$vals: 1 2 3;
+ media screen and (-webkit-min-device-pixel-ratio: 5 + 6 + nth($vals, 2)) {a: b}
+SCSS
+  end
+
+  def test_media_interpolation_with_reparse
+    assert_equal <<CSS, render(<<SCSS)
+ media screen and (max-width: 300px) {
+  a: b; }
+ media screen and (max-width: 300px) {
+  a: b; }
+ media screen and (max-width: 300px) {
+  a: b; }
+ media screen and (max-width: 300px), print and (max-width: 300px) {
+  a: b; }
+CSS
+$constraint: "(max-width: 300px)";
+$fragment: "nd \#{$constraint}";
+$comma: "een, pri";
+ media screen and \#{$constraint} {a: b}
+ media screen {
+  @media \#{$constraint} {a: b}
+}
+ media screen a\#{$fragment} {a: b}
+ media scr\#{$comma}nt {
+  @media \#{$constraint} {a: b}
+}
+SCSS
+  end
+
+  def test_moz_document_interpolation
+    assert_equal <<CSS, render(<<SCSS)
+ -moz-document url(http://sass-lang.com/),
+               url-prefix(http://sass-lang.com/docs),
+               domain(sass-lang.com),
+               domain("sass-lang.com") {
+  .foo {
+    a: b; } }
+CSS
+$domain: "sass-lang.com";
+ -moz-document url(http://\#{$domain}/),
+               url-prefix(http://\#{$domain}/docs),
+               domain(\#{$domain}),
+               \#{domain($domain)} {
+  .foo {a: b}
+}
+SCSS
+  end
+
+  def test_supports_with_expressions
+    assert_equal <<CSS, render(<<SCSS)
+ supports (feature1: val) and (feature2: val) or (not (feature23: val4)) {
+  foo {
+    a: b; } }
+CSS
+$query: "(feature1: val)";
+$feature: feature2;
+$val: val;
+ supports \#{$query} and ($feature: $val) or (not ($feature + 3: $val + 4)) {
+  foo {a: b}
+}
+SCSS
+  end
+
+  def test_supports_bubbling
+    assert_equal <<CSS, render(<<SCSS)
+ supports (foo: bar) {
+  a {
+    b: c; }
+    @supports (baz: bang) {
+      a {
+        d: e; } } }
+CSS
+a {
+  @supports (foo: bar) {
+    b: c;
+    @supports (baz: bang) {
+      d: e;
+    }
+  }
+}
+SCSS
+  end
+
+  def test_random_directive_interpolation
+    assert_equal <<CSS, render(<<SCSS)
+ foo url(http://sass-lang.com/),
+     domain("sass-lang.com"),
+     "foobarbaz",
+     foobarbaz {
+  .foo {
+    a: b; } }
+CSS
+$domain: "sass-lang.com";
+ foo url(http://\#{$domain}/),
+     \#{domain($domain)},
+     "foo\#{'ba' + 'r'}baz",
+     foo\#{'ba' + 'r'}baz {
+  .foo {a: b}
+}
+SCSS
+  end
+
+  def test_color_interpolation_warning_in_selector
+    assert_warning(<<WARNING) {assert_equal <<CSS, render(<<SCSS)}
+WARNING on line 1, column 4 of #{filename_for_test(:scss)}:
+You probably don't mean to use the color value `blue' in interpolation here.
+It may end up represented as #0000ff, which will likely produce invalid CSS.
+Always quote color names when using them as strings (for example, "blue").
+If you really want to use the color value here, use `"" + blue'.
+WARNING
+fooblue {
+  a: b; }
+CSS
+foo\#{blue} {a: b}
+SCSS
+  end
+
+  def test_color_interpolation_warning_in_directive
+    assert_warning(<<WARNING) {assert_equal <<CSS, render(<<SCSS)}
+WARNING on line 1, column 12 of #{filename_for_test(:scss)}:
+You probably don't mean to use the color value `blue' in interpolation here.
+It may end up represented as #0000ff, which will likely produce invalid CSS.
+Always quote color names when using them as strings (for example, "blue").
+If you really want to use the color value here, use `"" + blue'.
+WARNING
+ fblthp fooblue {
+  a: b; }
+CSS
+ fblthp foo\#{blue} {a: b}
+SCSS
+  end
+
+  def test_color_interpolation_warning_in_property_name
+    assert_warning(<<WARNING) {assert_equal <<CSS, render(<<SCSS)}
+WARNING on line 1, column 8 of #{filename_for_test(:scss)}:
+You probably don't mean to use the color value `blue' in interpolation here.
+It may end up represented as #0000ff, which will likely produce invalid CSS.
+Always quote color names when using them as strings (for example, "blue").
+If you really want to use the color value here, use `"" + blue'.
+WARNING
+foo {
+  a-blue: b; }
+CSS
+foo {a-\#{blue}: b}
+SCSS
+  end
+
+  def test_no_color_interpolation_warning_in_property_value
+    assert_no_warning {assert_equal <<CSS, render(<<SCSS)}
+foo {
+  a: b-blue; }
+CSS
+foo {a: b-\#{blue}}
+SCSS
+  end
+
+  def test_no_color_interpolation_warning_for_nameless_color
+    assert_no_warning {assert_equal <<CSS, render(<<SCSS)}
+foo-#abcdef {
+  a: b; }
+CSS
+foo-\#{#abcdef} {a: b}
+SCSS
+  end
+
+  def test_nested_mixin_def
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  a: b; }
+CSS
+foo {
+  @mixin bar {a: b}
+  @include bar; }
+SCSS
+  end
+
+  def test_nested_mixin_shadow
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  c: d; }
+
+baz {
+  a: b; }
+CSS
+ mixin bar {a: b}
+
+foo {
+  @mixin bar {c: d}
+  @include bar;
+}
+
+baz { include bar}
+SCSS
+  end
+
+  def test_nested_function_def
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  a: 1; }
+
+bar {
+  b: foo(); }
+CSS
+foo {
+  @function foo() { return 1}
+  a: foo(); }
+
+bar {b: foo()}
+SCSS
+  end
+
+  def test_nested_function_shadow
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  a: 2; }
+
+baz {
+  b: 1; }
+CSS
+ function foo() { return 1}
+
+foo {
+  @function foo() { return 2}
+  a: foo();
+}
+
+baz {b: foo()}
+SCSS
+  end
+
+  ## @at-root
+
+  def test_simple_at_root
+    assert_equal <<CSS, render(<<SCSS)
+.bar {
+  a: b; }
+CSS
+.foo {
+  @at-root {
+    .bar {a: b}
+  }
+}
+SCSS
+  end
+
+  def test_at_root_with_selector
+    assert_equal <<CSS, render(<<SCSS)
+.bar {
+  a: b; }
+CSS
+.foo {
+  @at-root .bar {a: b}
+}
+SCSS
+  end
+
+  def test_at_root_in_mixin
+    assert_equal <<CSS, render(<<SCSS)
+.bar {
+  a: b; }
+CSS
+ mixin bar {
+  @at-root .bar {a: b}
+}
+
+.foo {
+  @include bar;
+}
+SCSS
+  end
+
+  def test_at_root_in_media
+    assert_equal <<CSS, render(<<SCSS)
+ media screen {
+  .bar {
+    a: b; } }
+CSS
+ media screen {
+  .foo {
+    @at-root .bar {a: b}
+  }
+}
+SCSS
+  end
+
+  def test_at_root_in_bubbled_media
+    assert_equal <<CSS, render(<<SCSS)
+ media screen {
+  .bar {
+    a: b; } }
+CSS
+.foo {
+  @media screen {
+    @at-root .bar {a: b}
+  }
+}
+SCSS
+  end
+
+  def test_at_root_in_unknown_directive
+    assert_equal <<CSS, render(<<SCSS)
+ fblthp {
+  .bar {
+    a: b; } }
+CSS
+ fblthp {
+  .foo {
+    @at-root .bar {a: b}
+  }
+}
+SCSS
+  end
+
+  def test_comments_in_at_root
+    assert_equal <<CSS, render(<<SCSS)
+/* foo */
+.bar {
+  a: b; }
+
+/* baz */
+CSS
+.foo {
+  @at-root {
+    /* foo */
+    .bar {a: b}
+    /* baz */
+  }
+}
+SCSS
+  end
+
+  def test_comments_in_at_root_in_media
+    assert_equal <<CSS, render(<<SCSS)
+ media screen {
+  /* foo */
+  .bar {
+    a: b; }
+
+  /* baz */ }
+CSS
+ media screen {
+  .foo {
+    @at-root {
+      /* foo */
+      .bar {a: b}
+      /* baz */
+    }
+  }
+}
+SCSS
+  end
+
+  def test_comments_in_at_root_in_unknown_directive
+    assert_equal <<CSS, render(<<SCSS)
+ fblthp {
+  /* foo */
+  .bar {
+    a: b; }
+
+  /* baz */ }
+CSS
+ fblthp {
+  .foo {
+    @at-root {
+      /* foo */
+      .bar {a: b}
+      /* baz */
+    }
+  }
+}
+SCSS
+  end
+
+  def test_media_directive_in_at_root
+    assert_equal <<CSS, render(<<SCSS)
+ media screen {
+  .bar {
+    a: b; } }
+CSS
+.foo {
+  @at-root {
+    @media screen {.bar {a: b}}
+  }
+}
+SCSS
+  end
+
+  def test_bubbled_media_directive_in_at_root
+    assert_equal <<CSS, render(<<SCSS)
+ media screen {
+  .bar .baz {
+    a: b; } }
+CSS
+.foo {
+  @at-root {
+    .bar {
+      @media screen {.baz {a: b}}
+    }
+  }
+}
+SCSS
+  end
+
+  def test_unknown_directive_in_at_root
+    assert_equal <<CSS, render(<<SCSS)
+ fblthp {
+  .bar {
+    a: b; } }
+CSS
+.foo {
+  @at-root {
+    @fblthp {.bar {a: b}}
+  }
+}
+SCSS
+  end
+
+  def test_at_root_in_at_root
+    assert_equal <<CSS, render(<<SCSS)
+.bar {
+  a: b; }
+CSS
+.foo {
+  @at-root {
+    @at-root .bar {a: b}
+  }
+}
+SCSS
+  end
+
+  def test_at_root_with_parent_ref
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: b; }
+CSS
+.foo {
+  @at-root & {
+    a: b;
+  }
+}
+SCSS
+  end
+
+  def test_multi_level_at_root_with_parent_ref
+    assert_equal <<CSS, render(<<SCSS)
+.foo .bar {
+  a: b; }
+CSS
+.foo {
+  @at-root & {
+    .bar {
+      @at-root & {
+        a: b;
+      }
+    }
+  }
+}
+SCSS
+  end
+
+  def test_multi_level_at_root_with_inner_parent_ref
+    assert_equal <<CSS, render(<<SCSS)
+.bar {
+  a: b; }
+CSS
+.foo {
+  @at-root .bar {
+    @at-root & {
+      a: b;
+    }
+  }
+}
+SCSS
+  end
+
+  def test_at_root_beneath_comma_selector
+    assert_equal(<<CSS, render(<<SCSS))
+.baz {
+  a: b; }
+CSS
+.foo, .bar {
+  @at-root .baz {
+    a: b;
+  }
+}
+SCSS
+  end
+
+  def test_at_root_with_parent_ref_and_class
+    assert_equal(<<CSS, render(<<SCSS))
+.foo.bar {
+  a: b; }
+CSS
+.foo {
+  @at-root &.bar {
+    a: b;
+  }
+}
+SCSS
+  end
+
+  def test_at_root_beneath_comma_selector_with_parent_ref
+    assert_equal(<<CSS, render(<<SCSS))
+.foo.baz, .bar.baz {
+  a: b; }
+CSS
+.foo, .bar {
+  @at-root &.baz {
+    a: b;
+  }
+}
+SCSS
+  end
+
+  ## @at-root (...)
+
+  def test_at_root_without_media
+    assert_equal <<CSS, render(<<SCSS)
+.foo .bar {
+  a: b; }
+CSS
+.foo {
+  @media screen {
+    @at-root (without: media) {
+      .bar {
+        a: b;
+      }
+    }
+  }
+}
+SCSS
+  end
+
+  def test_at_root_without_supports
+    assert_equal <<CSS, render(<<SCSS)
+.foo .bar {
+  a: b; }
+CSS
+.foo {
+  @supports (foo: bar) {
+    @at-root (without: supports) {
+      .bar {
+        a: b;
+      }
+    }
+  }
+}
+SCSS
+  end
+
+  def test_at_root_without_rule
+    assert_equal <<CSS, render(<<SCSS)
+ media screen {
+  .bar {
+    a: b; } }
+CSS
+.foo {
+  @media screen {
+    @at-root (without: rule) {
+      .bar {
+        a: b;
+      }
+    }
+  }
+}
+SCSS
+  end
+
+  def test_at_root_without_unknown_directive
+    assert_equal <<CSS, render(<<SCSS)
+ fblthp {}
+.foo .bar {
+  a: b; }
+CSS
+.foo {
+  @fblthp {
+    @at-root (without: fblthp) {
+      .bar {
+        a: b;
+      }
+    }
+  }
+}
+SCSS
+  end
+
+  def test_at_root_without_multiple
+    assert_equal <<CSS, render(<<SCSS)
+ supports (foo: bar) {
+  .bar {
+    a: b; } }
+CSS
+.foo {
+  @media screen {
+    @supports (foo: bar) {
+      @at-root (without: media rule) {
+        .bar {
+          a: b;
+        }
+      }
+    }
+  }
+}
+SCSS
+  end
+
+  def test_at_root_without_all
+    assert_equal <<CSS, render(<<SCSS)
+ supports (foo: bar) {
+  @fblthp {} }
+.bar {
+  a: b; }
+CSS
+.foo {
+  @supports (foo: bar) {
+    @fblthp {
+      @at-root (without: all) {
+        .bar {
+          a: b;
+        }
+      }
+    }
+  }
+}
+SCSS
+  end
+
+  def test_at_root_with_media
+    assert_equal <<CSS, render(<<SCSS)
+ media screen {
+  @fblthp {}
+  .bar {
+    a: b; } }
+CSS
+.foo {
+  @media screen {
+    @fblthp {
+      @supports (foo: bar) {
+        @at-root (with: media) {
+          .bar {
+            a: b;
+          }
+        }
+      }
+    }
+  }
+}
+SCSS
+  end
+
+  def test_at_root_with_rule
+    assert_equal <<CSS, render(<<SCSS)
+ media screen {
+  @fblthp {} }
+.foo .bar {
+  a: b; }
+CSS
+.foo {
+  @media screen {
+    @fblthp {
+      @supports (foo: bar) {
+        @at-root (with: rule) {
+          .bar {
+            a: b;
+          }
+        }
+      }
+    }
+  }
+}
+SCSS
+  end
+
+  def test_at_root_with_supports
+    assert_equal <<CSS, render(<<SCSS)
+ media screen {
+  @fblthp {} }
+ supports (foo: bar) {
+  .bar {
+    a: b; } }
+CSS
+.foo {
+  @media screen {
+    @fblthp {
+      @supports (foo: bar) {
+        @at-root (with: supports) {
+          .bar {
+            a: b;
+          }
+        }
+      }
+    }
+  }
+}
+SCSS
+  end
+
+  def test_at_root_with_unknown_directive
+    assert_equal <<CSS, render(<<SCSS)
+ media screen {
+  @fblthp {} }
+ fblthp {
+  .bar {
+    a: b; } }
+CSS
+.foo {
+  @media screen {
+    @fblthp {
+      @supports (foo: bar) {
+        @at-root (with: fblthp) {
+          .bar {
+            a: b;
+          }
+        }
+      }
+    }
+  }
+}
+SCSS
+  end
+
+  def test_at_root_with_multiple
+    assert_equal <<CSS, render(<<SCSS)
+ media screen {
+  @fblthp {}
+  .foo .bar {
+    a: b; } }
+CSS
+.foo {
+  @media screen {
+    @fblthp {
+      @supports (foo: bar) {
+        @at-root (with: media rule) {
+          .bar {
+            a: b;
+          }
+        }
+      }
+    }
+  }
+}
+SCSS
+  end
+
+  def test_at_root_with_all
+    assert_equal <<CSS, render(<<SCSS)
+ media screen {
+  @fblthp {
+    @supports (foo: bar) {
+      .foo .bar {
+        a: b; } } } }
+CSS
+.foo {
+  @media screen {
+    @fblthp {
+      @supports (foo: bar) {
+        @at-root (with: all) {
+          .bar {
+            a: b;
+          }
+        }
+      }
+    }
+  }
+}
+SCSS
+  end
+
+  def test_at_root_dynamic_values
+    assert_equal <<CSS, render(<<SCSS)
+ media screen {
+  .bar {
+    a: b; } }
+CSS
+$key: with;
+$value: media;
+.foo {
+  @media screen {
+    @at-root ($key: $value) {
+      .bar {
+        a: b;
+      }
+    }
+  }
+}
+SCSS
+  end
+
+  def test_at_root_interpolated_query
+    assert_equal <<CSS, render(<<SCSS)
+ media screen {
+  .bar {
+    a: b; } }
+CSS
+.foo {
+  @media screen {
+    @at-root (\#{"with: media"}) {
+      .bar {
+        a: b;
+      }
+    }
+  }
+}
+SCSS
+  end
+
+  def test_at_root_plus_extend
+    assert_equal <<CSS, render(<<SCSS)
+.foo .bar {
+  a: b; }
+CSS
+%base {
+  a: b;
+}
+
+.foo {
+  @media screen {
+    @at-root (without: media) {
+      .bar {
+        @extend %base;
+      }
+    }
+  }
+}
+SCSS
+  end
+
+  def test_at_root_without_keyframes_in_keyframe_rule
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: b; }
+CSS
+ keyframes identifier {
+  0% {
+    @at-root (without: keyframes) {
+      .foo {a: b}
+    }
+  }
+}
+SCSS
+  end
+
+  def test_at_root_without_rule_in_keyframe_rule
+    assert_equal <<CSS, render(<<SCSS)
+ keyframes identifier {
+  0% {
+    a: b; } }
+CSS
+ keyframes identifier {
+  0% {
+    @at-root (without: rule) {a: b}
+  }
+}
+SCSS
+  end
+
+  ## Selector Script
+
+  def test_selector_script
+    assert_equal(<<CSS, render(<<SCSS))
+.foo .bar {
+  content: ".foo .bar"; }
+CSS
+.foo .bar {
+  content: "\#{&}";
+}
+SCSS
+  end
+
+  def test_nested_selector_script
+    assert_equal(<<CSS, render(<<SCSS))
+.foo .bar {
+  content: ".foo .bar"; }
+CSS
+.foo {
+  .bar {
+    content: "\#{&}";
+  }
+}
+SCSS
+  end
+
+  def test_nested_selector_script_with_outer_comma_selector
+    assert_equal(<<CSS, render(<<SCSS))
+.foo .baz, .bar .baz {
+  content: ".foo .baz, .bar .baz"; }
+CSS
+.foo, .bar {
+  .baz {
+    content: "\#{&}";
+  }
+}
+SCSS
+  end
+
+  def test_nested_selector_script_with_inner_comma_selector
+    assert_equal(<<CSS, render(<<SCSS))
+.foo .bar, .foo .baz {
+  content: ".foo .bar, .foo .baz"; }
+CSS
+.foo {
+  .bar, .baz {
+    content: "\#{&}";
+  }
+}
+SCSS
+  end
+
+  def test_selector_script_through_mixin
+    assert_equal(<<CSS, render(<<SCSS))
+.foo {
+  content: ".foo"; }
+CSS
+ mixin mixin {
+  content: "\#{&}";
+}
+
+.foo {
+  @include mixin;
+}
+SCSS
+  end
+
+  def test_selector_script_through_content
+    assert_equal(<<CSS, render(<<SCSS))
+.foo {
+  content: ".foo"; }
+CSS
+ mixin mixin {
+  @content;
+}
+
+.foo {
+  @include mixin {
+    content: "\#{&}";
+  }
+}
+SCSS
+  end
+
+  def test_selector_script_through_function
+    assert_equal(<<CSS, render(<<SCSS))
+.foo {
+  content: ".foo"; }
+CSS
+ function fn() {
+  @return "\#{&}";
+}
+
+.foo {
+  content: fn();
+}
+SCSS
+  end
+
+  def test_selector_script_through_media
+    assert_equal(<<CSS, render(<<SCSS))
+.foo {
+  content: "outer"; }
+  @media screen {
+    .foo .bar {
+      content: ".foo .bar"; } }
+CSS
+.foo {
+  content: "outer";
+  @media screen {
+    .bar {
+      content: "\#{&}";
+    }
+  }
+}
+SCSS
+  end
+
+  def test_selector_script_save_and_reuse
+    assert_equal(<<CSS, render(<<SCSS))
+.bar {
+  content: ".foo"; }
+CSS
+$var: null;
+.foo {
+  $var: & !global;
+}
+
+.bar {
+  content: "\#{$var}";
+}
+SCSS
+  end
+
+  def test_selector_script_with_at_root
+    assert_equal(<<CSS, render(<<SCSS))
+.foo-bar {
+  a: b; }
+CSS
+.foo {
+  @at-root \#{&}-bar {
+    a: b;
+  }
+}
+SCSS
+  end
+
+  def test_multi_level_at_root_with_inner_selector_script
+    assert_equal <<CSS, render(<<SCSS)
+.bar {
+  a: b; }
+CSS
+.foo {
+  @at-root .bar {
+    @at-root \#{&} {
+      a: b;
+    }
+  }
+}
+SCSS
+  end
+
+  def test_at_root_with_at_root_through_mixin
+    assert_equal(<<CSS, render(<<SCSS))
+.bar-baz {
+  a: b; }
+CSS
+ mixin foo {
+  .bar {
+    @at-root \#{&}-baz {
+      a: b;
+    }
+  }
+}
+
+ include foo;
+SCSS
+  end
+
+  # See https://github.com/sass/sass/issues/1294
+  def test_extend_top_leveled_by_at_root
+    render(<<SCSS)
+.span-10 {
+  @at-root (without: all) {
+    @extend %column;
+  }
+}
+SCSS
+
+    assert(false, "Expected syntax error")
+  rescue Sass::SyntaxError => e
+    assert_equal "Extend directives may only be used within rules.", e.message
+    assert_equal 3, e.sass_line
+  end
+
+  def test_at_root_doesnt_always_break_blocks
+    assert_equal <<CSS, render(<<SCSS)
+.foo {
+  a: b; }
+
+ media screen {
+  .foo {
+    c: d; }
+  .bar {
+    e: f; } }
+CSS
+%base {
+  a: b;
+}
+
+ media screen {
+  .foo {
+    c: d;
+    @at-root (without: media) {
+      @extend %base;
+    }
+  }
+
+  .bar {e: f}
+}
+SCSS
+  end
+
+  ## Errors
+
+  def test_keyframes_rule_outside_of_keyframes
+    render <<SCSS
+0% {
+  top: 0; }
+SCSS
+    assert(false, "Expected syntax error")
+  rescue Sass::SyntaxError => e
+    assert_equal 'Invalid CSS after "": expected selector, was "0%"', e.message
+    assert_equal 1, e.sass_line
+  end
+
+  def test_selector_rule_in_keyframes
+    render <<SCSS
+ keyframes identifier {
+  .foo {
+    top: 0; } }
+SCSS
+    assert(false, "Expected syntax error")
+  rescue Sass::SyntaxError => e
+    assert_equal 'Invalid CSS after "": expected keyframes selector (e.g. 10%), was ".foo"', e.message
+    assert_equal 2, e.sass_line
+  end
+
+  def test_nested_mixin_def_is_scoped
+    render <<SCSS
+foo {
+  @mixin bar {a: b}}
+bar { include bar}
+SCSS
+    assert(false, "Expected syntax error")
+  rescue Sass::SyntaxError => e
+    assert_equal "Undefined mixin 'bar'.", e.message
+    assert_equal 3, e.sass_line
+  end
+
+  def test_rules_beneath_properties
+    render <<SCSS
+foo {
+  bar: {
+    baz {
+      bang: bop }}}
+SCSS
+    assert(false, "Expected syntax error")
+  rescue Sass::SyntaxError => e
+    assert_equal 'Illegal nesting: Only properties may be nested beneath properties.', e.message
+    assert_equal 3, e.sass_line
+  end
+
+  def test_uses_property_exception_with_star_hack
+    render <<SCSS
+foo {
+  *bar:baz [fail]; }
+SCSS
+    assert(false, "Expected syntax error")
+  rescue Sass::SyntaxError => e
+    assert_equal 'Invalid CSS after "  *bar:baz ": expected ";", was "[fail]; }"', e.message
+    assert_equal 2, e.sass_line
+  end
+
+  def test_uses_property_exception_with_colon_hack
+    render <<SCSS
+foo {
+  :bar:baz [fail]; }
+SCSS
+    assert(false, "Expected syntax error")
+  rescue Sass::SyntaxError => e
+    assert_equal 'Invalid CSS after "  :bar:baz ": expected ";", was "[fail]; }"', e.message
+    assert_equal 2, e.sass_line
+  end
+
+  def test_uses_rule_exception_with_dot_hack
+    render <<SCSS
+foo {
+  .bar:baz <fail>; }
+SCSS
+    assert(false, "Expected syntax error")
+  rescue Sass::SyntaxError => e
+    assert_equal 'Invalid CSS after "  .bar:baz <fail>": expected expression (e.g. 1px, bold), was "; }"', 
e.message
+    assert_equal 2, e.sass_line
+  end
+
+  def test_uses_property_exception_with_space_after_name
+    render <<SCSS
+foo {
+  bar: baz [fail]; }
+SCSS
+    assert(false, "Expected syntax error")
+  rescue Sass::SyntaxError => e
+    assert_equal 'Invalid CSS after "  bar: baz ": expected ";", was "[fail]; }"', e.message
+    assert_equal 2, e.sass_line
+  end
+
+  def test_uses_property_exception_with_non_identifier_after_name
+    render <<SCSS
+foo {
+  bar:1px [fail]; }
+SCSS
+    assert(false, "Expected syntax error")
+  rescue Sass::SyntaxError => e
+    assert_equal 'Invalid CSS after "  bar:1px ": expected ";", was "[fail]; }"', e.message
+    assert_equal 2, e.sass_line
+  end
+
+  def test_uses_property_exception_when_followed_by_open_bracket
+    render <<SCSS
+foo {
+  bar:{baz: .fail} }
+SCSS
+    assert(false, "Expected syntax error")
+  rescue Sass::SyntaxError => e
+    assert_equal 'Invalid CSS after "  bar:{baz: ": expected expression (e.g. 1px, bold), was ".fail} }"', 
e.message
+    assert_equal 2, e.sass_line
+  end
+
+  def test_script_error
+    render <<SCSS
+foo {
+  bar: "baz" * * }
+SCSS
+    assert(false, "Expected syntax error")
+  rescue Sass::SyntaxError => e
+    assert_equal 'Invalid CSS after "  bar: "baz" * ": expected expression (e.g. 1px, bold), was "* }"', 
e.message
+    assert_equal 2, e.sass_line
+  end
+
+  def test_multiline_script_syntax_error
+    render <<SCSS
+foo {
+  bar:
+    "baz" * * }
+SCSS
+    assert(false, "Expected syntax error")
+  rescue Sass::SyntaxError => e
+    assert_equal 'Invalid CSS after "    "baz" * ": expected expression (e.g. 1px, bold), was "* }"', 
e.message
+    assert_equal 3, e.sass_line
+  end
+
+  def test_multiline_script_runtime_error
+    render <<SCSS
+foo {
+  bar: "baz" +
+    "bar" +
+    $bang }
+SCSS
+    assert(false, "Expected syntax error")
+  rescue Sass::SyntaxError => e
+    assert_equal "Undefined variable: \"$bang\".", e.message
+    assert_equal 4, e.sass_line
+  end
+
+  def test_post_multiline_script_runtime_error
+    render <<SCSS
+foo {
+  bar: "baz" +
+    "bar" +
+    "baz";
+  bip: $bop; }
+SCSS
+    assert(false, "Expected syntax error")
+  rescue Sass::SyntaxError => e
+    assert_equal "Undefined variable: \"$bop\".", e.message
+    assert_equal 5, e.sass_line
+  end
+
+  def test_multiline_property_runtime_error
+    render <<SCSS
+foo {
+  bar: baz
+    bar
+    \#{$bang} }
+SCSS
+    assert(false, "Expected syntax error")
+  rescue Sass::SyntaxError => e
+    assert_equal "Undefined variable: \"$bang\".", e.message
+    assert_equal 4, e.sass_line
+  end
+
+  def test_post_resolution_selector_error
+    render "\n\nfoo \#{\") bar\"} {a: b}"
+    assert(false, "Expected syntax error")
+  rescue Sass::SyntaxError => e
+    assert_equal 'Invalid CSS after "foo ": expected selector, was ") bar"', e.message
+    assert_equal 3, e.sass_line
+  end
+
+  def test_parent_in_mid_selector_error
+    assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
+Invalid CSS after ".foo": expected "{", was "&.bar"
+
+"&.bar" may only be used at the beginning of a compound selector.
+MESSAGE
+flim {
+  .foo&.bar {a: b}
+}
+SCSS
+  end
+
+  def test_parent_after_selector_error
+    assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
+Invalid CSS after ".foo.bar": expected "{", was "&"
+
+"&" may only be used at the beginning of a compound selector.
+MESSAGE
+flim {
+  .foo.bar& {a: b}
+}
+SCSS
+  end
+
+  def test_double_parent_selector_error
+    assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
+Invalid CSS after "&": expected "{", was "&"
+
+"&" may only be used at the beginning of a compound selector.
+MESSAGE
+flim {
+  && {a: b}
+}
+SCSS
+  end
+
+  def test_no_lonely_else
+    assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
+Invalid CSS: @else must come after @if
+MESSAGE
+ else {foo: bar}
+SCSS
+  end
+
+  def test_failed_parent_selector_with_suffix
+    assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
+Invalid parent selector for "&-bar": "*"
+MESSAGE
+* {
+  &-bar {a: b}
+}
+SCSS
+
+    assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
+Invalid parent selector for "&-bar": "[foo=bar]"
+MESSAGE
+[foo=bar] {
+  &-bar {a: b}
+}
+SCSS
+
+    assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
+Invalid parent selector for "&-bar": "::nth-child(2n+1)"
+MESSAGE
+::nth-child(2n+1) {
+  &-bar {a: b}
+}
+SCSS
+
+    assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
+Invalid parent selector for "&-bar": ":not(.foo)"
+MESSAGE
+:not(.foo) {
+  &-bar {a: b}
+}
+SCSS
+
+    assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
+Invalid parent selector for "&-bar": ".foo +"
+MESSAGE
+.foo + {
+  &-bar {a: b}
+}
+SCSS
+  end
+
+  def test_empty_media_query_error
+    assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
+Invalid CSS after "": expected media query list, was ""
+MESSAGE
+ media \#{""} {
+  foo {a: b}
+}
+SCSS
+  end
+
+  def test_newline_in_property_value
+    assert_equal(<<CSS, render(<<SCSS))
+.foo {
+  bar: "bazbang"; }
+CSS
+.foo {
+  $var: "baz\\
+bang";
+  bar: $var;
+}
+SCSS
+  end
+
+  def test_raw_newline_warning
+    assert_warning(<<MESSAGE.rstrip) {assert_equal(<<CSS, render(<<SCSS))}
+DEPRECATION WARNING on line 2, column 9 of #{filename_for_test :scss}:
+Unescaped multiline strings are deprecated and will be removed in a future version of Sass.
+To include a newline in a string, use "\\a" or "\\a " as in CSS.
+MESSAGE
+.foo {
+  bar: "baz\\a bang"; }
+CSS
+.foo {
+  $var: "baz
+bang";
+  bar: $var;
+}
+SCSS
+  end
+
+  # Regression
+
+  def test_escape_in_selector
+    assert_equal(<<CSS, render(".\\!foo {a: b}"))
+.\\!foo {
+  a: b; }
+CSS
+  end
+
+  def test_for_directive_with_float_bounds
+    assert_equal(<<CSS, render(<<SCSS))
+.a {
+  b: 0;
+  b: 1;
+  b: 2;
+  b: 3;
+  b: 4;
+  b: 5; }
+CSS
+.a {
+  @for $i from 0.0 through 5.0 {b: $i}
+}
+SCSS
+
+    assert_raise_message(Sass::SyntaxError, "0.5 is not an integer.") {render(<<SCSS)}
+.a {
+  @for $i from 0.5 through 5.0 {b: $i}
+}
+SCSS
+
+    assert_raise_message(Sass::SyntaxError, "5.5 is not an integer.") {render(<<SCSS)}
+.a {
+  @for $i from 0.0 through 5.5 {b: $i}
+}
+SCSS
+  end
+
+  def test_parent_selector_in_function_pseudo_selector
+    assert_equal <<CSS, render(<<SCSS)
+.bar:not(.foo) {
+  a: b; }
+
+.qux:nth-child(2n of .baz .bang) {
+  c: d; }
+CSS
+.foo {
+  .bar:not(&) {a: b}
+}
+
+.baz .bang {
+  .qux:nth-child(2n of &) {c: d}
+}
+SCSS
+  end
+
+  def test_attribute_selector_in_selector_pseudoclass
+    # Even though this is plain CSS, it only failed when given to the SCSS
+    # parser.
+    assert_equal(<<CSS, render(<<SCSS))
+[href^='http://'] {
+  color: red; }
+CSS
+[href^='http://'] {
+  color: red;
+}
+SCSS
+  end
+
+  def test_top_level_unknown_directive_in_at_root
+    assert_equal(<<CSS, render(<<SCSS))
+ fblthp {
+  a: b; }
+CSS
+ at-root {
+  @fblthp {a: b}
+}
+SCSS
+  end
+
+  def test_parent_ref_with_newline
+    assert_equal(<<CSS, render(<<SCSS))
+a.c
+, b.c {
+  x: y; }
+CSS
+a
+, b {&.c {x: y}}
+SCSS
+  end
+
+  def test_parent_ref_in_nested_at_root
+    assert_equal(<<CSS, render(<<SCSS))
+#test {
+  border: 0; }
+  #test:hover {
+    display: none; }
+CSS
+a {
+  @at-root #test {
+    border: 0;
+    &:hover{
+      display: none;
+    }
+  }
+}
+SCSS
+  end
+
+  def test_loud_comment_in_compressed_mode
+    assert_equal(<<CSS, render(<<SCSS))
+/*! foo */
+CSS
+/*! foo */
+SCSS
+  end
+
+  def test_parsing_decimals_followed_by_comments_doesnt_take_forever
+    assert_equal(<<CSS, render(<<SCSS))
+.foo {
+  padding: 4.21053% 4.21053% 5.63158%; }
+CSS
+.foo {
+  padding: 4.21052631578947% 4.21052631578947% 5.631578947368421% /**/
+}
+SCSS
+  end
+
+  def test_parsing_many_numbers_doesnt_take_forever
+    values = ["80% 90%"] * 1000
+    assert_equal(<<CSS, render(<<SCSS))
+.foo {
+  padding: #{values.join(', ')}; }
+CSS
+.foo {
+  padding: #{values.join(', ')};
+}
+SCSS
+  end
+
+  def test_import_comments_in_imports
+    assert_equal(<<CSS, render(<<SCSS))
+ import url(foo.css);
+ import url(bar.css);
+ import url(baz.css);
+CSS
+ import "foo.css", // this is a comment
+        "bar.css", /* this is another comment */
+        "baz.css"; // this is a third comment
+SCSS
+  end
+
+  def test_reference_combinator_with_parent_ref
+    assert_equal <<CSS, render(<<SCSS)
+a /foo/ b {
+  c: d; }
+CSS
+a {& /foo/ b {c: d}}
+SCSS
+  end
+
+  def test_newline_selector_rendered_multiple_times
+    assert_equal <<CSS, render(<<SCSS)
+form input,
+form select {
+  color: white; }
+
+form input,
+form select {
+  color: white; }
+CSS
+ for $i from 1 through 2 {
+  form {
+    input,
+    select {
+      color: white;
+    }
+  }
+}
+SCSS
+  end
+
+  def test_prop_name_interpolation_after_hyphen
+    assert_equal <<CSS, render(<<SCSS)
+a {
+  -foo-bar: b; }
+CSS
+a { -\#{"foo"}-bar: b; }
+SCSS
+  end
+
+  def test_star_plus_and_parent
+    assert_equal <<CSS, render(<<SCSS)
+* + html foo {
+  a: b; }
+CSS
+foo {*+html & {a: b}}
+SCSS
+  end
+
+  def test_weird_added_space
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  bar: -moz-bip; }
+CSS
+$value : bip;
+
+foo {
+  bar: -moz-\#{$value};
+}
+SCSS
+  end
+
+  def test_interpolation_with_bracket_on_next_line
+    assert_equal <<CSS, render(<<SCSS)
+a.foo b {
+  color: red; }
+CSS
+a.\#{"foo"} b
+{color: red}
+SCSS
+  end
+
+  def test_extra_comma_in_mixin_arglist_error
+    assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
+Invalid CSS after "...clude foo(bar, ": expected mixin argument, was ");"
+MESSAGE
+ mixin foo($a1, $a2) {
+  baz: $a1 $a2;
+}
+
+.bar {
+  @include foo(bar, );
+}
+SCSS
+  end
+
+  def test_interpolation
+    assert_equal <<CSS, render(<<SCSS)
+ul li#foo a span.label {
+  foo: bar; }
+CSS
+$bar : "#foo";
+ul li\#{$bar} a span.label { foo: bar; }
+SCSS
+  end
+
+  def test_mixin_with_keyword_args
+    assert_equal <<CSS, render(<<SCSS)
+.mixed {
+  required: foo;
+  arg1: default-val1;
+  arg2: non-default-val2; }
+CSS
+ mixin a-mixin($required, $arg1: default-val1, $arg2: default-val2) {
+  required: $required;
+  arg1: $arg1;
+  arg2: $arg2;
+}
+.mixed { @include a-mixin(foo, $arg2: non-default-val2); }
+SCSS
+  end
+
+  def test_passing_required_args_as_a_keyword_arg
+    assert_equal <<CSS, render(<<SCSS)
+.mixed {
+  required: foo;
+  arg1: default-val1;
+  arg2: default-val2; }
+CSS
+ mixin a-mixin($required, $arg1: default-val1, $arg2: default-val2) {
+  required: $required;
+  arg1: $arg1;
+  arg2: $arg2; }
+.mixed { @include a-mixin($required: foo); }
+SCSS
+  end
+
+  def test_passing_all_as_keyword_args_in_opposite_order
+    assert_equal <<CSS, render(<<SCSS)
+.mixed {
+  required: foo;
+  arg1: non-default-val1;
+  arg2: non-default-val2; }
+CSS
+ mixin a-mixin($required, $arg1: default-val1, $arg2: default-val2) {
+  required: $required;
+  arg1: $arg1;
+  arg2: $arg2; }
+.mixed { @include a-mixin($arg2: non-default-val2, $arg1: non-default-val1, $required: foo); }
+SCSS
+  end
+
+  def test_keyword_args_in_functions
+    assert_equal <<CSS, render(<<SCSS)
+.keyed {
+  color: rgba(170, 119, 204, 0.4); }
+CSS
+.keyed { color: rgba($color: #a7c, $alpha: 0.4) }
+SCSS
+  end
+
+  def test_unknown_keyword_arg_raises_error
+    assert_raise_message(Sass::SyntaxError, "Mixin a doesn't have an argument named $c.") {render <<SCSS}
+ mixin a($b: 1) { a: $b; }
+div { @include a(1, $c: 3); }
+SCSS
+  end
+
+
+  def test_newlines_removed_from_selectors_when_compressed
+    assert_equal <<CSS, render(<<SCSS, :style => :compressed)
+z a,z b{display:block}
+CSS
+a
+, b {
+  z & {
+    display: block;
+  }
+}
+SCSS
+  end
+
+  def test_if_error_line
+    assert_raise_line(2) {render(<<SCSS)}
+ if true {foo: bar}
+}
+SCSS
+  end
+
+  def test_multiline_var
+    assert_equal <<CSS, render(<<SCSS)
+foo {
+  a: 3;
+  b: false;
+  c: a b c; }
+CSS
+foo {
+  $var1: 1 +
+    2;
+  $var2: true and
+    false;
+  $var3: a b
+    c;
+  a: $var1;
+  b: $var2;
+  c: $var3; }
+SCSS
+  end
+
+  def test_mixin_content
+    assert_equal <<CSS, render(<<SASS)
+.parent {
+  background-color: red;
+  border-color: red; }
+  .parent .child {
+    background-color: yellow;
+    color: blue;
+    border-color: yellow; }
+CSS
+$color: blue;
+ mixin context($class, $color: red) {
+  .\#{$class} {
+    background-color: $color;
+    @content;
+    border-color: $color;
+  }
+}
+ include context(parent) {
+  @include context(child, $color: yellow) {
+    color: $color;
+  }
+}
+SASS
+  end
+
+  def test_empty_content
+    assert_equal <<CSS, render(<<SCSS)
+a {
+  b: c; }
+CSS
+ mixin foo { @content }
+a { b: c; @include foo {} }
+SCSS
+  end
+
+  def test_options_passed_to_script
+    assert_equal <<CSS, render(<<SCSS, :style => :compressed)
+foo{color:#000}
+CSS
+foo {color: darken(black, 10%)}
+SCSS
+  end
+
+  # ref: https://github.com/nex3/sass/issues/104
+  def test_no_buffer_overflow
+    template = render <<SCSS
+.aaa {
+  background-color: white;
+}
+.aaa .aaa .aaa {
+  background-color: black;
+}
+.bbb {
+  @extend .aaa;
+}
+.xxx {
+  @extend .bbb;
+}
+.yyy {
+  @extend .bbb;
+}
+.zzz {
+  @extend .bbb;
+}
+SCSS
+    Sass::SCSS::Parser.new(template, "test.scss", nil).parse
+  end
+
+  def test_extend_in_media_in_rule
+    assert_equal(<<CSS, render(<<SCSS))
+ media screen {
+  .foo {
+    a: b; } }
+CSS
+.foo {
+  @media screen {
+    @extend %bar;
+  }
+}
+
+ media screen {
+  %bar {
+    a: b;
+  }
+}
+SCSS
+  end
+end
diff --git a/backends/css/gems/sass-3.2.12/test/sass/scss/test_helper.rb 
b/backends/css/gems/sass-3.4.9/test/sass/scss/test_helper.rb
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/scss/test_helper.rb
rename to backends/css/gems/sass-3.4.9/test/sass/scss/test_helper.rb
diff --git a/backends/css/gems/sass-3.4.9/test/sass/source_map_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/source_map_test.rb
new file mode 100755
index 0000000..00424bf
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/source_map_test.rb
@@ -0,0 +1,977 @@
+#!/usr/bin/env ruby
+# -*- coding: utf-8 -*-
+require File.dirname(__FILE__) + '/../test_helper'
+require File.dirname(__FILE__) + '/test_helper'
+
+class SourcemapTest < MiniTest::Test
+  def test_to_json_requires_args
+    _, sourcemap = render_with_sourcemap('')
+    assert_raises(ArgumentError) {sourcemap.to_json({})}
+    assert_raises(ArgumentError) {sourcemap.to_json({:css_path => 'foo'})}
+    assert_raises(ArgumentError) {sourcemap.to_json({:sourcemap_path => 'foo'})}
+  end
+
+  def test_simple_mapping_scss
+    assert_parses_with_sourcemap <<SCSS, <<CSS, <<JSON
+a {
+  foo: bar;
+/* SOME COMMENT */
+  font-size: 12px;
+}
+SCSS
+a {
+  foo: bar;
+  /* SOME COMMENT */
+  font-size: 12px; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+{
+"version": 3,
+"mappings": "AAAA,CAAE;EACA,GAAG,EAAE,GAAG;;EAER,SAAS,EAAE,IAAI",
+"sources": ["test_simple_mapping_scss_inline.scss"],
+"names": [],
+"file": "test.css"
+}
+JSON
+  end
+
+  def test_simple_mapping_sass
+    assert_parses_with_sourcemap <<SASS, <<CSS, <<JSON, :syntax => :sass
+a
+  foo: bar
+  /* SOME COMMENT */
+  :font-size 12px
+SASS
+a {
+  foo: bar;
+  /* SOME COMMENT */
+  font-size: 12px; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+{
+"version": 3,
+"mappings": "AAAA,CAAC;EACC,GAAG,EAAE,GAAG;;EAEP,SAAS,EAAC,IAAI",
+"sources": ["test_simple_mapping_sass_inline.sass"],
+"names": [],
+"file": "test.css"
+}
+JSON
+  end
+
+  def test_simple_mapping_with_file_uris
+    uri = Sass::Util.file_uri_from_path(Sass::Util.absolute_path(filename_for_test(:scss)))
+    assert_parses_with_sourcemap <<SCSS, <<CSS, <<JSON, :sourcemap => :file
+a {
+  foo: bar;
+/* SOME COMMENT */
+  font-size: 12px;
+}
+SCSS
+a {
+  foo: bar;
+  /* SOME COMMENT */
+  font-size: 12px; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+{
+"version": 3,
+"mappings": "AAAA,CAAE;EACA,GAAG,EAAE,GAAG;;EAER,SAAS,EAAE,IAAI",
+"sources": ["#{uri}"],
+"names": [],
+"file": "test.css"
+}
+JSON
+  end
+
+  def test_mapping_with_directory_scss
+    options = {:filename => "scss/style.scss", :output => "css/style.css"}
+    assert_parses_with_sourcemap <<SCSS, <<CSS, <<JSON, options
+a {
+  foo: bar;
+/* SOME COMMENT */
+  font-size: 12px;
+}
+SCSS
+a {
+  foo: bar;
+  /* SOME COMMENT */
+  font-size: 12px; }
+
+/*# sourceMappingURL=style.css.map */
+CSS
+{
+"version": 3,
+"mappings": "AAAA,CAAE;EACA,GAAG,EAAE,GAAG;;EAER,SAAS,EAAE,IAAI",
+"sources": ["../scss/style.scss"],
+"names": [],
+"file": "style.css"
+}
+JSON
+  end
+
+  def test_mapping_with_directory_sass
+    options = {:filename => "sass/style.sass", :output => "css/style.css", :syntax => :sass}
+    assert_parses_with_sourcemap <<SASS, <<CSS, <<JSON, options
+a
+  foo: bar
+  /* SOME COMMENT */
+  :font-size 12px
+SASS
+a {
+  foo: bar;
+  /* SOME COMMENT */
+  font-size: 12px; }
+
+/*# sourceMappingURL=style.css.map */
+CSS
+{
+"version": 3,
+"mappings": "AAAA,CAAC;EACC,GAAG,EAAE,GAAG;;EAEP,SAAS,EAAC,IAAI",
+"sources": ["../sass/style.sass"],
+"names": [],
+"file": "style.css"
+}
+JSON
+  end
+
+  unless Sass::Util.ruby1_8?
+    def test_simple_charset_mapping_scss
+      assert_parses_with_sourcemap <<SCSS, <<CSS, <<JSON
+a {
+  fóó: bár;
+}
+SCSS
+ charset "UTF-8";
+a {
+  fóó: bár; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+{
+"version": 3,
+"mappings": ";AAAA,CAAE;EACA,GAAG,EAAE,GAAG",
+"sources": ["test_simple_charset_mapping_scss_inline.scss"],
+"names": [],
+"file": "test.css"
+}
+JSON
+    end
+
+    def test_simple_charset_mapping_sass
+      assert_parses_with_sourcemap <<SASS, <<CSS, <<JSON, :syntax => :sass
+a
+  fóó: bár
+SASS
+ charset "UTF-8";
+a {
+  fóó: bár; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+{
+"version": 3,
+"mappings": ";AAAA,CAAC;EACC,GAAG,EAAE,GAAG",
+"sources": ["test_simple_charset_mapping_sass_inline.sass"],
+"names": [],
+"file": "test.css"
+}
+JSON
+    end
+
+    def test_different_charset_than_encoding_scss
+      assert_parses_with_sourcemap(<<SCSS.force_encoding("IBM866"), <<CSS, <<JSON)
+ charset "IBM866";
+f\x86\x86 {
+  \x86: b;
+}
+SCSS
+ charset "UTF-8";
+fЖЖ {
+  Ж: b; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+{
+"version": 3,
+"mappings": ";AACA,GAAI;EACF,CAAC,EAAE,CAAC",
+"sources": ["test_different_charset_than_encoding_scss_inline.scss"],
+"names": [],
+"file": "test.css"
+}
+JSON
+    end
+
+    def test_different_charset_than_encoding_sass
+      assert_parses_with_sourcemap(<<SASS.force_encoding("IBM866"), <<CSS, <<JSON, :syntax => :sass)
+ charset "IBM866"
+f\x86\x86
+  \x86: b
+SASS
+ charset "UTF-8";
+fЖЖ {
+  Ж: b; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+{
+"version": 3,
+"mappings": ";AACA,GAAG;EACD,CAAC,EAAE,CAAC",
+"sources": ["test_different_charset_than_encoding_sass_inline.sass"],
+"names": [],
+"file": "test.css"
+}
+JSON
+    end
+  end
+
+  def test_import_sourcemap_scss
+    assert_parses_with_mapping <<'SCSS', <<'CSS'
+ import {{1}}url(foo){{/1}},{{2}}url(moo)   {{/2}},       {{3}}url(bar) {{/3}};
+ import {{4}}url(baz) screen print{{/4}};
+SCSS
+{{1}} import url(foo){{/1}};
+{{2}} import url(moo){{/2}};
+{{3}} import url(bar){{/3}};
+{{4}} import url(baz) screen print{{/4}};
+
+/*# sourceMappingURL=test.css.map */
+CSS
+  end
+
+  def test_import_sourcemap_sass
+    assert_parses_with_mapping <<'SASS', <<'CSS', :syntax => :sass
+ import {{1}}foo.css{{/1}},{{2}}moo.css{{/2}},      {{3}}bar.css{{/3}}
+ import {{4}}url(baz.css){{/4}}
+ import {{5}}url(qux.css) screen print{{/5}}
+SASS
+{{1}} import url(foo.css){{/1}};
+{{2}} import url(moo.css){{/2}};
+{{3}} import url(bar.css){{/3}};
+{{4}} import url(baz.css){{/4}};
+{{5}} import url(qux.css) screen print{{/5}};
+
+/*# sourceMappingURL=test.css.map */
+CSS
+  end
+
+  def test_media_sourcemap_scss
+    assert_parses_with_mapping <<'SCSS', <<'CSS'
+{{1}} media screen, tv  {{/1}}{
+  {{2}}body {{/2}}{
+    {{3}}max-width{{/3}}: {{4}}1070px{{/4}};
+  }
+}
+SCSS
+{{1}} media screen, tv{{/1}} {
+  {{2}}body{{/2}} {
+    {{3}}max-width{{/3}}: {{4}}1070px{{/4}}; } }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+  end
+
+  def test_media_sourcemap_sass
+    assert_parses_with_mapping <<'SASS', <<'CSS', :syntax => :sass
+{{1}} media screen, tv{{/1}}
+  {{2}}body{{/2}}
+    {{3}}max-width{{/3}}: {{4}}1070px{{/4}}
+SASS
+{{1}} media screen, tv{{/1}} {
+  {{2}}body{{/2}} {
+    {{3}}max-width{{/3}}: {{4}}1070px{{/4}}; } }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+  end
+
+  def test_interpolation_and_vars_sourcemap_scss
+    assert_parses_with_mapping <<'SCSS', <<'CSS'
+$te: "te";
+$teal: {{5}}teal{{/5}};
+{{1}}p {{/1}}{
+  {{2}}con#{$te}nt{{/2}}: {{3}}"I a#{$te} #{5 + 10} pies!"{{/3}};
+  {{4}}color{{/4}}: $teal;
+}
+
+$name: foo;
+$attr: border;
+{{6}}p.#{$name} {{/6}}{
+  {{7}}#{$attr}-color{{/7}}: {{8}}blue{{/8}};
+  $font-size: 12px;
+  $line-height: 30px;
+  {{9}}font{{/9}}: {{10}}#{$font-size}/#{$line-height}{{/10}};
+}
+SCSS
+{{1}}p{{/1}} {
+  {{2}}content{{/2}}: {{3}}"I ate 15 pies!"{{/3}};
+  {{4}}color{{/4}}: {{5}}teal{{/5}}; }
+
+{{6}}p.foo{{/6}} {
+  {{7}}border-color{{/7}}: {{8}}blue{{/8}};
+  {{9}}font{{/9}}: {{10}}12px/30px{{/10}}; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+  end
+
+  def test_interpolation_and_vars_sourcemap_sass
+    assert_parses_with_mapping <<'SASS', <<'CSS', :syntax => :sass
+$te: "te"
+$teal: {{5}}teal{{/5}}
+{{1}}p{{/1}}
+  {{2}}con#{$te}nt{{/2}}: {{3}}"I a#{$te} #{5 + 10} pies!"{{/3}}
+  {{4}}color{{/4}}: $teal
+
+$name: foo
+$attr: border
+{{6}}p.#{$name}{{/6}}
+  {{7}}#{$attr}-color{{/7}}: {{8}}blue{{/8}}
+  $font-size: 12px
+  $line-height: 30px
+  {{9}}font{{/9}}: {{10}}#{$font-size}/#{$line-height}{{/10}}
+SASS
+{{1}}p{{/1}} {
+  {{2}}content{{/2}}: {{3}}"I ate 15 pies!"{{/3}};
+  {{4}}color{{/4}}: {{5}}teal{{/5}}; }
+
+{{6}}p.foo{{/6}} {
+  {{7}}border-color{{/7}}: {{8}}blue{{/8}};
+  {{9}}font{{/9}}: {{10}}12px/30px{{/10}}; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+  end
+
+  def test_selectors_properties_sourcemap_scss
+    assert_parses_with_mapping <<'SCSS', <<'CSS'
+$width: 2px;
+$translucent-red: rgba(255, 0, 0, 0.5);
+{{1}}a {{/1}}{
+  {{8}}.special {{/8}}{
+    {{9}}color{{/9}}: {{10}}red{{/10}};
+    {{11}}&:hover {{/11}}{
+      {{12}}foo{{/12}}: {{13}}bar{{/13}};
+      {{14}}cursor{{/14}}: {{15}}e + -resize{{/15}};
+      {{16}}color{{/16}}: {{17}}opacify($translucent-red, 0.3){{/17}};
+    }
+    {{18}}&:after {{/18}}{
+      {{19}}content{{/19}}: {{20}}"I ate #{5 + 10} pies #{$width} thick!"{{/20}};
+    }
+  }
+  {{21}}&:active {{/21}}{
+    {{22}}color{{/22}}: {{23}}#010203 + #040506{{/23}};
+    {{24}}border{{/24}}: {{25}}$width solid black{{/25}};
+  }
+/* SOME COMMENT */
+  {{2}}font{{/2}}: {{3}}2px/3px {{/3}}{
+    {{4}}family{{/4}}: {{5}}fantasy{{/5}};
+    {{6}}size{{/6}}: {{7}}1em + (2em * 3){{/7}};
+  }
+}
+SCSS
+{{1}}a{{/1}} {
+  /* SOME COMMENT */
+  {{2}}font{{/2}}: {{3}}2px/3px{{/3}};
+    {{4}}font-family{{/4}}: {{5}}fantasy{{/5}};
+    {{6}}font-size{{/6}}: {{7}}7em{{/7}}; }
+  {{8}}a .special{{/8}} {
+    {{9}}color{{/9}}: {{10}}red{{/10}}; }
+    {{11}}a .special:hover{{/11}} {
+      {{12}}foo{{/12}}: {{13}}bar{{/13}};
+      {{14}}cursor{{/14}}: {{15}}e-resize{{/15}};
+      {{16}}color{{/16}}: {{17}}rgba(255, 0, 0, 0.8){{/17}}; }
+    {{18}}a .special:after{{/18}} {
+      {{19}}content{{/19}}: {{20}}"I ate 15 pies 2px thick!"{{/20}}; }
+  {{21}}a:active{{/21}} {
+    {{22}}color{{/22}}: {{23}}#050709{{/23}};
+    {{24}}border{{/24}}: {{25}}2px solid black{{/25}}; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+  end
+
+  def test_selectors_properties_sourcemap_sass
+    assert_parses_with_mapping <<'SASS', <<'CSS', :syntax => :sass
+$width: 2px
+$translucent-red: rgba(255, 0, 0, 0.5)
+{{1}}a{{/1}}
+  {{8}}.special{{/8}}
+    {{9}}color{{/9}}: {{10}}red{{/10}}
+    {{11}}&:hover{{/11}}
+      {{12}}foo{{/12}}: {{13}}bar{{/13}}
+      {{14}}cursor{{/14}}: {{15}}e + -resize{{/15}}
+      {{16}}color{{/16}}: {{17}}opacify($translucent-red, 0.3){{/17}}
+    {{18}}&:after{{/18}}
+      {{19}}content{{/19}}: {{20}}"I ate #{5 + 10} pies #{$width} thick!"{{/20}}
+  {{21}}&:active{{/21}}
+    {{22}}color{{/22}}: {{23}}#010203 + #040506{{/23}}
+    {{24}}border{{/24}}: {{25}}$width solid black{{/25}}
+
+  /* SOME COMMENT */
+  {{2}}font{{/2}}: {{3}}2px/3px{{/3}}
+    {{4}}family{{/4}}: {{5}}fantasy{{/5}}
+    {{6}}size{{/6}}: {{7}}1em + (2em * 3){{/7}}
+SASS
+{{1}}a{{/1}} {
+  /* SOME COMMENT */
+  {{2}}font{{/2}}: {{3}}2px/3px{{/3}};
+    {{4}}font-family{{/4}}: {{5}}fantasy{{/5}};
+    {{6}}font-size{{/6}}: {{7}}7em{{/7}}; }
+  {{8}}a .special{{/8}} {
+    {{9}}color{{/9}}: {{10}}red{{/10}}; }
+    {{11}}a .special:hover{{/11}} {
+      {{12}}foo{{/12}}: {{13}}bar{{/13}};
+      {{14}}cursor{{/14}}: {{15}}e-resize{{/15}};
+      {{16}}color{{/16}}: {{17}}rgba(255, 0, 0, 0.8){{/17}}; }
+    {{18}}a .special:after{{/18}} {
+      {{19}}content{{/19}}: {{20}}"I ate 15 pies 2px thick!"{{/20}}; }
+  {{21}}a:active{{/21}} {
+    {{22}}color{{/22}}: {{23}}#050709{{/23}};
+    {{24}}border{{/24}}: {{25}}2px solid black{{/25}}; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+  end
+
+  def test_extend_sourcemap_scss
+    assert_parses_with_mapping <<'SCSS', <<'CSS'
+{{1}}.error {{/1}}{
+  {{2}}border{{/2}}: {{3}}1px #ff00aa{{/3}};
+  {{4}}background-color{{/4}}: {{5}}#fdd{{/5}};
+}
+{{6}}.seriousError {{/6}}{
+  @extend .error;
+  {{7}}border-width{{/7}}: {{8}}3px{{/8}};
+}
+SCSS
+{{1}}.error, .seriousError{{/1}} {
+  {{2}}border{{/2}}: {{3}}1px #ff00aa{{/3}};
+  {{4}}background-color{{/4}}: {{5}}#fdd{{/5}}; }
+
+{{6}}.seriousError{{/6}} {
+  {{7}}border-width{{/7}}: {{8}}3px{{/8}}; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+  end
+
+  def test_extend_sourcemap_sass
+    assert_parses_with_mapping <<'SASS', <<'CSS', :syntax => :sass
+{{1}}.error{{/1}}
+  {{2}}border{{/2}}: {{3}}1px #f00{{/3}}
+  {{4}}background-color{{/4}}: {{5}}#fdd{{/5}}
+
+{{6}}.seriousError{{/6}}
+  @extend .error
+  {{7}}border-width{{/7}}: {{8}}3px{{/8}}
+SASS
+{{1}}.error, .seriousError{{/1}} {
+  {{2}}border{{/2}}: {{3}}1px #f00{{/3}};
+  {{4}}background-color{{/4}}: {{5}}#fdd{{/5}}; }
+
+{{6}}.seriousError{{/6}} {
+  {{7}}border-width{{/7}}: {{8}}3px{{/8}}; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+  end
+
+  def test_for_sourcemap_scss
+    assert_parses_with_mapping <<'SCSS', <<'CSS'
+ for $i from 1 through 3 {
+  {{1}}{{4}}{{7}}.item-#{$i} {{/1}}{{/4}}{{/7}}{ {{2}}{{5}}{{8}}width{{/2}}{{/5}}{{/8}}: {{3}}{{6}}{{9}}2em 
* $i{{/3}}{{/6}}{{/9}}; }
+}
+SCSS
+{{1}}.item-1{{/1}} {
+  {{2}}width{{/2}}: {{3}}2em{{/3}}; }
+
+{{4}}.item-2{{/4}} {
+  {{5}}width{{/5}}: {{6}}4em{{/6}}; }
+
+{{7}}.item-3{{/7}} {
+  {{8}}width{{/8}}: {{9}}6em{{/9}}; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+  end
+
+  def test_for_sourcemap_sass
+    assert_parses_with_mapping <<'SASS', <<'CSS', :syntax => :sass
+ for $i from 1 through 3
+  {{1}}{{4}}{{7}}.item-#{$i}{{/1}}{{/4}}{{/7}}
+    {{2}}{{5}}{{8}}width{{/2}}{{/5}}{{/8}}: {{3}}{{6}}{{9}}2em * $i{{/3}}{{/6}}{{/9}}
+SASS
+{{1}}.item-1{{/1}} {
+  {{2}}width{{/2}}: {{3}}2em{{/3}}; }
+
+{{4}}.item-2{{/4}} {
+  {{5}}width{{/5}}: {{6}}4em{{/6}}; }
+
+{{7}}.item-3{{/7}} {
+  {{8}}width{{/8}}: {{9}}6em{{/9}}; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+  end
+
+  def test_while_sourcemap_scss
+    assert_parses_with_mapping <<'SCSS', <<'CSS'
+$i: 6;
+ while $i > 0 {
+  {{1}}{{4}}{{7}}.item-#{$i} {{/1}}{{/4}}{{/7}}{ {{2}}{{5}}{{8}}width{{/2}}{{/5}}{{/8}}: {{3}}{{6}}{{9}}2em 
* $i{{/3}}{{/6}}{{/9}}; }
+  $i: $i - 2 !global;
+}
+SCSS
+{{1}}.item-6{{/1}} {
+  {{2}}width{{/2}}: {{3}}12em{{/3}}; }
+
+{{4}}.item-4{{/4}} {
+  {{5}}width{{/5}}: {{6}}8em{{/6}}; }
+
+{{7}}.item-2{{/7}} {
+  {{8}}width{{/8}}: {{9}}4em{{/9}}; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+  end
+
+  def test_while_sourcemap_sass
+  assert_parses_with_mapping <<'SASS', <<'CSS', :syntax => :sass
+$i: 6
+ while $i > 0
+  {{1}}{{4}}{{7}}.item-#{$i}{{/1}}{{/4}}{{/7}}
+    {{2}}{{5}}{{8}}width{{/2}}{{/5}}{{/8}}: {{3}}{{6}}{{9}}2em * $i{{/3}}{{/6}}{{/9}}
+    $i: $i - 2 !global
+SASS
+{{1}}.item-6{{/1}} {
+  {{2}}width{{/2}}: {{3}}12em{{/3}}; }
+
+{{4}}.item-4{{/4}} {
+  {{5}}width{{/5}}: {{6}}8em{{/6}}; }
+
+{{7}}.item-2{{/7}} {
+  {{8}}width{{/8}}: {{9}}4em{{/9}}; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+  end
+
+  def test_each_sourcemap_scss
+    assert_parses_with_mapping <<'SCSS', <<'CSS'
+ each $animal in puma, sea-slug, egret, salamander {
+  {{1}}{{4}}{{7}}{{10}}.#{$animal}-icon {{/1}}{{/4}}{{/7}}{{/10}}{
+    {{2}}{{5}}{{8}}{{11}}background-image{{/2}}{{/5}}{{/8}}{{/11}}: 
{{3}}{{6}}{{9}}{{12}}url('/images/#{$animal}.png'){{/3}}{{/6}}{{/9}}{{/12}};
+  }
+}
+SCSS
+{{1}}.puma-icon{{/1}} {
+  {{2}}background-image{{/2}}: {{3}}url("/images/puma.png"){{/3}}; }
+
+{{4}}.sea-slug-icon{{/4}} {
+  {{5}}background-image{{/5}}: {{6}}url("/images/sea-slug.png"){{/6}}; }
+
+{{7}}.egret-icon{{/7}} {
+  {{8}}background-image{{/8}}: {{9}}url("/images/egret.png"){{/9}}; }
+
+{{10}}.salamander-icon{{/10}} {
+  {{11}}background-image{{/11}}: {{12}}url("/images/salamander.png"){{/12}}; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+  end
+
+  def test_each_sourcemap_sass
+    assert_parses_with_mapping <<'SASS', <<'CSS', :syntax => :sass
+ each $animal in puma, sea-slug, egret, salamander
+  {{1}}{{4}}{{7}}{{10}}.#{$animal}-icon{{/1}}{{/4}}{{/7}}{{/10}}
+    {{2}}{{5}}{{8}}{{11}}background-image{{/2}}{{/5}}{{/8}}{{/11}}: 
{{3}}{{6}}{{9}}{{12}}url('/images/#{$animal}.png'){{/3}}{{/6}}{{/9}}{{/12}}
+SASS
+{{1}}.puma-icon{{/1}} {
+  {{2}}background-image{{/2}}: {{3}}url("/images/puma.png"){{/3}}; }
+
+{{4}}.sea-slug-icon{{/4}} {
+  {{5}}background-image{{/5}}: {{6}}url("/images/sea-slug.png"){{/6}}; }
+
+{{7}}.egret-icon{{/7}} {
+  {{8}}background-image{{/8}}: {{9}}url("/images/egret.png"){{/9}}; }
+
+{{10}}.salamander-icon{{/10}} {
+  {{11}}background-image{{/11}}: {{12}}url("/images/salamander.png"){{/12}}; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+  end
+
+  def test_mixin_sourcemap_scss
+    assert_parses_with_mapping <<'SCSS', <<'CSS'
+ mixin large-text {
+  font: {
+    {{2}}size{{/2}}: {{3}}20px{{/3}};
+    {{4}}weight{{/4}}: {{5}}bold{{/5}};
+  }
+  {{6}}color{{/6}}: {{7}}#ff0000{{/7}};
+}
+
+{{1}}.page-title {{/1}}{
+  @include large-text;
+  {{8}}padding{{/8}}: {{9}}4px{{/9}};
+}
+
+ mixin dashed-border($color, $width: {{14}}1in{{/14}}) {
+  border: {
+    {{11}}{{18}}color{{/11}}{{/18}}: $color;
+    {{13}}{{20}}width{{/13}}{{/20}}: $width;
+    {{15}}{{22}}style{{/15}}{{/22}}: {{16}}{{23}}dashed{{/16}}{{/23}};
+  }
+}
+
+{{10}}p {{/10}}{ @include dashed-border({{12}}blue{{/12}}); }
+{{17}}h1 {{/17}}{ @include dashed-border({{19}}blue{{/19}}, {{21}}2in{{/21}}); }
+
+ mixin box-shadow($shadows...) {
+  {{25}}-moz-box-shadow{{/25}}: {{26}}$shadows{{/26}};
+  {{27}}-webkit-box-shadow{{/27}}: {{28}}$shadows{{/28}};
+  {{29}}box-shadow{{/29}}: {{30}}$shadows{{/30}};
+}
+
+{{24}}.shadows {{/24}}{
+  @include box-shadow(0px 4px 5px #666, 2px 6px 10px #999);
+}
+SCSS
+{{1}}.page-title{{/1}} {
+  {{2}}font-size{{/2}}: {{3}}20px{{/3}};
+  {{4}}font-weight{{/4}}: {{5}}bold{{/5}};
+  {{6}}color{{/6}}: {{7}}#ff0000{{/7}};
+  {{8}}padding{{/8}}: {{9}}4px{{/9}}; }
+
+{{10}}p{{/10}} {
+  {{11}}border-color{{/11}}: {{12}}blue{{/12}};
+  {{13}}border-width{{/13}}: {{14}}1in{{/14}};
+  {{15}}border-style{{/15}}: {{16}}dashed{{/16}}; }
+
+{{17}}h1{{/17}} {
+  {{18}}border-color{{/18}}: {{19}}blue{{/19}};
+  {{20}}border-width{{/20}}: {{21}}2in{{/21}};
+  {{22}}border-style{{/22}}: {{23}}dashed{{/23}}; }
+
+{{24}}.shadows{{/24}} {
+  {{25}}-moz-box-shadow{{/25}}: {{26}}0px 4px 5px #666, 2px 6px 10px #999{{/26}};
+  {{27}}-webkit-box-shadow{{/27}}: {{28}}0px 4px 5px #666, 2px 6px 10px #999{{/28}};
+  {{29}}box-shadow{{/29}}: {{30}}0px 4px 5px #666, 2px 6px 10px #999{{/30}}; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+  end
+
+def test_mixin_sourcemap_sass
+  assert_parses_with_mapping <<'SASS', <<'CSS', :syntax => :sass
+=large-text
+  :font
+    {{2}}size{{/2}}: {{3}}20px{{/3}}
+    {{4}}weight{{/4}}: {{5}}bold{{/5}}
+  {{6}}color{{/6}}: {{7}}#ff0000{{/7}}
+
+{{1}}.page-title{{/1}}
+  +large-text
+  {{8}}padding{{/8}}: {{9}}4px{{/9}}
+
+=dashed-border($color, $width: {{14}}1in{{/14}})
+  border:
+    {{11}}{{18}}color{{/11}}{{/18}}: $color
+    {{13}}{{20}}width{{/13}}{{/20}}: $width
+    {{15}}{{22}}style{{/15}}{{/22}}: {{16}}{{23}}dashed{{/16}}{{/23}}
+
+{{10}}p{{/10}}
+  +dashed-border({{12}}blue{{/12}})
+
+{{17}}h1{{/17}}
+  +dashed-border({{19}}blue{{/19}}, {{21}}2in{{/21}})
+
+=box-shadow($shadows...)
+  {{25}}-moz-box-shadow{{/25}}: {{26}}$shadows{{/26}}
+  {{27}}-webkit-box-shadow{{/27}}: {{28}}$shadows{{/28}}
+  {{29}}box-shadow{{/29}}: {{30}}$shadows{{/30}}
+
+{{24}}.shadows{{/24}}
+  +box-shadow(0px 4px 5px #666, 2px 6px 10px #999)
+SASS
+{{1}}.page-title{{/1}} {
+  {{2}}font-size{{/2}}: {{3}}20px{{/3}};
+  {{4}}font-weight{{/4}}: {{5}}bold{{/5}};
+  {{6}}color{{/6}}: {{7}}#ff0000{{/7}};
+  {{8}}padding{{/8}}: {{9}}4px{{/9}}; }
+
+{{10}}p{{/10}} {
+  {{11}}border-color{{/11}}: {{12}}blue{{/12}};
+  {{13}}border-width{{/13}}: {{14}}1in{{/14}};
+  {{15}}border-style{{/15}}: {{16}}dashed{{/16}}; }
+
+{{17}}h1{{/17}} {
+  {{18}}border-color{{/18}}: {{19}}blue{{/19}};
+  {{20}}border-width{{/20}}: {{21}}2in{{/21}};
+  {{22}}border-style{{/22}}: {{23}}dashed{{/23}}; }
+
+{{24}}.shadows{{/24}} {
+  {{25}}-moz-box-shadow{{/25}}: {{26}}0px 4px 5px #666, 2px 6px 10px #999{{/26}};
+  {{27}}-webkit-box-shadow{{/27}}: {{28}}0px 4px 5px #666, 2px 6px 10px #999{{/28}};
+  {{29}}box-shadow{{/29}}: {{30}}0px 4px 5px #666, 2px 6px 10px #999{{/30}}; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+end
+
+  def test_function_sourcemap_scss
+    assert_parses_with_mapping <<'SCSS', <<'CSS'
+$grid-width: 20px;
+$gutter-width: 5px;
+
+ function grid-width($n) {
+  @return $n * $grid-width + ($n - 1) * $gutter-width;
+}
+{{1}}sidebar {{/1}}{ {{2}}width{{/2}}: {{3}}grid-width(5){{/3}}; }
+SCSS
+{{1}}sidebar{{/1}} {
+  {{2}}width{{/2}}: {{3}}120px{{/3}}; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+  end
+
+  def test_function_sourcemap_sass
+    assert_parses_with_mapping <<'SASS', <<'CSS', :syntax => :sass
+$grid-width: 20px
+$gutter-width: 5px
+
+ function grid-width($n)
+  @return $n * $grid-width + ($n - 1) * $gutter-width
+
+{{1}}sidebar{{/1}}
+  {{2}}width{{/2}}: {{3}}grid-width(5){{/3}}
+SASS
+{{1}}sidebar{{/1}} {
+  {{2}}width{{/2}}: {{3}}120px{{/3}}; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+  end
+
+  # Regression tests
+
+  def test_properties_sass
+    assert_parses_with_mapping <<SASS, <<CSS, :syntax => :sass
+{{1}}.foo{{/1}}
+  :{{2}}name{{/2}} {{3}}value{{/3}}
+  {{4}}name{{/4}}: {{5}}value{{/5}}
+  :{{6}}name{{/6}}  {{7}}value{{/7}}
+  {{8}}name{{/8}}:  {{9}}value{{/9}}
+SASS
+{{1}}.foo{{/1}} {
+  {{2}}name{{/2}}: {{3}}value{{/3}};
+  {{4}}name{{/4}}: {{5}}value{{/5}};
+  {{6}}name{{/6}}: {{7}}value{{/7}};
+  {{8}}name{{/8}}: {{9}}value{{/9}}; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+  end
+
+  def test_multiline_script_scss
+    assert_parses_with_mapping <<SCSS, <<CSS, :syntax => :scss
+$var: {{3}}foo +
+    bar{{/3}}; {{1}}x {{/1}}{ {{2}}y{{/2}}: $var }
+SCSS
+{{1}}x{{/1}} {
+  {{2}}y{{/2}}: {{3}}foobar{{/3}}; }
+
+/*# sourceMappingURL=test.css.map */
+CSS
+  end
+
+  def test_multiline_interpolation_source_range
+    engine = Sass::Engine.new(<<-SCSS, :cache => false, :syntax => :scss)
+p {
+  filter: progid:DXImageTransform(
+          '\#{123}');
+}
+SCSS
+
+    interpolated = engine.to_tree.children.
+      first.children.
+      first.value.children[1]
+    assert_equal "123", interpolated.to_sass
+    range = interpolated.source_range
+    assert_equal 3, range.start_pos.line
+    assert_equal 14, range.start_pos.offset
+    assert_equal 3, range.end_pos.line
+    assert_equal 17, range.end_pos.offset
+  end
+
+  def test_sources_array_is_uri_escaped
+    map = Sass::Source::Map.new
+    importer = Sass::Importers::Filesystem.new('.')
+    map.add(
+      Sass::Source::Range.new(
+        Sass::Source::Position.new(0, 0),
+        Sass::Source::Position.new(0, 10),
+        'source file.scss',
+        importer),
+      Sass::Source::Range.new(
+        Sass::Source::Position.new(0, 0),
+        Sass::Source::Position.new(0, 10),
+        nil, nil))
+
+    json = map.to_json(:css_path => 'output file.css', :sourcemap_path => 'output file.css.map')
+    assert_equal json, <<JSON.rstrip
+{
+"version": 3,
+"mappings": "DADD,UAAU",
+"sources": ["source%20file.scss"],
+"names": [],
+"file": "output%20file.css"
+}
+JSON
+  end
+
+  private
+
+  ANNOTATION_REGEX = /\{\{(\/?)([^}]+)\}\}/
+
+  def build_ranges(text, file_name = nil)
+    ranges = Hash.new {|h, k| h[k] = []}
+    start_positions = {}
+    text.split("\n").each_with_index do |line_text, line|
+      line += 1 # lines shoud be 1-based
+      while (match = line_text.match(ANNOTATION_REGEX))
+        closing = !match[1].empty?
+        name = match[2]
+        match_offsets = match.offset(0)
+        offset = match_offsets[0] + 1 # Offsets are 1-based in source maps.
+        assert(!closing || start_positions[name], "Closing annotation #{name} found before opening one.")
+        position = Sass::Source::Position.new(line, offset)
+        if closing
+          ranges[name] << Sass::Source::Range.new(
+            start_positions[name], position, file_name,
+            Sass::Importers::Filesystem.new('.'))
+          start_positions.delete name
+        else
+          assert(!start_positions[name], "Overlapping range annotation #{name} encountered on line #{line}")
+          start_positions[name] = position
+        end
+        line_text.slice!(match_offsets[0], match_offsets[1] - match_offsets[0])
+      end
+    end
+    ranges
+  end
+
+  def build_mapping_from_annotations(source, css, source_file_name)
+    source_ranges = build_ranges(source, source_file_name)
+    target_ranges = build_ranges(css)
+    map = Sass::Source::Map.new
+    Sass::Util.flatten(source_ranges.map do |(name, sources)|
+        assert(sources.length == 1, "#{sources.length} source ranges encountered for annotation #{name}")
+        assert(target_ranges[name], "No target ranges for annotation #{name}")
+        target_ranges[name].map {|target_range| [sources.first, target_range]}
+      end, 1).
+      sort_by {|(_, target)| [target.start_pos.line, target.start_pos.offset]}.
+      each {|(s2, target)| map.add(s2, target)}
+    map
+  end
+
+  def assert_parses_with_mapping(source, css, options={})
+    options[:syntax] ||= :scss
+    input_filename = filename_for_test(options[:syntax])
+    mapping = build_mapping_from_annotations(source, css, input_filename)
+    source.gsub!(ANNOTATION_REGEX, "")
+    css.gsub!(ANNOTATION_REGEX, "")
+    rendered, sourcemap = render_with_sourcemap(source, options)
+    assert_equal css.rstrip, rendered.rstrip
+    assert_sourcemaps_equal source, css, mapping, sourcemap
+  end
+
+  def assert_positions_equal(expected, actual, lines, message = nil)
+    prefix = message ? message + ": " : ""
+    expected_location = lines[expected.line - 1] + "\n" + ("-" * (expected.offset - 1)) + "^"
+    actual_location = lines[actual.line - 1] + "\n" + ("-" * (actual.offset - 1)) + "^"
+    assert_equal(expected.line, actual.line, prefix +
+      "Expected #{expected.inspect}\n" +
+      expected_location + "\n\n" +
+      "But was #{actual.inspect}\n" +
+      actual_location)
+    assert_equal(expected.offset, actual.offset, prefix +
+      "Expected #{expected.inspect}\n" +
+      expected_location + "\n\n" +
+      "But was #{actual.inspect}\n" +
+      actual_location)
+  end
+
+  def assert_ranges_equal(expected, actual, lines, prefix)
+    assert_positions_equal(expected.start_pos, actual.start_pos, lines, prefix + " start position")
+    assert_positions_equal(expected.end_pos, actual.end_pos, lines, prefix + " end position")
+    assert_equal(expected.file, actual.file)
+  end
+
+  def assert_sourcemaps_equal(source, css, expected, actual)
+    assert_equal(expected.data.length, actual.data.length, <<MESSAGE)
+Wrong number of mappings. Expected:
+#{dump_sourcemap_as_expectation(source, css, expected).gsub(/^/, '| ')}
+
+Actual:
+#{dump_sourcemap_as_expectation(source, css, actual).gsub(/^/, '| ')}
+MESSAGE
+    source_lines = source.split("\n")
+    css_lines = css.split("\n")
+    expected.data.zip(actual.data) do |expected_mapping, actual_mapping|
+      assert_ranges_equal(expected_mapping.input, actual_mapping.input, source_lines, "Input")
+      assert_ranges_equal(expected_mapping.output, actual_mapping.output, css_lines, "Output")
+    end
+  end
+
+  def assert_parses_with_sourcemap(source, css, sourcemap_json, options={})
+    rendered, sourcemap = render_with_sourcemap(source, options)
+    css_path = options[:output] || "test.css"
+    sourcemap_path = Sass::Util.sourcemap_name(css_path)
+    rendered_json = sourcemap.to_json(:css_path => css_path, :sourcemap_path => sourcemap_path, :type => 
options[:sourcemap])
+
+    assert_equal css.rstrip, rendered.rstrip
+    assert_equal sourcemap_json.rstrip, rendered_json
+  end
+
+  def render_with_sourcemap(source, options={})
+    options[:syntax] ||= :scss
+    munge_filename options
+    engine = Sass::Engine.new(source, options)
+    engine.options[:cache] = false
+    sourcemap_path = Sass::Util.sourcemap_name(options[:output] || "test.css")
+    engine.render_with_sourcemap File.basename(sourcemap_path)
+  end
+
+  def dump_sourcemap_as_expectation(source, css, sourcemap)
+    mappings_to_annotations(source, sourcemap.data.map {|d| d.input}) + "\n\n" +
+      "=" * 20 + " maps to:\n\n" +
+      mappings_to_annotations(css, sourcemap.data.map {|d| d.output})
+  end
+
+  def mappings_to_annotations(source, ranges)
+    additional_offsets = Hash.new(0)
+    lines = source.split("\n")
+
+    add_annotation = lambda do |pos, str|
+      line_num = pos.line - 1
+      line = lines[line_num]
+      offset = pos.offset + additional_offsets[line_num] - 1
+      line << " " * (offset - line.length) if offset > line.length
+      line.insert(offset, str)
+      additional_offsets[line_num] += str.length
+    end
+
+    ranges.each_with_index do |range, i|
+      add_annotation[range.start_pos, "{{#{i + 1}}}"]
+      add_annotation[range.end_pos, "{{/#{i + 1}}}"]
+    end
+
+    return lines.join("\n")
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/test/sass/superselector_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/superselector_test.rb
new file mode 100755
index 0000000..3ac22de
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/superselector_test.rb
@@ -0,0 +1,210 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../test_helper'
+
+class SuperselectorTest < MiniTest::Test
+  def test_superselector_reflexivity
+    assert_superselector 'h1', 'h1'
+    assert_superselector '.foo', '.foo'
+    assert_superselector '#foo > .bar, baz', '#foo > .bar, baz'
+  end
+
+  def test_smaller_compound_superselector
+    assert_strict_superselector '.foo', '.foo.bar'
+    assert_strict_superselector '.bar', '.foo.bar'
+    assert_strict_superselector 'a', 'a#b'
+    assert_strict_superselector '#b', 'a#b'
+  end
+
+  def test_smaller_complex_superselector
+    assert_strict_superselector '.bar', '.foo .bar'
+    assert_strict_superselector '.bar', '.foo > .bar'
+    assert_strict_superselector '.bar', '.foo + .bar'
+    assert_strict_superselector '.bar', '.foo ~ .bar'
+  end
+
+  def test_selector_list_subset_superselector
+    assert_strict_superselector '.foo, .bar', '.foo'
+    assert_strict_superselector '.foo, .bar, .baz', '.foo, .baz'
+    assert_strict_superselector '.foo, .baz, .qux', '.foo.bar, .baz.bang'
+  end
+
+  def test_leading_combinator_superselector
+    refute_superselector '+ .foo', '.foo'
+    refute_superselector '+ .foo', '.bar + .foo'
+  end
+
+  def test_trailing_combinator_superselector
+    refute_superselector '.foo +', '.foo'
+    refute_superselector '.foo +', '.foo + .bar'
+  end
+
+  def test_matching_combinator_superselector
+    assert_strict_superselector '.foo + .bar', '.foo + .bar.baz'
+    assert_strict_superselector '.foo + .bar', '.foo.baz + .bar'
+    assert_strict_superselector '.foo > .bar', '.foo > .bar.baz'
+    assert_strict_superselector '.foo > .bar', '.foo.baz > .bar'
+    assert_strict_superselector '.foo ~ .bar', '.foo ~ .bar.baz'
+    assert_strict_superselector '.foo ~ .bar', '.foo.baz ~ .bar'
+  end
+
+  def test_following_sibling_is_superselector_of_next_sibling
+    assert_strict_superselector '.foo ~ .bar', '.foo + .bar.baz'
+    assert_strict_superselector '.foo ~ .bar', '.foo.baz + .bar'
+  end
+
+  def test_descendant_is_superselector_of_child
+    assert_strict_superselector '.foo .bar', '.foo > .bar.baz'
+    assert_strict_superselector '.foo .bar', '.foo.baz > .bar'
+    assert_strict_superselector '.foo .baz', '.foo > .bar > .baz'
+  end
+
+  def test_child_isnt_superselector_of_longer_child
+    refute_superselector '.foo > .baz', '.foo > .bar > .baz'
+    refute_superselector '.foo > .baz', '.foo > .bar .baz'
+  end
+
+  def test_following_sibling_isnt_superselector_of_longer_following_sibling
+    refute_superselector '.foo + .baz', '.foo + .bar + .baz'
+    refute_superselector '.foo + .baz', '.foo + .bar .baz'
+  end
+
+  def test_sibling_isnt_superselector_of_longer_sibling
+    # This actually is a superselector, but it's a very narrow edge case and
+    # detecting it is very difficult and may be exponential in the worst case.
+    refute_superselector '.foo ~ .baz', '.foo ~ .bar ~ .baz'
+
+    refute_superselector '.foo ~ .baz', '.foo ~ .bar .baz'
+  end
+
+  def test_matches_is_superselector_of_constituent_selectors
+    %w[matches -moz-any].each do |name|
+      assert_strict_superselector ":#{name}(.foo, .bar)", '.foo.baz'
+      assert_strict_superselector ":#{name}(.foo, .bar)", '.bar.baz'
+      assert_strict_superselector ":#{name}(.foo .bar, .baz)", '.x .foo .bar'
+    end
+  end
+
+  def test_matches_is_superselector_of_subset_matches
+    assert_strict_superselector ':matches(.foo, .bar, .baz)', '#x:matches(.foo.bip, .baz.bang)'
+    assert_strict_superselector ':-moz-any(.foo, .bar, .baz)', '#x:-moz-any(.foo.bip, .baz.bang)'
+  end
+
+  def test_matches_is_not_superselector_of_any
+    refute_superselector ':matches(.foo, .bar)', ':-moz-any(.foo, .bar)'
+    refute_superselector ':-moz-any(.foo, .bar)', ':matches(.foo, .bar)'
+  end
+
+  def test_matches_can_be_subselector
+    %w[matches -moz-any].each do |name|
+      assert_superselector '.foo', ":#{name}(.foo.bar)"
+      assert_superselector '.foo.bar', ":#{name}(.foo.bar.baz)"
+      assert_superselector '.foo', ":#{name}(.foo.bar, .foo.baz)"
+    end
+  end
+
+  def test_any_is_not_superselector_of_different_prefix
+    refute_superselector ':-moz-any(.foo, .bar)', ':-s-any(.foo, .bar)'
+  end
+
+  def test_not_is_superselector_of_less_complex_not
+    assert_strict_superselector ':not(.foo.bar)', ':not(.foo)'
+    assert_strict_superselector ':not(.foo .bar)', ':not(.bar)'
+  end
+
+  def test_not_is_superselector_of_superset
+    assert_strict_superselector ':not(.foo.bip, .baz.bang)', ':not(.foo, .bar, .baz)'
+    assert_strict_superselector ':not(.foo.bip, .baz.bang)', ':not(.foo):not(.bar):not(.baz)'
+  end
+
+  def test_not_is_superselector_of_unique_selectors
+    assert_strict_superselector ':not(h1.foo)', 'a'
+    assert_strict_superselector ':not(.baz #foo)', '#bar'
+  end
+
+  def test_not_is_not_superselector_of_non_unique_selectors
+    refute_superselector ':not(.foo)', '.bar'
+    refute_superselector ':not(:hover)', ':visited'
+  end
+
+  def test_current_is_superselector_with_identical_innards
+    assert_superselector ':current(.foo)', ':current(.foo)'
+  end
+
+  def test_current_is_superselector_with_subselector_innards
+    refute_superselector ':current(.foo)', ':current(.foo.bar)'
+    refute_superselector ':current(.foo.bar)', ':current(.foo)'
+  end
+
+  def test_nth_match_is_superselector_of_subset_nth_match
+    assert_strict_superselector(
+      ':nth-child(2n of .foo, .bar, .baz)', '#x:nth-child(2n of .foo.bip, .baz.bang)')
+    assert_strict_superselector(
+      ':nth-last-child(2n of .foo, .bar, .baz)', '#x:nth-last-child(2n of .foo.bip, .baz.bang)')
+  end
+
+  def test_nth_match_is_not_superselector_of_nth_match_with_different_arg
+    refute_superselector(
+      ':nth-child(2n of .foo, .bar, .baz)', '#x:nth-child(2n + 1 of .foo.bip, .baz.bang)')
+    refute_superselector(
+      ':nth-last-child(2n of .foo, .bar, .baz)', '#x:nth-last-child(2n + 1 of .foo.bip, .baz.bang)')
+  end
+
+  def test_nth_match_is_not_superselector_of_nth_last_match
+    refute_superselector ':nth-child(2n of .foo, .bar)', ':nth-last-child(2n of .foo, .bar)'
+    refute_superselector ':nth-last-child(2n of .foo, .bar)', ':nth-child(2n of .foo, .bar)'
+  end
+
+  def test_nth_match_can_be_subselector
+    %w[nth-child nth-last-child].each do |name|
+      assert_superselector '.foo', ":#{name}(2n of .foo.bar)"
+      assert_superselector '.foo.bar', ":#{name}(2n of .foo.bar.baz)"
+      assert_superselector '.foo', ":#{name}(2n of .foo.bar, .foo.baz)"
+    end
+  end
+
+  def has_is_superselector_of_subset_host
+    assert_strict_superselector ':has(.foo, .bar, .baz)', ':has(.foo.bip, .baz.bang)'
+  end
+
+  def has_isnt_superselector_of_contained_selector
+    assert_strict_superselector ':has(.foo, .bar, .baz)', '.foo'
+  end
+
+  def host_is_superselector_of_subset_host
+    assert_strict_superselector ':host(.foo, .bar, .baz)', ':host(.foo.bip, .baz.bang)'
+  end
+
+  def host_isnt_superselector_of_contained_selector
+    assert_strict_superselector ':host(.foo, .bar, .baz)', '.foo'
+  end
+
+  def host_context_is_superselector_of_subset_host
+    assert_strict_superselector(
+      ':host-context(.foo, .bar, .baz)', ':host-context(.foo.bip, .baz.bang)')
+  end
+
+  def host_context_isnt_superselector_of_contained_selector
+    assert_strict_superselector ':host-context(.foo, .bar, .baz)', '.foo'
+  end
+
+  private
+
+  def assert_superselector(superselector, subselector)
+    assert(parse_selector(superselector).superselector?(parse_selector(subselector)),
+      "Expected #{superselector} to be a superselector of #{subselector}.")
+  end
+
+  def refute_superselector(superselector, subselector)
+    assert(!parse_selector(superselector).superselector?(parse_selector(subselector)),
+      "Expected #{superselector} not to be a superselector of #{subselector}.")
+  end
+
+  def assert_strict_superselector(superselector, subselector)
+    assert_superselector(superselector, subselector)
+    refute_superselector(subselector, superselector)
+  end
+
+  def parse_selector(selector)
+    Sass::SCSS::CssParser.new(selector, filename_for_test, nil).parse_selector
+  end
+end
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/_cached_import_option_partial.scss 
b/backends/css/gems/sass-3.4.9/test/sass/templates/_cached_import_option_partial.scss
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/_cached_import_option_partial.scss
rename to backends/css/gems/sass-3.4.9/test/sass/templates/_cached_import_option_partial.scss
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/_double_import_loop2.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/_double_import_loop2.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/_double_import_loop2.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/_double_import_loop2.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/_filename_fn_import.scss 
b/backends/css/gems/sass-3.4.9/test/sass/templates/_filename_fn_import.scss
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/_filename_fn_import.scss
rename to backends/css/gems/sass-3.4.9/test/sass/templates/_filename_fn_import.scss
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/_imported_charset_ibm866.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/_imported_charset_ibm866.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/_imported_charset_ibm866.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/_imported_charset_ibm866.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/_imported_charset_utf8.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/_imported_charset_utf8.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/_imported_charset_utf8.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/_imported_charset_utf8.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/_imported_content.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/_imported_content.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/_imported_content.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/_imported_content.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/_partial.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/_partial.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/_partial.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/_partial.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/_same_name_different_partiality.scss 
b/backends/css/gems/sass-3.4.9/test/sass/templates/_same_name_different_partiality.scss
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/_same_name_different_partiality.scss
rename to backends/css/gems/sass-3.4.9/test/sass/templates/_same_name_different_partiality.scss
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/alt.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/alt.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/alt.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/alt.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/basic.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/basic.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/basic.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/basic.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/bork1.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/bork1.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/bork1.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/bork1.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/bork2.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/bork2.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/bork2.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/bork2.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/bork3.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/bork3.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/bork3.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/bork3.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/bork4.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/bork4.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/bork4.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/bork4.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/bork5.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/bork5.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/bork5.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/bork5.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/cached_import_option.scss 
b/backends/css/gems/sass-3.4.9/test/sass/templates/cached_import_option.scss
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/cached_import_option.scss
rename to backends/css/gems/sass-3.4.9/test/sass/templates/cached_import_option.scss
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/compact.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/compact.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/compact.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/compact.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/complex.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/complex.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/complex.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/complex.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/compressed.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/compressed.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/compressed.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/compressed.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/double_import_loop1.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/double_import_loop1.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/double_import_loop1.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/double_import_loop1.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/expanded.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/expanded.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/expanded.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/expanded.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/filename_fn.scss 
b/backends/css/gems/sass-3.4.9/test/sass/templates/filename_fn.scss
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/filename_fn.scss
rename to backends/css/gems/sass-3.4.9/test/sass/templates/filename_fn.scss
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/if.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/if.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/if.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/if.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/import.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/import.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/import.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/import.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/import_charset.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/import_charset.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/import_charset.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/import_charset.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/import_charset_1_8.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/import_charset_1_8.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/import_charset_1_8.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/import_charset_1_8.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/import_charset_ibm866.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/import_charset_ibm866.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/import_charset_ibm866.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/import_charset_ibm866.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/import_content.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/import_content.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/import_content.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/import_content.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/importee.less 
b/backends/css/gems/sass-3.4.9/test/sass/templates/importee.less
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/importee.less
rename to backends/css/gems/sass-3.4.9/test/sass/templates/importee.less
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/importee.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/importee.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/importee.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/importee.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/line_numbers.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/line_numbers.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/line_numbers.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/line_numbers.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/mixin_bork.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/mixin_bork.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/mixin_bork.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/mixin_bork.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/mixins.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/mixins.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/mixins.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/mixins.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/multiline.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/multiline.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/multiline.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/multiline.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/nested.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/nested.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/nested.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/nested.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/nested_bork1.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/nested_bork1.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/nested_bork1.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/nested_bork1.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/nested_bork2.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/nested_bork2.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/nested_bork2.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/nested_bork2.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/nested_bork3.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/nested_bork3.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/nested_bork3.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/nested_bork3.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/nested_bork4.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/nested_bork4.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/nested_bork4.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/nested_bork4.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/nested_import.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/nested_import.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/nested_import.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/nested_import.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/nested_mixin_bork.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/nested_mixin_bork.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/nested_mixin_bork.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/nested_mixin_bork.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/options.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/options.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/options.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/options.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/parent_ref.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/parent_ref.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/parent_ref.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/parent_ref.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/same_name_different_ext.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/same_name_different_ext.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/same_name_different_ext.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/same_name_different_ext.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/same_name_different_ext.scss 
b/backends/css/gems/sass-3.4.9/test/sass/templates/same_name_different_ext.scss
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/same_name_different_ext.scss
rename to backends/css/gems/sass-3.4.9/test/sass/templates/same_name_different_ext.scss
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/same_name_different_partiality.scss 
b/backends/css/gems/sass-3.4.9/test/sass/templates/same_name_different_partiality.scss
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/same_name_different_partiality.scss
rename to backends/css/gems/sass-3.4.9/test/sass/templates/same_name_different_partiality.scss
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/script.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/script.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/script.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/script.sass
diff --git a/backends/css/gems/sass-3.4.9/test/sass/templates/scss_import.scss 
b/backends/css/gems/sass-3.4.9/test/sass/templates/scss_import.scss
new file mode 100644
index 0000000..b9c5c79
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/templates/scss_import.scss
@@ -0,0 +1,12 @@
+$preconst: hello;
+
+ mixin premixin {pre-mixin: here}
+
+ import "importee.sass", "scss_importee", "basic.sass", "basic.css", "../results/complex.css";
+ import "part\
+ial.sass";
+
+nonimported {
+  myconst: $preconst;
+  otherconst: $postconst;
+  @include postmixin; }
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/scss_importee.scss 
b/backends/css/gems/sass-3.4.9/test/sass/templates/scss_importee.scss
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/scss_importee.scss
rename to backends/css/gems/sass-3.4.9/test/sass/templates/scss_importee.scss
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/single_import_loop.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/single_import_loop.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/single_import_loop.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/single_import_loop.sass
diff --git a/backends/css/gems/sass-3.4.9/test/sass/templates/subdir/import_up1.scss 
b/backends/css/gems/sass-3.4.9/test/sass/templates/subdir/import_up1.scss
new file mode 100644
index 0000000..90559f5
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/templates/subdir/import_up1.scss
@@ -0,0 +1 @@
+ import "../subdir/import_up2.scss";
\ No newline at end of file
diff --git a/backends/css/gems/sass-3.4.9/test/sass/templates/subdir/import_up2.scss 
b/backends/css/gems/sass-3.4.9/test/sass/templates/subdir/import_up2.scss
new file mode 100644
index 0000000..22f5a59
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/templates/subdir/import_up2.scss
@@ -0,0 +1 @@
+ import "../subdir/import_up3.scss";
\ No newline at end of file
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/subdir/nested_subdir/_nested_partial.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/subdir/nested_subdir/_nested_partial.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/subdir/nested_subdir/_nested_partial.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/subdir/nested_subdir/_nested_partial.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/subdir/nested_subdir/nested_subdir.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/subdir/nested_subdir/nested_subdir.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/subdir/nested_subdir/nested_subdir.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/subdir/nested_subdir/nested_subdir.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/subdir/subdir.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/subdir/subdir.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/subdir/subdir.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/subdir/subdir.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/units.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/units.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/units.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/units.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/warn.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/warn.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/warn.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/warn.sass
diff --git a/backends/css/gems/sass-3.2.12/test/sass/templates/warn_imported.sass 
b/backends/css/gems/sass-3.4.9/test/sass/templates/warn_imported.sass
similarity index 100%
rename from backends/css/gems/sass-3.2.12/test/sass/templates/warn_imported.sass
rename to backends/css/gems/sass-3.4.9/test/sass/templates/warn_imported.sass
diff --git a/backends/css/gems/sass-3.4.9/test/sass/test_helper.rb 
b/backends/css/gems/sass-3.4.9/test/sass/test_helper.rb
new file mode 100644
index 0000000..eaa433f
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/test_helper.rb
@@ -0,0 +1,8 @@
+test_dir = File.dirname(__FILE__)
+$:.unshift test_dir unless $:.include?(test_dir)
+
+class MiniTest::Test
+  def absolutize(file)
+    File.expand_path("#{File.dirname(__FILE__)}/#{file}")
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/test/sass/util/multibyte_string_scanner_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/util/multibyte_string_scanner_test.rb
new file mode 100755
index 0000000..f8dbab7
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/util/multibyte_string_scanner_test.rb
@@ -0,0 +1,147 @@
+#!/usr/bin/env ruby
+# -*- coding: utf-8 -*-
+require File.dirname(__FILE__) + '/../../test_helper'
+
+unless Sass::Util.ruby1_8?
+  class MultibyteStringScannerTest < MiniTest::Test
+    def setup
+      @scanner = Sass::Util::MultibyteStringScanner.new("cölorfül")
+    end
+
+    def test_initial
+      assert_scanner_state 0, 0, nil, nil
+    end
+
+    def test_check
+      assert_equal 'cö', @scanner.check(/../)
+      assert_scanner_state 0, 0, 2, 3
+      assert_equal 0, @scanner.pos
+      assert_equal 0, @scanner.pos
+      assert_equal 2, @scanner.matched_size
+      assert_equal 3, @scanner.byte_matched_size
+    end
+
+    def test_check_until
+      assert_equal 'cölorfü', @scanner.check_until(/f./)
+      assert_scanner_state 0, 0, 2, 3
+    end
+
+    def test_getch
+      assert_equal 'c', @scanner.getch
+      assert_equal 'ö', @scanner.getch
+      assert_scanner_state 2, 3, 1, 2
+    end
+
+    def test_match?
+      assert_equal 2, @scanner.match?(/../)
+      assert_scanner_state 0, 0, 2, 3
+    end
+
+    def test_peek
+      assert_equal 'cö', @scanner.peek(2)
+      assert_scanner_state 0, 0, nil, nil
+    end
+
+    def test_rest_size
+      assert_equal 'cö', @scanner.scan(/../)
+      assert_equal 6, @scanner.rest_size
+    end
+
+    def test_scan
+      assert_equal 'cö', @scanner.scan(/../)
+      assert_scanner_state 2, 3, 2, 3
+    end
+
+    def test_scan_until
+      assert_equal 'cölorfü', @scanner.scan_until(/f./)
+      assert_scanner_state 7, 9, 2, 3
+    end
+
+    def test_skip
+      assert_equal 2, @scanner.skip(/../)
+      assert_scanner_state 2, 3, 2, 3
+    end
+
+    def test_skip_until
+      assert_equal 7, @scanner.skip_until(/f./)
+      assert_scanner_state 7, 9, 2, 3
+    end
+
+    def test_set_pos
+      @scanner.pos = 7
+      assert_scanner_state 7, 9, nil, nil
+      @scanner.pos = 6
+      assert_scanner_state 6, 7, nil, nil
+      @scanner.pos = 1
+      assert_scanner_state 1, 1, nil, nil
+    end
+
+    def test_reset
+      @scanner.scan(/../)
+      @scanner.reset
+      assert_scanner_state 0, 0, nil, nil
+    end
+
+    def test_scan_full
+      assert_equal 'cö', @scanner.scan_full(/../, true, true)
+      assert_scanner_state 2, 3, 2, 3
+
+      @scanner.reset
+      assert_equal 'cö', @scanner.scan_full(/../, false, true)
+      assert_scanner_state 0, 0, 2, 3
+
+      @scanner.reset
+      assert_nil @scanner.scan_full(/../, true, false)
+      assert_scanner_state 2, 3, 2, 3
+
+      @scanner.reset
+      assert_nil @scanner.scan_full(/../, false, false)
+      assert_scanner_state 0, 0, 2, 3
+    end
+
+    def test_search_full
+      assert_equal 'cölorfü', @scanner.search_full(/f./, true, true)
+      assert_scanner_state 7, 9, 2, 3
+
+      @scanner.reset
+      assert_equal 'cölorfü', @scanner.search_full(/f./, false, true)
+      assert_scanner_state 0, 0, 2, 3
+
+      @scanner.reset
+      assert_nil @scanner.search_full(/f./, true, false)
+      assert_scanner_state 7, 9, 2, 3
+
+      @scanner.reset
+      assert_nil @scanner.search_full(/f./, false, false)
+      assert_scanner_state 0, 0, 2, 3
+    end
+
+    def test_set_string
+      @scanner.scan(/../)
+      @scanner.string = 'föóbâr'
+      assert_scanner_state 0, 0, nil, nil
+    end
+
+    def test_terminate
+      @scanner.scan(/../)
+      @scanner.terminate
+      assert_scanner_state 8, 10, nil, nil
+    end
+
+    def test_unscan
+      @scanner.scan(/../)
+      @scanner.scan_until(/f./)
+      @scanner.unscan
+      assert_scanner_state 2, 3, nil, nil
+    end
+
+    private
+
+    def assert_scanner_state(pos, byte_pos, matched_size, byte_matched_size)
+      assert_equal pos, @scanner.pos, 'pos'
+      assert_equal byte_pos, @scanner.byte_pos, 'byte_pos'
+      assert_equal matched_size, @scanner.matched_size, 'matched_size'
+      assert_equal byte_matched_size, @scanner.byte_matched_size, 'byte_matched_size'
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/test/sass/util/normalized_map_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/util/normalized_map_test.rb
new file mode 100755
index 0000000..99a1719
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/util/normalized_map_test.rb
@@ -0,0 +1,51 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../../test_helper'
+require 'sass/util/normalized_map'
+
+class NormalizedMapTest < MiniTest::Test
+  extend PublicApiLinter
+
+  lint_api Hash, Sass::Util::NormalizedMap
+
+  def lint_instance
+    Sass::Util::NormalizedMap.new
+  end
+
+  def test_normalized_map_errors_unless_explicitly_implemented
+    assert Sass.tests_running
+    assert_raise_message(ArgumentError, "The method invert must be implemented explicitly") do
+      Sass::Util::NormalizedMap.new.invert
+    end
+  end
+
+  def test_normalized_map_does_not_error_when_released
+    Sass.tests_running = false
+    assert_equal({}, Sass::Util::NormalizedMap.new.invert)
+  ensure
+    Sass.tests_running = true
+  end
+
+  def test_basic_lifecycle
+    m = Sass::Util::NormalizedMap.new
+    m["a-b"] = 1
+    assert_equal ["a_b"], m.keys
+    assert_equal 1, m["a_b"]
+    assert_equal 1, m["a-b"]
+    assert m.has_key?("a_b")
+    assert m.has_key?("a-b")
+    assert_equal({"a-b" => 1}, m.as_stored)
+    assert_equal 1, m.delete("a-b")
+    assert !m.has_key?("a-b")
+    m["a_b"] = 2
+    assert_equal({"a_b" => 2}, m.as_stored)
+  end
+
+  def test_dup
+    m = Sass::Util::NormalizedMap.new
+    m["a-b"] = 1
+    m2 = m.dup
+    m.delete("a-b")
+    assert !m.has_key?("a-b")
+    assert m2.has_key?("a-b")
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/test/sass/util/subset_map_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/util/subset_map_test.rb
new file mode 100755
index 0000000..9d42543
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/util/subset_map_test.rb
@@ -0,0 +1,91 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../../test_helper'
+
+class SubsetMapTest < MiniTest::Test
+  def setup
+    @ssm = Sass::Util::SubsetMap.new
+    @ssm[Set[1, 2]] = "Foo"
+    @ssm[Set["fizz", "fazz"]] = "Bar"
+
+    @ssm[Set[:foo, :bar]] = "Baz"
+    @ssm[Set[:foo, :bar, :baz]] = "Bang"
+
+    @ssm[Set[:bip, :bop, :blip]] = "Qux"
+    @ssm[Set[:bip, :bop]] = "Thram"
+  end
+
+  def test_equal_keys
+    assert_equal [["Foo", Set[1, 2]]], @ssm.get(Set[1, 2])
+    assert_equal [["Bar", Set["fizz", "fazz"]]], @ssm.get(Set["fizz", "fazz"])
+  end
+
+  def test_subset_keys
+    assert_equal [["Foo", Set[1, 2]]], @ssm.get(Set[1, 2, "fuzz"])
+    assert_equal [["Bar", Set["fizz", "fazz"]]], @ssm.get(Set["fizz", "fazz", 3])
+  end
+
+  def test_superset_keys
+    assert_equal [], @ssm.get(Set[1])
+    assert_equal [], @ssm.get(Set[2])
+    assert_equal [], @ssm.get(Set["fizz"])
+    assert_equal [], @ssm.get(Set["fazz"])
+  end
+
+  def test_disjoint_keys
+    assert_equal [], @ssm.get(Set[3, 4])
+    assert_equal [], @ssm.get(Set["fuzz", "frizz"])
+    assert_equal [], @ssm.get(Set["gran", 15])
+  end
+
+  def test_semi_disjoint_keys
+    assert_equal [], @ssm.get(Set[2, 3])
+    assert_equal [], @ssm.get(Set["fizz", "fuzz"])
+    assert_equal [], @ssm.get(Set[1, "fazz"])
+  end
+
+  def test_empty_key_set
+    assert_raises(ArgumentError) { ssm[Set[]] = "Fail"}
+  end
+
+  def test_empty_key_get
+    assert_equal [], @ssm.get(Set[])
+  end
+
+  def test_multiple_subsets
+    assert_equal [["Foo", Set[1, 2]], ["Bar", Set["fizz", "fazz"]]], @ssm.get(Set[1, 2, "fizz", "fazz"])
+    assert_equal [["Foo", Set[1, 2]], ["Bar", Set["fizz", "fazz"]]], @ssm.get(Set[1, 2, 3, "fizz", "fazz", 
"fuzz"])
+
+    assert_equal [["Baz", Set[:foo, :bar]]], @ssm.get(Set[:foo, :bar])
+    assert_equal [["Baz", Set[:foo, :bar]], ["Bang", Set[:foo, :bar, :baz]]], @ssm.get(Set[:foo, :bar, :baz])
+  end
+
+  def test_bracket_bracket
+    assert_equal ["Foo"], @ssm[Set[1, 2, "fuzz"]]
+    assert_equal ["Baz", "Bang"], @ssm[Set[:foo, :bar, :baz]]
+  end
+
+  def test_order_preserved
+    @ssm[Set[10, 11, 12]] = 1
+    @ssm[Set[10, 11]] = 2
+    @ssm[Set[11]] = 3
+    @ssm[Set[11, 12]] = 4
+    @ssm[Set[9, 10, 11, 12, 13]] = 5
+    @ssm[Set[10, 13]] = 6
+
+    assert_equal(
+      [[1, Set[10, 11, 12]], [2, Set[10, 11]], [3, Set[11]], [4, Set[11, 12]],
+        [5, Set[9, 10, 11, 12, 13]], [6, Set[10, 13]]],
+      @ssm.get(Set[9, 10, 11, 12, 13]))
+  end
+
+  def test_multiple_equal_values
+    @ssm[Set[11, 12]] = 1
+    @ssm[Set[12, 13]] = 2
+    @ssm[Set[13, 14]] = 1
+    @ssm[Set[14, 15]] = 1
+
+    assert_equal(
+      [[1, Set[11, 12]], [2, Set[12, 13]], [1, Set[13, 14]], [1, Set[14, 15]]],
+      @ssm.get(Set[11, 12, 13, 14, 15]))
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/test/sass/util_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/util_test.rb
new file mode 100755
index 0000000..bcb7fda
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/util_test.rb
@@ -0,0 +1,471 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../test_helper'
+require 'pathname'
+require 'tmpdir'
+
+class UtilTest < MiniTest::Test
+  include Sass::Util
+
+  def test_scope
+    assert(File.exist?(scope("Rakefile")))
+  end
+
+  def test_to_hash
+    assert_equal({
+        :foo => 1,
+        :bar => 2,
+        :baz => 3
+      }, to_hash([[:foo, 1], [:bar, 2], [:baz, 3]]))
+  end
+
+  def test_map_keys
+    assert_equal({
+        "foo" => 1,
+        "bar" => 2,
+        "baz" => 3
+      }, map_keys({:foo => 1, :bar => 2, :baz => 3}) {|k| k.to_s})
+  end
+
+  def test_map_vals
+    assert_equal({
+        :foo => "1",
+        :bar => "2",
+        :baz => "3"
+      }, map_vals({:foo => 1, :bar => 2, :baz => 3}) {|k| k.to_s})
+  end
+
+  def test_map_hash
+    assert_equal({
+        "foo" => "1",
+        "bar" => "2",
+        "baz" => "3"
+      }, map_hash({:foo => 1, :bar => 2, :baz => 3}) {|k, v| [k.to_s, v.to_s]})
+  end
+
+  def test_map_hash_with_normalized_map
+    map = NormalizedMap.new("foo-bar" => 1, "baz_bang" => 2)
+    result = map_hash(map) {|k, v| [k, v.to_s]}
+    assert_equal("1", result["foo-bar"])
+    assert_equal("1", result["foo_bar"])
+    assert_equal("2", result["baz-bang"])
+    assert_equal("2", result["baz_bang"])
+  end
+
+  def test_powerset
+    return unless Set[Set[]] == Set[Set[]] # There's a bug in Ruby 1.8.6 that breaks nested set equality
+    assert_equal([[].to_set].to_set,
+      powerset([]))
+    assert_equal([[].to_set, [1].to_set].to_set,
+      powerset([1]))
+    assert_equal([[].to_set, [1].to_set, [2].to_set, [1, 2].to_set].to_set,
+      powerset([1, 2]))
+    assert_equal([[].to_set, [1].to_set, [2].to_set, [3].to_set,
+        [1, 2].to_set, [2, 3].to_set, [1, 3].to_set, [1, 2, 3].to_set].to_set,
+      powerset([1, 2, 3]))
+  end
+
+  def test_restrict
+    assert_equal(0.5, restrict(0.5, 0..1))
+    assert_equal(1, restrict(2, 0..1))
+    assert_equal(1.3, restrict(2, 0..1.3))
+    assert_equal(0, restrict(-1, 0..1))
+  end
+
+  def test_merge_adjacent_strings
+    assert_equal(["foo bar baz", :bang, "biz bop", 12],
+      merge_adjacent_strings(["foo ", "bar ", "baz", :bang, "biz", " bop", 12]))
+    str = "foo"
+    assert_equal(["foo foo foo", :bang, "foo foo", 12],
+      merge_adjacent_strings([str, " ", str, " ", str, :bang, str, " ", str, 12]))
+  end
+
+  def test_replace_subseq
+    assert_equal([1, 2, :a, :b, 5],
+      replace_subseq([1, 2, 3, 4, 5], [3, 4], [:a, :b]))
+    assert_equal([1, 2, 3, 4, 5],
+      replace_subseq([1, 2, 3, 4, 5], [3, 4, 6], [:a, :b]))
+    assert_equal([1, 2, 3, 4, 5],
+      replace_subseq([1, 2, 3, 4, 5], [4, 5, 6], [:a, :b]))
+  end
+
+  def test_intersperse
+    assert_equal(["foo", " ", "bar", " ", "baz"],
+      intersperse(%w[foo bar baz], " "))
+    assert_equal([], intersperse([], " "))
+  end
+
+  def test_substitute
+    assert_equal(["foo", "bar", "baz", 3, 4],
+      substitute([1, 2, 3, 4], [1, 2], ["foo", "bar", "baz"]))
+    assert_equal([1, "foo", "bar", "baz", 4],
+      substitute([1, 2, 3, 4], [2, 3], ["foo", "bar", "baz"]))
+    assert_equal([1, 2, "foo", "bar", "baz"],
+      substitute([1, 2, 3, 4], [3, 4], ["foo", "bar", "baz"]))
+
+    assert_equal([1, "foo", "bar", "baz", 2, 3, 4],
+      substitute([1, 2, 2, 2, 3, 4], [2, 2], ["foo", "bar", "baz"]))
+  end
+
+  def test_strip_string_array
+    assert_equal(["foo ", " bar ", " baz"],
+      strip_string_array([" foo ", " bar ", " baz "]))
+    assert_equal([:foo, " bar ", " baz"],
+      strip_string_array([:foo, " bar ", " baz "]))
+    assert_equal(["foo ", " bar ", :baz],
+      strip_string_array([" foo ", " bar ", :baz]))
+  end
+
+  def test_paths
+    assert_equal([[1, 3, 5], [2, 3, 5], [1, 4, 5], [2, 4, 5]],
+      paths([[1, 2], [3, 4], [5]]))
+    assert_equal([[]], paths([]))
+    assert_equal([[1, 2, 3]], paths([[1], [2], [3]]))
+  end
+
+  def test_lcs
+    assert_equal([1, 2, 3], lcs([1, 2, 3], [1, 2, 3]))
+    assert_equal([], lcs([], [1, 2, 3]))
+    assert_equal([], lcs([1, 2, 3], []))
+    assert_equal([1, 2, 3], lcs([5, 1, 4, 2, 3, 17], [0, 0, 1, 2, 6, 3]))
+
+    assert_equal([1], lcs([1, 2, 3, 4], [4, 3, 2, 1]))
+    assert_equal([1, 2], lcs([1, 2, 3, 4], [3, 4, 1, 2]))
+  end
+
+  def test_lcs_with_block
+    assert_equal(["1", "2", "3"],
+      lcs([1, 4, 2, 5, 3], [1, 2, 3]) {|a, b| a == b && a.to_s})
+    assert_equal([-4, 2, 8],
+      lcs([-5, 3, 2, 8], [-4, 1, 8]) {|a, b| (a - b).abs <= 1 && [a, b].max})
+  end
+
+  def test_group_by_to_a
+    assert_equal([[1, [1, 3, 5, 7]], [0, [2, 4, 6, 8]]],
+      group_by_to_a(1..8) {|i| i % 2})
+    assert_equal([[1, [1, 4, 7, 10]], [2, [2, 5, 8, 11]], [0, [3, 6, 9, 12]]],
+      group_by_to_a(1..12) {|i| i % 3})
+  end
+
+  def test_subsequence
+    assert(subsequence?([1, 2, 3], [1, 2, 3]))
+    assert(subsequence?([1, 2, 3], [1, :a, 2, :b, 3]))
+    assert(subsequence?([1, 2, 3], [:a, 1, :b, :c, 2, :d, 3, :e, :f]))
+
+    assert(!subsequence?([1, 2, 3], [1, 2]))
+    assert(!subsequence?([1, 2, 3], [1, 3, 2]))
+    assert(!subsequence?([1, 2, 3], [3, 2, 1]))
+  end
+
+  def test_silence_warnings
+    old_stderr, $stderr = $stderr, StringIO.new
+    warn "Out"
+    assert_equal("Out\n", $stderr.string)
+    silence_warnings {warn "In"}
+    assert_equal("Out\n", $stderr.string)
+  ensure
+    $stderr = old_stderr
+  end
+
+  def test_sass_warn
+    assert_warning("Foo!") {sass_warn "Foo!"}
+  end
+
+  def test_silence_sass_warnings
+    old_stderr, $stderr = $stderr, StringIO.new
+    silence_sass_warnings {warn "Out"}
+    assert_equal("Out\n", $stderr.string)
+    silence_sass_warnings {sass_warn "In"}
+    assert_equal("Out\n", $stderr.string)
+  ensure
+    $stderr = old_stderr
+  end
+
+  def test_has
+    assert(has?(:instance_method, String, :chomp!))
+    assert(has?(:private_instance_method, Sass::Engine, :parse_interp))
+  end
+
+  def test_enum_with_index
+    assert_equal(%w[foo0 bar1 baz2],
+      enum_with_index(%w[foo bar baz]).map {|s, i| "#{s}#{i}"})
+  end
+
+  def test_enum_cons
+    assert_equal(%w[foobar barbaz],
+      enum_cons(%w[foo bar baz], 2).map {|s1, s2| "#{s1}#{s2}"})
+  end
+
+  def test_extract
+    arr = [1, 2, 3, 4, 5]
+    assert_equal([1, 3, 5], extract!(arr) {|e| e % 2 == 1})
+    assert_equal([2, 4], arr)
+  end
+
+  def test_ord
+    assert_equal(102, ord("f"))
+    assert_equal(98, ord("bar"))
+  end
+
+  def test_flatten
+    assert_equal([1, 2, 3], flatten([1, 2, 3], 0))
+    assert_equal([1, 2, 3], flatten([1, 2, 3], 1))
+    assert_equal([1, 2, 3], flatten([1, 2, 3], 2))
+
+    assert_equal([[1, 2], 3], flatten([[1, 2], 3], 0))
+    assert_equal([1, 2, 3], flatten([[1, 2], 3], 1))
+    assert_equal([1, 2, 3], flatten([[1, 2], 3], 2))
+
+    assert_equal([[[1], 2], [3], 4], flatten([[[1], 2], [3], 4], 0))
+    assert_equal([[1], 2, 3, 4], flatten([[[1], 2], [3], 4], 1))
+    assert_equal([1, 2, 3, 4], flatten([[[1], 2], [3], 4], 2))
+  end
+
+  def test_flatten_vertically
+    assert_equal([1, 2, 3], flatten_vertically([1, 2, 3]))
+    assert_equal([1, 3, 5, 2, 4, 6], flatten_vertically([[1, 2], [3, 4], [5, 6]]))
+    assert_equal([1, 2, 4, 3, 5, 6], flatten_vertically([1, [2, 3], [4, 5, 6]]))
+    assert_equal([1, 4, 6, 2, 5, 3], flatten_vertically([[1, 2, 3], [4, 5], 6]))
+  end
+
+  def test_set_hash
+    assert(set_hash(Set[1, 2, 3]) == set_hash(Set[3, 2, 1]))
+    assert(set_hash(Set[1, 2, 3]) == set_hash(Set[1, 2, 3]))
+
+    s1 = Set[]
+    s1 << 1
+    s1 << 2
+    s1 << 3
+    s2 = Set[]
+    s2 << 3
+    s2 << 2
+    s2 << 1
+    assert(set_hash(s1) == set_hash(s2))
+  end
+
+  def test_set_eql
+    assert(set_eql?(Set[1, 2, 3], Set[3, 2, 1]))
+    assert(set_eql?(Set[1, 2, 3], Set[1, 2, 3]))
+
+    s1 = Set[]
+    s1 << 1
+    s1 << 2
+    s1 << 3
+    s2 = Set[]
+    s2 << 3
+    s2 << 2
+    s2 << 1
+    assert(set_eql?(s1, s2))
+  end
+
+  def test_extract_and_inject_values
+    test = lambda {|arr| assert_equal(arr, with_extracted_values(arr) {|str| str})}
+
+    test[['foo bar']]
+    test[['foo {12} bar']]
+    test[['foo {{12} bar']]
+    test[['foo {{1', 12, '2} bar']]
+    test[['foo 1', 2, '{3', 4, 5, 6, '{7}', 8]]
+    test[['foo 1', [2, 3, 4], ' bar']]
+    test[['foo ', 1, "\n bar\n", [2, 3, 4], "\n baz"]]
+  end
+
+  def nested_caller_info_fn
+    caller_info
+  end
+
+  def double_nested_caller_info_fn
+    nested_caller_info_fn
+  end
+
+  def test_caller_info
+    assert_equal(["/tmp/foo.rb", 12, "fizzle"], caller_info("/tmp/foo.rb:12: in `fizzle'"))
+    assert_equal(["/tmp/foo.rb", 12, nil], caller_info("/tmp/foo.rb:12"))
+    assert_equal(["C:/tmp/foo.rb", 12, nil], caller_info("C:/tmp/foo.rb:12"))
+    assert_equal(["(sass)", 12, "blah"], caller_info("(sass):12: in `blah'"))
+    assert_equal(["", 12, "boop"], caller_info(":12: in `boop'"))
+    assert_equal(["/tmp/foo.rb", -12, "fizzle"], caller_info("/tmp/foo.rb:-12: in `fizzle'"))
+    assert_equal(["/tmp/foo.rb", 12, "fizzle"], caller_info("/tmp/foo.rb:12: in `fizzle {}'"))
+    assert_equal(["C:/tmp/foo.rb", 12, "fizzle"], caller_info("C:/tmp/foo.rb:12: in `fizzle {}'"))
+
+    info = nested_caller_info_fn
+    assert_equal(__FILE__, info[0])
+    assert_equal("test_caller_info", info[2])
+
+    info = proc {nested_caller_info_fn}.call
+    assert_equal(__FILE__, info[0])
+    assert_match(/^(block in )?test_caller_info$/, info[2])
+
+    info = double_nested_caller_info_fn
+    assert_equal(__FILE__, info[0])
+    assert_equal("double_nested_caller_info_fn", info[2])
+
+    info = proc {double_nested_caller_info_fn}.call
+    assert_equal(__FILE__, info[0])
+    assert_equal("double_nested_caller_info_fn", info[2])
+  end
+
+  def test_version_gt
+    assert_version_gt("2.0.0", "1.0.0")
+    assert_version_gt("1.1.0", "1.0.0")
+    assert_version_gt("1.0.1", "1.0.0")
+    assert_version_gt("1.0.0", "1.0.0.rc")
+    assert_version_gt("1.0.0.1", "1.0.0.rc")
+    assert_version_gt("1.0.0.rc", "0.9.9")
+    assert_version_gt("1.0.0.beta", "1.0.0.alpha")
+
+    assert_version_eq("1.0.0", "1.0.0")
+    assert_version_eq("1.0.0", "1.0.0.0")
+  end
+
+  def assert_version_gt(v1, v2)
+    #assert(version_gt(v1, v2), "Expected #{v1} > #{v2}")
+    assert(!version_gt(v2, v1), "Expected #{v2} < #{v1}")
+  end
+
+  def assert_version_eq(v1, v2)
+    assert(!version_gt(v1, v2), "Expected #{v1} = #{v2}")
+    assert(!version_gt(v2, v1), "Expected #{v2} = #{v1}")
+  end
+
+  class FooBar
+    def foo
+      Sass::Util.abstract(self)
+    end
+    def old_method
+      Sass::Util.deprecated(self)
+    end
+    def old_method_with_custom_message
+      Sass::Util.deprecated(self, "Call FooBar#new_method instead.")
+    end
+    def self.another_old_method
+      Sass::Util.deprecated(self)
+    end
+  end
+
+  def test_abstract
+    assert_raise_message(NotImplementedError,
+      "UtilTest::FooBar must implement #foo") {FooBar.new.foo}
+  end
+
+  def test_deprecated
+    assert_warning("DEPRECATION WARNING: UtilTest::FooBar#old_method will be removed in a future version of 
Sass.") { FooBar.new.old_method }
+    assert_warning(<<WARNING) { FooBar.new.old_method_with_custom_message }
+DEPRECATION WARNING: UtilTest::FooBar#old_method_with_custom_message will be removed in a future version of 
Sass.
+Call FooBar#new_method instead.
+WARNING
+    assert_warning("DEPRECATION WARNING: UtilTest::FooBar.another_old_method will be removed in a future 
version of Sass.") { FooBar.another_old_method }
+  end
+
+  def test_json_escape_string
+    assert_json_string "", ""
+    alphanum = (("0".."9").to_a).concat(("a".."z").to_a).concat(("A".."Z").to_a).join
+    assert_json_string alphanum, alphanum
+    assert_json_string "'\"\\'", "'\\\"\\\\'"
+    assert_json_string "\b\f\n\r\t", "\\b\\f\\n\\r\\t"
+  end
+
+  def assert_json_string(source, target)
+    assert_equal target, json_escape_string(source)
+  end
+
+  def test_json_value_of
+    assert_json_value 0, "0"
+    assert_json_value(-42, "-42")
+    assert_json_value 42, "42"
+    assert_json_value true, "true"
+    assert_json_value false, "false"
+    assert_json_value "", "\"\""
+    assert_json_value "\"\"", "\"\\\"\\\"\""
+    assert_json_value "Multi\nLine\rString", "\"Multi\\nLine\\rString\""
+    assert_json_value [1, "some\nstr,ing", false, nil], "[1,\"some\\nstr,ing\",false,null]"
+  end
+
+  def assert_json_value(source, target)
+    assert_equal target, json_value_of(source)
+  end
+
+  def test_vlq
+    assert_equal "A", encode_vlq(0)
+    assert_equal "e", encode_vlq(15)
+    assert_equal "gB", encode_vlq(16)
+    assert_equal "wH", encode_vlq(120)
+  end
+
+  def assert_vlq_encodes(int, vlq)
+    vlq_from_decimal_array = decimal_array.map {|d| encode_vlq(d)}.join
+    decimal_array_from_vlq = decode_vlq(vlq)
+    assert_equal vlq, vlq_from_decimal_array
+    assert_equal decimal_array, decimal_array_from_vlq
+  end
+
+  def test_atomic_writes
+    # when using normal writes, this test fails about 90% of the time.
+    filename = File.join(Dir.tmpdir, "test_atomic")
+    5.times do
+      writes_to_perform = %w(1 2 3 4 5 6 7 8 9).map {|i| "#{i}\n" * 100_000}
+      threads = writes_to_perform.map do |to_write|
+        Thread.new do
+          # To see this test fail with a normal write,
+          # change to the standard file open mechanism:
+          # open(filename, "w") do |f|
+          atomic_create_and_write_file(filename) do |f|
+            f.write(to_write)
+          end
+        end
+      end
+      loop do
+        contents = File.exist?(filename) ? File.read(filename) : nil
+        next if contents.nil? || contents.size == 0
+        unless writes_to_perform.include?(contents)
+          if contents.size != writes_to_perform.first.size
+            fail "Incomplete write detected: was #{contents.size} characters, " +
+                 "should have been #{writes_to_perform.first.size}"
+          else
+            fail "Corrupted read/write detected"
+          end
+        end
+        break if threads.all? {|t| !t.alive?}
+      end
+      threads.each {|t| t.join}
+    end
+  ensure
+    Sass::Util.retry_on_windows {File.delete filename if File.exist?(filename)}
+  end
+
+  def test_atomic_write_permissions
+    atomic_filename = File.join(Dir.tmpdir, "test_atomic_perms.atomic")
+    normal_filename = File.join(Dir.tmpdir, "test_atomic_perms.normal")
+    atomic_create_and_write_file(atomic_filename) {|f| f.write("whatever\n") }
+    open(normal_filename, "wb") {|f| f.write("whatever\n") }
+    assert_equal File.stat(normal_filename).mode.to_s(8), File.stat(atomic_filename).mode.to_s(8)
+  ensure
+    File.unlink(atomic_filename) rescue nil
+    File.unlink(normal_filename) rescue nil
+  end
+
+  def test_atomic_writes_respect_umask
+    atomic_filename = File.join(Dir.tmpdir, "test_atomic_perms.atomic")
+    atomic_create_and_write_file(atomic_filename) do |f|
+      f.write("whatever\n")
+    end
+    assert_equal 0, File.stat(atomic_filename).mode & File.umask
+  ensure
+    File.unlink(atomic_filename)
+  end
+
+  class FakeError < RuntimeError; end
+
+  def test_atomic_writes_handles_exceptions
+    filename = File.join(Dir.tmpdir, "test_atomic_exception")
+    FileUtils.rm_f(filename)
+    tmp_filename = nil
+    assert_raises FakeError do
+      atomic_create_and_write_file(filename) do |f|
+        tmp_filename = f.path
+        raise FakeError.new "Borken"
+      end
+    end
+    assert !File.exist?(filename)
+    assert !File.exist?(tmp_filename)
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/test/sass/value_helpers_test.rb 
b/backends/css/gems/sass-3.4.9/test/sass/value_helpers_test.rb
new file mode 100755
index 0000000..53b2290
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/sass/value_helpers_test.rb
@@ -0,0 +1,179 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../test_helper'
+
+class ValueHelpersTest < MiniTest::Test
+  include Sass::Script
+  include Sass::Script::Value::Helpers
+
+  def test_bool
+    assert_same Value::Bool::TRUE, bool(true)
+    assert_same Value::Bool::FALSE, bool(false)
+    assert_same Value::Bool::FALSE, bool(nil)
+    assert_same Value::Bool::TRUE, bool(Object.new)
+  end
+
+  def test_hex_color_with_three_digits
+    color = hex_color("F07")
+    assert_equal 255, color.red
+    assert_equal 0, color.green
+    assert_equal 119, color.blue
+    assert_equal 1, color.alpha
+  end
+
+  def test_hex_color_without_hash
+    color_without_hash = hex_color("FF007F")
+    assert_equal 255, color_without_hash.red
+    assert_equal 0, color_without_hash.green
+    assert_equal 127, color_without_hash.blue
+    assert_equal 1, color_without_hash.alpha
+  end
+
+  def test_hex_color_with_hash
+    color_with_hash = hex_color("#FF007F")
+    assert_equal 255, color_with_hash.red
+    assert_equal 0, color_with_hash.green
+    assert_equal 127, color_with_hash.blue
+    assert_equal 1, color_with_hash.alpha
+  end
+
+  def test_malformed_hex_color
+    assert_raises ArgumentError do
+      hex_color("green")
+    end
+    assert_raises ArgumentError do
+      hex_color("#abcd")
+    end
+  end
+
+
+  def test_hex_color_with_alpha
+    color_with_alpha = hex_color("FF007F", 0.5)
+    assert_equal 0.5, color_with_alpha.alpha
+  end
+
+  def test_hex_color_alpha_clamps_0_to_1
+    assert_equal 1, hex_color("FF007F", 50).alpha
+  end
+
+  def test_hsl_color_without_alpha
+    no_alpha = hsl_color(1, 0.5, 1)
+    assert_equal 1, no_alpha.hue
+    assert_equal 0.5, no_alpha.saturation
+    assert_equal 1, no_alpha.lightness
+    assert_equal 1, no_alpha.alpha
+  end
+
+  def test_hsl_color_with_alpha
+    has_alpha = hsl_color(1, 0.5, 1, 0.5)
+    assert_equal 1, has_alpha.hue
+    assert_equal 0.5, has_alpha.saturation
+    assert_equal 1, has_alpha.lightness
+    assert_equal 0.5, has_alpha.alpha
+  end
+
+  def test_rgb_color_without_alpha
+    no_alpha = rgb_color(255, 0, 0)
+    assert_equal 255, no_alpha.red
+    assert_equal 0, no_alpha.green
+    assert_equal 0, no_alpha.blue
+    assert_equal 1, no_alpha.alpha
+  end
+
+  def test_rgb_color_with_alpha
+    has_alpha = rgb_color(255, 255, 255, 0.5)
+    assert_equal 255, has_alpha.red
+    assert_equal 255, has_alpha.green
+    assert_equal 255, has_alpha.blue
+    assert_equal 0.5, has_alpha.alpha
+  end
+
+  def test_number
+    n = number(1)
+    assert_equal 1, n.value
+    assert_equal "1", n.to_sass
+  end
+
+  def test_number_with_single_unit
+    n = number(1, "px")
+    assert_equal 1, n.value
+    assert_equal "1px", n.to_sass
+  end
+
+  def test_number_with_singal_numerator_and_denominator
+    ratio = number(1, "px/em")
+    assert_equal "1px/em", ratio.to_sass
+  end
+
+  def test_number_with_many_numerator_and_denominator_units
+    complex = number(1, "px*in/em*%")
+    assert_equal "1in*px/%*em", complex.to_sass
+  end
+
+  def test_number_with_many_numerator_and_denominator_units_with_spaces
+    complex = number(1, "px * in / em * %")
+    assert_equal "1in*px/%*em", complex.to_sass
+  end
+
+  def test_number_with_malformed_units
+    assert_raises ArgumentError do
+      number(1, "px/em/%")
+    end
+    assert_raises ArgumentError do
+      number(1, "/")
+    end
+    assert_raises ArgumentError do
+      number(1, "px/")
+    end
+  end
+
+  def test_space_list
+    l = list(number(1, "px"), hex_color("#f71"), :space)
+    l.options = {}
+    assert_kind_of Sass::Script::Value::List, l
+    assert_equal "1px #f71", l.to_sass
+  end
+
+  def test_comma_list
+    l = list(number(1, "px"), hex_color("#f71"), :comma)
+    l.options = {}
+    assert_kind_of Sass::Script::Value::List, l
+    assert_equal "1px, #f71", l.to_sass
+  end
+
+  def test_missing_list_type
+    assert_raises ArgumentError do
+      list(number(1, "px"), hex_color("#f71"))
+    end
+  end
+
+  def test_null
+    assert_kind_of Sass::Script::Value::Null, null
+  end
+
+  def test_quoted_string
+    s = quoted_string("sassy string")
+    s.options = {}
+    assert_kind_of Sass::Script::Value::String, s
+    assert_equal "sassy string", s.value
+    assert_equal :string, s.type
+    assert_equal '"sassy string"', s.to_sass
+  end
+
+  def test_identifier
+    s = identifier("a-sass-ident")
+    s.options = {}
+    assert_kind_of Sass::Script::Value::String, s
+    assert_equal "a-sass-ident", s.value
+    assert_equal :identifier, s.type
+    assert_equal "a-sass-ident", s.to_sass
+  end
+
+  def test_unquoted_string
+    s = unquoted_string("a-sass-ident")
+    s.options = {}
+    assert_kind_of Sass::Script::Value::String, s
+    assert_equal "a-sass-ident", s.value
+    assert_equal :identifier, s.type
+    assert_equal "a-sass-ident", s.to_sass
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/test/test_helper.rb 
b/backends/css/gems/sass-3.4.9/test/test_helper.rb
new file mode 100644
index 0000000..128d476
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/test/test_helper.rb
@@ -0,0 +1,109 @@
+lib_dir = File.dirname(__FILE__) + '/../lib'
+
+require 'minitest/autorun'
+require 'fileutils'
+$:.unshift lib_dir unless $:.include?(lib_dir)
+require 'sass'
+require 'mathn' if ENV['MATHN'] == 'true'
+
+Sass::RAILS_LOADED = true unless defined?(Sass::RAILS_LOADED)
+
+Sass.tests_running = true
+
+if defined?(Encoding)
+  $-w, w = false, $-w
+  Encoding.default_external = 'UTF-8'
+  $-w = w
+end
+
+module Sass::Script::Functions
+  def option(name)
+    Sass::Script::Value::String.new(@options[name.value.to_sym].to_s)
+  end
+end
+
+class MiniTest::Test
+  def munge_filename(opts = {})
+    opts[:filename] ||= filename_for_test(opts[:syntax] || :sass)
+    opts[:sourcemap_filename] ||= sourcemap_filename_for_test
+    opts
+  end
+
+  def test_name
+    caller.
+      map {|c| Sass::Util.caller_info(c)[2]}.
+      compact.
+      map {|c| c.sub(/^(block|rescue) in /, '')}.
+      find {|c| c =~ /^test_/}
+  end
+
+  def filename_for_test(syntax = :sass)
+    "#{test_name}_inline.#{syntax}"
+  end
+
+  def sourcemap_filename_for_test(syntax = :sass)
+    "#{test_name}_inline.css.map"
+  end
+
+  def clean_up_sassc
+    path = File.dirname(__FILE__) + "/../.sass-cache"
+    Sass::Util.retry_on_windows {FileUtils.rm_r(path) if File.exist?(path)}
+  end
+
+  def assert_warning(message)
+    the_real_stderr, $stderr = $stderr, StringIO.new
+    yield
+
+    if message.is_a?(Regexp)
+      assert_match message, $stderr.string.strip
+    else
+      assert_equal message.strip, $stderr.string.strip
+    end
+  ensure
+    $stderr = the_real_stderr
+  end
+
+  def assert_no_warning
+    the_real_stderr, $stderr = $stderr, StringIO.new
+    yield
+
+    assert_equal '', $stderr.string
+  ensure
+    $stderr = the_real_stderr
+  end
+
+  def silence_warnings(&block)
+    Sass::Util.silence_warnings(&block)
+  end
+
+  def assert_raise_message(klass, message)
+    yield
+  rescue Exception => e
+    assert_instance_of(klass, e)
+    assert_equal(message, e.message)
+  else
+    flunk "Expected exception #{klass}, none raised"
+  end
+
+  def assert_raise_line(line)
+    yield
+  rescue Sass::SyntaxError => e
+    assert_equal(line, e.sass_line)
+  else
+    flunk "Expected exception on line #{line}, none raised"
+  end
+end
+
+module PublicApiLinter
+  def lint_api(api_class, duck_type_class)
+    define_method :test_lint_instance do
+      assert lint_instance.is_a?(duck_type_class)
+    end
+    api_class.instance_methods.each do |meth|
+      define_method :"test_has_#{meth}" do
+        assert lint_instance.respond_to?(meth),
+          "#{duck_type_class.name} does not implement #{meth}"
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/CHANGELOG.md 
b/backends/css/gems/sass-3.4.9/vendor/listen/CHANGELOG.md
new file mode 100644
index 0000000..877461f
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/CHANGELOG.md
@@ -0,0 +1 @@
+# Moved to [Github releases](https://github.com/guard/listen/releases) page.
diff --git a/backends/css/gems/sass-3.2.12/vendor/listen/CONTRIBUTING.md 
b/backends/css/gems/sass-3.4.9/vendor/listen/CONTRIBUTING.md
similarity index 100%
rename from backends/css/gems/sass-3.2.12/vendor/listen/CONTRIBUTING.md
rename to backends/css/gems/sass-3.4.9/vendor/listen/CONTRIBUTING.md
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/Gemfile 
b/backends/css/gems/sass-3.4.9/vendor/listen/Gemfile
new file mode 100644
index 0000000..9609578
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/Gemfile
@@ -0,0 +1,20 @@
+source 'https://rubygems.org'
+
+gemspec
+
+gem 'rake'
+
+require 'rbconfig'
+gem 'wdm', '>= 0.1.0' if RbConfig::CONFIG['target_os'] =~ /mswin|mingw/i
+
+group :development do
+  gem 'guard-rspec'
+  gem 'yard'
+  gem 'redcarpet'
+  gem 'pimpmychangelog'
+end
+
+group :test do
+  gem 'rspec'
+  gem 'coveralls', :require => false
+end
diff --git a/backends/css/gems/sass-3.2.12/vendor/listen/Guardfile 
b/backends/css/gems/sass-3.4.9/vendor/listen/Guardfile
similarity index 100%
rename from backends/css/gems/sass-3.2.12/vendor/listen/Guardfile
rename to backends/css/gems/sass-3.4.9/vendor/listen/Guardfile
diff --git a/backends/css/gems/sass-3.2.12/vendor/listen/LICENSE 
b/backends/css/gems/sass-3.4.9/vendor/listen/LICENSE
similarity index 100%
rename from backends/css/gems/sass-3.2.12/vendor/listen/LICENSE
rename to backends/css/gems/sass-3.4.9/vendor/listen/LICENSE
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/README.md 
b/backends/css/gems/sass-3.4.9/vendor/listen/README.md
new file mode 100644
index 0000000..ff0ec33
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/README.md
@@ -0,0 +1,349 @@
+# Listen [![Gem Version](https://badge.fury.io/rb/listen.png)](http://badge.fury.io/rb/listen) [![Build 
Status](https://secure.travis-ci.org/guard/listen.png?branch=master)](http://travis-ci.org/guard/listen) 
[![Dependency Status](https://gemnasium.com/guard/listen.png)](https://gemnasium.com/guard/listen) [![Code 
Climate](https://codeclimate.com/github/guard/listen.png)](https://codeclimate.com/github/guard/listen) 
[![Coverage 
Status](https://coveralls.io/repos/guard/listen/badge.png?branch=master)](https://coveralls.io/r/guard/listen)
+
+The Listen gem listens to file modifications and notifies you about the changes.
+
+## Features
+
+* Works everywhere!
+* Supports watching multiple directories from a single listener.
+* OS-specific adapters for Mac OS X 10.6+, Linux, *BSD and Windows.
+* Automatic fallback to polling if OS-specific adapter doesn't work.
+* Detects file modification, addition and removal.
+* File content checksum comparison for modifications made under the same second.
+* Allows supplying regexp-patterns to ignore and filter paths for better results.
+* Tested on all Ruby environments via [Travis CI](https://travis-ci.org/guard/listen).
+
+## Pending features
+
+Still not implemented, pull requests are welcome.
+
+* Symlinks support. [#25](https://github.com/guard/listen/issues/25)
+* Signal handling. [#105](https://github.com/guard/listen/issues/105)
+* Non-recursive directory scanning. [#111](https://github.com/guard/listen/issues/111)
+
+## Install
+
+### Using Bundler
+
+The simplest way to install Listen is to use Bundler.
+
+Add Listen to your Gemfile:
+
+```ruby
+group :development do
+  gem 'listen'
+end
+```
+
+and install it by running Bundler:
+
+```bash
+$ bundle
+```
+
+### Install the gem with RubyGems
+
+```bash
+$ gem install listen
+```
+
+### On Windows
+
+If your are on Windows and using Ruby MRI >= 1.9.2 you can try to use the 
[`wdm`](https://github.com/Maher4Ever/wdm) instead of polling.
+Please add the following to your Gemfile:
+
+```ruby
+require 'rbconfig'
+gem 'wdm', '>= 0.1.0' if RbConfig::CONFIG['target_os'] =~ /mswin|mingw/i
+```
+
+## Usage
+
+There are **two ways** to use Listen:
+
+1. Block API: Call `Listen.to`/`Listen.to!` with either a single directory or multiple directories, then 
define the `change` callback in a block.
+2. "Object" API: Create a `listener` object and use it in a chainable way.
+
+### Block API
+
+``` ruby
+# Listen to a single directory.
+Listen.to('dir/path/to/listen', :filter => /\.rb$/, :ignore => %r{ignored/path/}) do |modified, added, 
removed|
+  # ...
+end
+
+# Listen to multiple directories.
+Listen.to('dir/to/awesome_app', 'dir/to/other_app', :filter => /\.rb$/, :latency => 0.1) do |modified, 
added, removed|
+  # ...
+end
+```
+
+### "Object" API
+
+``` ruby
+listener = Listen.to('dir/path/to/listen')
+listener = listener.ignore(%r{^ignored/path/})
+listener = listener.filter(/\.rb$/)
+listener = listener.latency(0.5)
+listener = listener.force_polling(true)
+listener = listener.polling_fallback_message(false)
+listener = listener.force_adapter(Listen::Adapters::Linux)
+listener = listener.change(&callback)
+listener.start
+```
+
+**Note**: All the "Object" API methods except `start`/`start!` return the listener
+and are thus chainable:
+
+``` ruby
+Listen.to('dir/path/to/listen')
+      .ignore(%r{^ignored/path/})
+      .filter(/\.rb$/)
+      .latency(0.5)
+      .force_polling(true)
+      .polling_fallback_message('custom message')
+      .change(&callback)
+      .start
+```
+
+### Pause/Unpause
+
+Listener can also easily be paused/unpaused:
+
+``` ruby
+listener = Listen.to('dir/path/to/listen')
+listener.start   # non-blocking mode
+listener.pause   # stop listening to changes
+listener.paused? # => true
+listener.unpause # start listening to changes again
+listener.stop    # stop completely the listener
+```
+
+## Changes callback
+
+Changes to the listened-to directories gets reported back to the user in a callback.
+The registered callback gets invoked, when there are changes, with **three** parameters:
+`modified_paths`, `added_paths` and `removed_paths` in that particular order.
+
+You can register a callback in two ways. The first way is by passing a block when calling
+the `Listen.to`/`Listen.to!` method or when initializing a listener object:
+
+```ruby
+Listen.to('path/to/app') do |modified, added, removed|
+  # This block will be called when there are changes.
+end
+
+# or ...
+
+listener = Listen::Listener.new('path/to/app') do |modified, added, removed|
+  # This block will be called when there are changes.
+end
+
+```
+
+The second way to register a callback is by calling the `#change` method on a
+listener passing it a block:
+
+```ruby
+# Create a callback
+callback = Proc.new do |modified, added, removed|
+  # This proc will be called when there are changes.
+end
+
+listener = Listen.to('dir')
+listener.change(&callback) # convert the callback to a block and register it
+
+listener.start
+```
+
+### Paths in callbacks
+
+Listeners invoke callbacks passing them absolute paths by default:
+
+```ruby
+# Assume someone changes the 'style.css' file in '/home/user/app/css' after creating
+# the listener.
+Listen.to('/home/user/app/css') do |modified, added, removed|
+  modified.inspect # => ['/home/user/app/css/style.css']
+end
+```
+
+#### Relative paths in callbacks
+
+When creating a listener for a **single** path (more specifically a `Listen::Listener` instance),
+you can pass `:relative_paths => true` as an option to get relative paths in
+your callback:
+
+```ruby
+# Assume someone changes the 'style.css' file in '/home/user/app/css' after creating
+# the listener.
+Listen.to('/home/user/app/css', :relative_paths => true) do |modified, added, removed|
+  modified.inspect # => ['style.css']
+end
+```
+
+Passing the `:relative_paths => true` option won't work when listening to multiple
+directories:
+
+```ruby
+# Assume someone changes the 'style.css' file in '/home/user/app/css' after creating
+# the listener.
+Listen.to('/home/user/app/css', '/home/user/app/js', :relative_paths => true) do |modified, added, removed|
+  modified.inspect # => ['/home/user/app/css/style.css']
+end
+```
+
+## Options
+
+All the following options can be set through the `Listen.to`/`Listen.to!` params
+or via ["Object" API](#object-api) methods:
+
+```ruby
+:ignore => %r{app/CMake/}, /\.pid$/           # Ignore a list of paths (root directory or sub-dir)
+                                              # default: See DEFAULT_IGNORED_DIRECTORIES and 
DEFAULT_IGNORED_EXTENSIONS in Listen::DirectoryRecord
+
+:filter => /\.rb$/, /\.coffee$/               # Filter files to listen to via a regexps list.
+                                              # default: none
+
+:latency => 0.5                               # Set the delay (**in seconds**) between checking for changes
+                                              # default: 0.25 sec (1.0 sec for polling)
+
+:force_adapter => Listen::Adapters::Linux     # Force the use of a particular adapter class
+                                              # default: none
+
+:force_polling => true                        # Force the use of the polling adapter
+                                              # default: none
+
+:polling_fallback_message => 'custom message' # Set a custom polling fallback message (or disable it with 
false)
+                                              # default: "Listen will be polling for changes. Learn more at 
https://github.com/guard/listen#polling-fallback.";
+
+:relative_paths => true                       # Enable the use of relative paths in the callback.
+                                              # default: false
+```
+
+### Note on the patterns for ignoring and filtering paths
+
+Just like the unix convention of beginning absolute paths with the
+directory-separator (forward slash `/` in unix) and with no prefix for relative paths,
+Listen doesn't prefix relative paths (to the watched directory) with a directory-separator.
+
+Therefore make sure _NOT_ to prefix your regexp-patterns for filtering or ignoring paths
+with a directory-separator, otherwise they won't work as expected.
+
+As an example: to ignore the `build` directory in a C-project, use `%r{build/}`
+and not `%r{/build/}`.
+
+Use `#filter!` and `#ignore!` methods to overwrites default patterns.
+
+## Blocking listening to changes
+
+Calling `Listen.to` with a block doesn't block the current thread. If you want
+to block the current thread instead until the listener is stopped (which needs
+to be done from another thread), you can use `Listen.to!`.
+
+Similarly, if you're using the "Object" API, you can use `#start!` instead of `#start` to block the
+current thread until the listener is stopped.
+
+Here is an example of using a listener in the blocking mode:
+
+```ruby
+Listen.to!('dir/path/to/listen') # block execution
+
+# Code here will not run until the listener is stopped
+
+```
+
+Here is an example of using a listener started with the "Object" API in blocking mode:
+
+```ruby
+listener = Listen.to('dir/path/to/listen')
+listener.start! # block execution
+
+# Code here will not run until the listener is stopped
+
+```
+
+**Note**: Using the `Listen.to!` helper-method with or without a callback-block
+will always start the listener right away and block execution of the current thread.
+
+## Listen adapters
+
+The Listen gem has a set of adapters to notify it when there are changes.
+There are 4 OS-specific adapters to support Mac, Linux, *BSD and Windows.
+These adapters are fast as they use some system-calls to implement the notifying function.
+
+There is also a polling adapter which is a cross-platform adapter and it will
+work on any system. This adapter is unfortunately slower than the rest of the adapters.
+
+The Listen gem will choose the best and working adapter for your machine automatically. If you
+want to force the use of the polling adapter, either use the `:force_polling` option
+while initializing the listener or call the `#force_polling` method on your listener
+before starting it.
+
+It is also possible to force the use of a particular adapter, by using the `:force_adapter`
+option.  This option skips the usual adapter choosing mechanism and uses the given
+adapter class instead.  The adapter choosing mechanism requires write permission
+to your watched directories and will needlessly load code, which isn't always desirable.
+
+## Polling fallback
+
+When a OS-specific adapter doesn't work the Listen gem automatically falls back to the polling adapter.
+Here are some things you could try to avoid the polling fallback:
+
+* [Update your Dropbox client](http://www.dropbox.com/downloading) (if used).
+* Increase latency. (Please [open an issue](https://github.com/guard/listen/issues/new)
+if you think that default is too low.)
+* Move or rename the listened folder.
+* Update/reboot your OS.
+
+If your application keeps using the polling-adapter and you can't figure out why, feel free to [open an 
issue](https://github.com/guard/listen/issues/new) (and be sure to [give all the 
details](https://github.com/guard/listen/blob/master/CONTRIBUTING.md)).
+
+## Development [![Dependency 
Status](https://gemnasium.com/guard/listen.png?branch=master)](https://gemnasium.com/guard/listen)
+
+* Documentation hosted at [RubyDoc](http://rubydoc.info/github/guard/listen/master/frames).
+* Source hosted at [GitHub](https://github.com/guard/listen).
+
+Pull requests are very welcome! Please try to follow these simple rules if applicable:
+
+* Please create a topic branch for every separate change you make.
+* Make sure your patches are well tested. All specs must pass on [Travis 
CI](https://travis-ci.org/guard/listen).
+* Update the [Yard](http://yardoc.org/) documentation.
+* Update the [README](https://github.com/guard/listen/blob/master/README.md).
+* Update the [CHANGELOG](https://github.com/guard/listen/blob/master/CHANGELOG.md) for noteworthy changes 
(don't forget to run `bundle exec pimpmychangelog` and watch the magic happen)!
+* Please **do not change** the version number.
+
+For questions please join us in our [Google group](http://groups.google.com/group/guard-dev) or on
+`#guard` (irc.freenode.net).
+
+## Acknowledgments
+
+* [Michael Kessler (netzpirat)][] for having written the [initial 
specs](https://github.com/guard/listen/commit/1e457b13b1bb8a25d2240428ce5ed488bafbed1f).
+* [Travis Tilley (ttilley)][] for this awesome work on [fssm][] & [rb-fsevent][].
+* [Nathan Weizenbaum (nex3)][] for [rb-inotify][], a thorough inotify wrapper.
+* [Mathieu Arnold (mat813)][] for [rb-kqueue][], a simple kqueue wrapper.
+* [stereobooster][] for [rb-fchange][], windows support wouldn't exist without him.
+* [Yehuda Katz (wycats)][] for [vigilo][], that has been a great source of inspiration.
+
+## Authors
+
+* [Thibaud Guillaume-Gentil][] ([ thibaudgg](http://twitter.com/thibaudgg))
+* [Maher Sallam][] ([ mahersalam](http://twitter.com/mahersalam))
+
+## Contributors
+
+[https://github.com/guard/listen/contributors](https://github.com/guard/listen/contributors)
+
+[Thibaud Guillaume-Gentil]: https://github.com/thibaudgg
+[Maher Sallam]: https://github.com/Maher4Ever
+[Michael Kessler (netzpirat)]: https://github.com/netzpirat
+[Travis Tilley (ttilley)]: https://github.com/ttilley
+[fssm]: https://github.com/ttilley/fssm
+[rb-fsevent]: https://github.com/thibaudgg/rb-fsevent
+[Mathieu Arnold (mat813)]: https://github.com/mat813
+[Nathan Weizenbaum (nex3)]: https://github.com/nex3
+[rb-inotify]: https://github.com/nex3/rb-inotify
+[stereobooster]: https://github.com/stereobooster
+[rb-fchange]: https://github.com/stereobooster/rb-fchange
+[rb-kqueue]: https://github.com/mat813/rb-kqueue
+[Yehuda Katz (wycats)]: https://github.com/wycats
+[vigilo]: https://github.com/wycats/vigilo
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/Rakefile 
b/backends/css/gems/sass-3.4.9/vendor/listen/Rakefile
new file mode 100644
index 0000000..87da91c
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/Rakefile
@@ -0,0 +1,5 @@
+require 'bundler/gem_tasks'
+require 'rspec/core/rake_task'
+
+RSpec::Core::RakeTask.new(:spec)
+task :default => :spec
diff --git a/backends/css/gems/sass-3.2.12/vendor/listen/Vagrantfile 
b/backends/css/gems/sass-3.4.9/vendor/listen/Vagrantfile
similarity index 100%
rename from backends/css/gems/sass-3.2.12/vendor/listen/Vagrantfile
rename to backends/css/gems/sass-3.4.9/vendor/listen/Vagrantfile
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen.rb
new file mode 100644
index 0000000..9b3fdf2
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen.rb
@@ -0,0 +1,54 @@
+require 'listen/turnstile'
+require 'listen/listener'
+require 'listen/directory_record'
+require 'listen/adapter'
+
+module Listen
+
+  module Adapters
+    Adapter::ADAPTERS.each do |adapter|
+      require "listen/adapters/#{adapter.downcase}"
+    end
+  end
+
+  # Listens to file system modifications on a either single directory or multiple directories.
+  # When calling this method, the current thread is not blocked.
+  #
+  # @param (see Listen::Listener#new)
+  #
+  # @yield [modified, added, removed] the changed files
+  # @yieldparam [Array<String>] modified the list of modified files
+  # @yieldparam [Array<String>] added the list of added files
+  # @yieldparam [Array<String>] removed the list of removed files
+  #
+  # @return [Listen::Listener] the file listener if no block given
+  #
+  def self.to(*args, &block)
+    listener = _init_listener(*args, &block)
+
+    block ? listener.start : listener
+  end
+
+  # Listens to file system modifications on a either single directory or multiple directories.
+  # When calling this method, the current thread is blocked.
+  #
+  # @param (see Listen::Listener#new)
+  #
+  # @yield [modified, added, removed] the changed files
+  # @yieldparam [Array<String>] modified the list of modified files
+  # @yieldparam [Array<String>] added the list of added files
+  # @yieldparam [Array<String>] removed the list of removed files
+  #
+  # @since 1.0.0
+  #
+  def self.to!(*args, &block)
+    _init_listener(*args, &block).start!
+  end
+
+  # @private
+  #
+  def self._init_listener(*args, &block)
+    Listener.new(*args, &block)
+  end
+
+end
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapter.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapter.rb
new file mode 100644
index 0000000..4a0abec
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapter.rb
@@ -0,0 +1,327 @@
+require 'rbconfig'
+require 'thread'
+require 'set'
+require 'fileutils'
+
+module Listen
+  class Adapter
+    attr_accessor :directories, :callback, :stopped, :paused,
+                  :mutex, :changed_directories, :turnstile, :latency,
+                  :worker, :worker_thread, :poller_thread
+
+    # The list of existing optimized adapters.
+    OPTIMIZED_ADAPTERS = %w[Darwin Linux BSD Windows]
+
+    # The list of existing fallback adapters.
+    FALLBACK_ADAPTERS = %w[Polling]
+
+    # The list of all existing adapters.
+    ADAPTERS = OPTIMIZED_ADAPTERS + FALLBACK_ADAPTERS
+
+    # The default delay between checking for changes.
+    DEFAULT_LATENCY = 0.25
+
+    # The default warning message when falling back to polling adapter.
+    POLLING_FALLBACK_MESSAGE = <<-EOS.gsub(/^\s*/, '')
+      Listen will be polling for changes. Learn more at https://github.com/guard/listen#polling-fallback.
+    EOS
+
+    # Selects the appropriate adapter implementation for the
+    # current OS and initializes it.
+    #
+    # @param [String, Array<String>] directories the directories to watch
+    # @param [Hash] options the adapter options
+    # @option options [Boolean] force_polling to force polling or not
+    # @option options [String, Boolean] polling_fallback_message to change polling fallback message or 
remove it
+    # @option options [Float] latency the delay between checking for changes in seconds
+    #
+    # @yield [changed_directories, options] callback the callback called when a change happens
+    # @yieldparam [Array<String>] changed_directories the changed directories
+    # @yieldparam [Hash] options callback options (like recursive: true)
+    #
+    # @return [Listen::Adapter] the chosen adapter
+    #
+    def self.select_and_initialize(directories, options = {}, &callback)
+      forced_adapter_class = options.delete(:force_adapter)
+      force_polling = options.delete(:force_polling)
+
+      if forced_adapter_class
+        forced_adapter_class.load_dependent_adapter
+        return forced_adapter_class.new(directories, options, &callback)
+      end
+
+      return Adapters::Polling.new(directories, options, &callback) if force_polling
+
+      OPTIMIZED_ADAPTERS.each do |adapter|
+        namespaced_adapter = Adapters.const_get(adapter)
+        if namespaced_adapter.send(:usable_and_works?, directories, options)
+          return namespaced_adapter.new(directories, options, &callback)
+        end
+      end
+
+      self.warn_polling_fallback(options)
+      Adapters::Polling.new(directories, options, &callback)
+    end
+
+    # Initializes the adapter.
+    #
+    # @param [String, Array<String>] directories the directories to watch
+    # @param [Hash] options the adapter options
+    # @option options [Float] latency the delay between checking for changes in seconds
+    #
+    # @yield [changed_directories, options] callback Callback called when a change happens
+    # @yieldparam [Array<String>] changed_directories the changed directories
+    # @yieldparam [Hash] options callback options (like recursive: true)
+    #
+    # @return [Listen::Adapter] the adapter
+    #
+    def initialize(directories, options = {}, &callback)
+      @directories         = Array(directories)
+      @callback            = callback
+      @stopped             = true
+      @paused              = false
+      @mutex               = Mutex.new
+      @changed_directories = Set.new
+      @turnstile           = Turnstile.new
+      @latency             = options.fetch(:latency, default_latency)
+      @worker              = initialize_worker
+    end
+
+    # Starts the adapter and don't block the current thread.
+    #
+    # @param [Boolean] blocking whether or not to block the current thread after starting
+    #
+    def start
+      mutex.synchronize do
+        return unless stopped
+        @stopped = false
+      end
+
+      start_worker
+      start_poller
+    end
+
+    # Starts the adapter and block the current thread.
+    #
+    # @since 1.0.0
+    #
+    def start!
+      start
+      blocking_thread.join
+    end
+
+    # Stops the adapter.
+    #
+    def stop
+      mutex.synchronize do
+        return if stopped
+        @stopped = true
+        turnstile.signal # ensure no thread is blocked
+      end
+
+      worker.stop if worker
+      Thread.kill(worker_thread) if worker_thread
+      if poller_thread
+        poller_thread.kill
+        poller_thread.join
+      end
+    end
+
+    # Pauses the adapter.
+    #
+    def pause
+      @paused = true
+    end
+
+    # Unpauses the adapter.
+    #
+    def unpause
+      @paused = false
+    end
+
+    # Returns whether the adapter is started or not.
+    #
+    # @return [Boolean] whether the adapter is started or not
+    #
+    def started?
+      !stopped
+    end
+
+    # Returns whether the adapter is paused or not.
+    #
+    # @return [Boolean] whether the adapter is paused or not
+    #
+    def paused?
+      paused
+    end
+
+    # Blocks the main thread until the poll thread
+    # runs the callback.
+    #
+    def wait_for_callback
+      turnstile.wait unless paused
+    end
+
+    # Blocks the main thread until N changes are
+    # detected.
+    #
+    def wait_for_changes(threshold = 0)
+      changes = 0
+
+      loop do
+        mutex.synchronize { changes = changed_directories.size }
+
+        return if paused || stopped
+        return if changes >= threshold
+
+        sleep(latency)
+      end
+    end
+
+    # Checks if the adapter is usable and works on the current OS.
+    #
+    # @param [String, Array<String>] directories the directories to watch
+    # @param [Hash] options the adapter options
+    # @option options [Float] latency the delay between checking for changes in seconds
+    #
+    # @return [Boolean] whether the adapter is usable and work or not
+    #
+    def self.usable_and_works?(directories, options = {})
+      usable? && Array(directories).all? { |d| works?(d, options) }
+    end
+
+    # Checks if the adapter is usable on target OS.
+    #
+    # @return [Boolean] whether usable or not
+    #
+    def self.usable?
+      load_dependent_adapter if RbConfig::CONFIG['target_os'] =~ target_os_regex
+    end
+
+    # Load the adapter gem
+    #
+    # @return [Boolean] whether loaded or not
+    #
+    def self.load_dependent_adapter
+      return true if @loaded
+      require adapter_gem
+      return @loaded = true
+    rescue LoadError
+      false
+    end
+
+    # Runs a tests to determine if the adapter can actually pick up
+    # changes in a given directory and returns the result.
+    #
+    # @note This test takes some time depending on the adapter latency.
+    #
+    # @param [String, Pathname] directory the directory to watch
+    # @param [Hash] options the adapter options
+    # @option options [Float] latency the delay between checking for changes in seconds
+    #
+    # @return [Boolean] whether the adapter works or not
+    #
+    def self.works?(directory, options = {})
+      work      = false
+      test_file = "#{directory}/.listen_test"
+      callback  = lambda { |*| work = true }
+      adapter   = self.new(directory, options, &callback)
+      adapter.start
+
+      FileUtils.touch(test_file)
+
+      t = Thread.new { sleep(adapter.latency * 5); adapter.stop }
+
+      adapter.wait_for_callback
+      work
+    ensure
+      Thread.kill(t) if t
+      FileUtils.rm(test_file, :force => true)
+      adapter.stop if adapter && adapter.started?
+    end
+
+    # Runs the callback and passes it the changes if there are any.
+    #
+    def report_changes
+      changed_dirs = nil
+
+      mutex.synchronize do
+        return if @changed_directories.empty?
+        changed_dirs = @changed_directories.to_a
+        @changed_directories.clear
+      end
+
+      callback.call(changed_dirs, {})
+      turnstile.signal
+    end
+
+    private
+
+    # The default delay between checking for changes.
+    #
+    # @note This method can be overriden on a per-adapter basis.
+    #
+    def default_latency
+      DEFAULT_LATENCY
+    end
+
+    # The thread on which the main thread should wait
+    # when the adapter has been started in blocking mode.
+    #
+    # @note This method can be overriden on a per-adapter basis.
+    #
+    def blocking_thread
+      worker_thread
+    end
+
+    # Initialize the adpater' specific worker.
+    #
+    # @note Each adapter must override this method
+    #   to initialize its own @worker.
+    #
+    def initialize_worker
+      nil
+    end
+
+    # Should start the worker in a new thread.
+    #
+    # @note Each adapter must override this method
+    #   to start its worker on a new @worker_thread thread.
+    #
+    def start_worker
+      raise NotImplementedError, "#{self.class} cannot respond to: #{__method__}"
+    end
+
+    # This method starts a new thread which poll for changes detected by
+    # the adapter and report them back to the user.
+    #
+    def start_poller
+      @poller_thread = Thread.new { poll_changed_directories }
+    end
+
+    # Warn of polling fallback unless the :polling_fallback_message
+    # has been set to false.
+    #
+    # @param [String] warning an existing warning message
+    # @param [Hash] options the adapter options
+    # @option options [Boolean] polling_fallback_message to change polling fallback message or remove it
+    #
+    def self.warn_polling_fallback(options)
+      return if options[:polling_fallback_message] == false
+
+      warning = options[:polling_fallback_message] || POLLING_FALLBACK_MESSAGE
+      Kernel.warn "[Listen warning]:\n#{warning.gsub(/^(.*)/, '  \1')}"
+    end
+
+    # Polls changed directories and reports them back when there are changes.
+    #
+    # @note This method can be overriden on a per-adapter basis.
+    #
+    def poll_changed_directories
+      until stopped
+        sleep(latency)
+        report_changes
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapters/bsd.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapters/bsd.rb
new file mode 100644
index 0000000..743c8ea
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapters/bsd.rb
@@ -0,0 +1,75 @@
+module Listen
+  module Adapters
+
+    # Listener implementation for BSD's `kqueue`.
+    #
+    class BSD < Adapter
+      # Watched kqueue events
+      #
+      # @see http://www.freebsd.org/cgi/man.cgi?query=kqueue
+      # @see https://github.com/nex3/rb-kqueue/blob/master/lib/rb-kqueue/queue.rb
+      #
+      EVENTS = [:delete, :write, :extend, :attrib, :link, :rename, :revoke]
+
+      def self.target_os_regex; /freebsd/i; end
+      def self.adapter_gem; 'rb-kqueue'; end
+
+      private
+
+      # Initializes a kqueue Queue and adds a watcher for each files in
+      # the directories passed to the adapter.
+      #
+      # @return [INotify::Notifier] initialized kqueue
+      #
+      # @see Listen::Adapter#initialize_worker
+      #
+      def initialize_worker
+        require 'find'
+
+        callback = lambda do |event|
+          path = event.watcher.path
+          mutex.synchronize do
+            # kqueue watches everything, but Listen only needs the
+            # directory where stuffs happens.
+            @changed_directories << (File.directory?(path) ? path : File.dirname(path))
+
+            # If it is a directory, and it has a write flag, it means a
+            # file has been added so find out which and deal with it.
+            # No need to check for removed files, kqueue will forget them
+            # when the vfs does.
+            if File.directory?(path) && event.flags.include?(:write)
+              queue = event.watcher.queue
+              Find.find(path) do |file|
+                unless queue.watchers.detect { |k,v| v.path == file.to_s }
+                  queue.watch_file(file, *EVENTS, &callback)
+                end
+              end
+            end
+          end
+        end
+
+        KQueue::Queue.new.tap do |queue|
+          directories.each do |directory|
+            Find.find(directory) do |path|
+              queue.watch_file(path, *EVENTS, &callback)
+            end
+          end
+        end
+      end
+
+      # Starts the worker in a new thread.
+      #
+      # @see Listen::Adapter#start_worker
+      #
+      def start_worker
+        @worker_thread = Thread.new do
+          until stopped
+            worker.poll
+            sleep(latency)
+          end
+        end
+      end
+    end
+
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapters/darwin.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapters/darwin.rb
new file mode 100644
index 0000000..ad0a955
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapters/darwin.rb
@@ -0,0 +1,48 @@
+module Listen
+  module Adapters
+
+    # Adapter implementation for Mac OS X `FSEvents`.
+    #
+    class Darwin < Adapter
+      LAST_SEPARATOR_REGEX = /\/$/
+
+
+      def self.target_os_regex; /darwin(1.+)?$/i; end
+      def self.adapter_gem; 'rb-fsevent'; end
+
+      private
+
+      # Initializes a FSEvent worker and adds a watcher for
+      # each directory passed to the adapter.
+      #
+      # @return [FSEvent] initialized worker
+      #
+      # @see Listen::Adapter#initialize_worker
+      #
+      def initialize_worker
+        FSEvent.new.tap do |worker|
+          worker.watch(directories.dup, :latency => latency) do |changes|
+            next if paused
+
+            mutex.synchronize do
+              changes.each { |path| @changed_directories << path.sub(LAST_SEPARATOR_REGEX, '') }
+            end
+          end
+        end
+      end
+
+      # Starts the worker in a new thread and sleep 0.1 second.
+      #
+      # @see Listen::Adapter#start_worker
+      #
+      def start_worker
+        @worker_thread = Thread.new { worker.run }
+        # The FSEvent worker needs some time to start up. Turnstiles can't
+        # be used to wait for it as it runs in a loop.
+        # TODO: Find a better way to block until the worker starts.
+        sleep 0.1
+      end
+    end
+
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapters/linux.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapters/linux.rb
new file mode 100644
index 0000000..b926465
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapters/linux.rb
@@ -0,0 +1,81 @@
+module Listen
+  module Adapters
+
+    # Listener implementation for Linux `inotify`.
+    #
+    class Linux < Adapter
+      # Watched inotify events
+      #
+      # @see http://www.tin.org/bin/man.cgi?section=7&topic=inotify
+      # @see https://github.com/nex3/rb-inotify/blob/master/lib/rb-inotify/notifier.rb#L99-L177
+      #
+      EVENTS = [:recursive, :attrib, :create, :delete, :move, :close_write]
+
+      # The message to show when the limit of inotify watchers is not enough
+      #
+      INOTIFY_LIMIT_MESSAGE = <<-EOS.gsub(/^\s*/, '')
+        Listen error: unable to monitor directories for changes.
+
+        Please head to https://github.com/guard/listen/wiki/Increasing-the-amount-of-inotify-watchers
+        for information on how to solve this issue.
+      EOS
+
+      def self.target_os_regex; /linux/i; end
+      def self.adapter_gem; 'rb-inotify'; end
+
+      # Initializes the Adapter.
+      #
+      # @see Listen::Adapter#initialize
+      #
+      def initialize(directories, options = {}, &callback)
+        super
+      rescue Errno::ENOSPC
+        abort(INOTIFY_LIMIT_MESSAGE)
+      end
+
+      private
+
+      # Initializes a INotify worker and adds a watcher for
+      # each directory passed to the adapter.
+      #
+      # @return [INotify::Notifier] initialized worker
+      #
+      # @see Listen::Adapter#initialize_worker
+      #
+      def initialize_worker
+        callback = lambda do |event|
+          if paused || (
+            # Event on root directory
+            event.name == ""
+          ) || (
+            # INotify reports changes to files inside directories as events
+            # on the directories themselves too.
+            #
+            # @see http://linux.die.net/man/7/inotify
+            event.flags.include?(:isdir) and (event.flags & [:close, :modify]).any?
+          )
+            # Skip all of these!
+            next
+          end
+
+          mutex.synchronize do
+            @changed_directories << File.dirname(event.absolute_name)
+          end
+        end
+
+        INotify::Notifier.new.tap do |worker|
+          directories.each { |dir| worker.watch(dir, *EVENTS, &callback) }
+        end
+      end
+
+      # Starts the worker in a new thread.
+      #
+      # @see Listen::Adapter#start_worker
+      #
+      def start_worker
+        @worker_thread = Thread.new { worker.run }
+      end
+    end
+
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapters/polling.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapters/polling.rb
new file mode 100644
index 0000000..77b6525
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapters/polling.rb
@@ -0,0 +1,58 @@
+module Listen
+  module Adapters
+
+    DEFAULT_POLLING_LATENCY = 1.0
+
+    # Polling Adapter that works cross-platform and
+    # has no dependencies. This is the adapter that
+    # uses the most CPU processing power and has higher
+    # file IO than the other implementations.
+    #
+    class Polling < Adapter
+      private
+
+      # The default delay between checking for changes.
+      #
+      # @see Listen::Adapter#default_latency
+      #
+      def default_latency
+        1.0
+      end
+
+      # The thread on which the main thread should wait
+      # when the adapter has been started in blocking mode.
+      #
+      # @see Listen::Adapter#blocking_thread
+      #
+      def blocking_thread
+        poller_thread
+      end
+
+      # @see Listen::Adapter#start_worker
+      #
+      # @see Listen::Adapter#start_worker
+      #
+      def start_worker
+        # The polling adapter has no worker! Sad panda! :'(
+      end
+
+      # Poll listener directory for file system changes.
+      #
+      # @see Listen::Adapter#poll_changed_directories
+      #
+      def poll_changed_directories
+        until stopped
+          next if paused
+
+          start = Time.now.to_f
+          callback.call(directories.dup, :recursive => true)
+          turnstile.signal
+          nap_time = latency - (Time.now.to_f - start)
+          sleep(nap_time) if nap_time > 0
+        end
+      rescue Interrupt
+      end
+    end
+
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapters/windows.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapters/windows.rb
new file mode 100644
index 0000000..3c470bf
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/adapters/windows.rb
@@ -0,0 +1,91 @@
+require 'set'
+require 'rubygems'
+
+module Listen
+  module Adapters
+
+    # Adapter implementation for Windows `wdm`.
+    #
+    class Windows < Adapter
+
+      BUNDLER_DECLARE_GEM = <<-EOS.gsub(/^ {6}/, '')
+        Please add the following to your Gemfile to avoid polling for changes:
+          require 'rbconfig'
+          gem 'wdm', '>= 0.1.0' if RbConfig::CONFIG['target_os'] =~ /mswin|mingw/i
+      EOS
+
+      def self.target_os_regex; /mswin|mingw/i; end
+      def self.adapter_gem; 'wdm'; end
+
+      # Checks if the adapter is usable on target OS.
+      #
+      # @return [Boolean] whether usable or not
+      #
+      def self.usable?
+        super if mri? && at_least_ruby_1_9?
+      end
+
+      # Load the adapter gem
+      #
+      # @return [Boolean] whether required or not
+      #
+      def self.load_dependent_adapter
+        super
+      rescue Gem::LoadError
+        Kernel.warn BUNDLER_DECLARE_GEM
+      end
+
+      private
+
+      # Checks if Ruby engine is MRI.
+      #
+      # @return [Boolean]
+      #
+      def self.mri?
+        defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby'
+      end
+
+      # Checks if Ruby engine is MRI.
+      #
+      # @return [Boolean]
+      #
+      def self.at_least_ruby_1_9?
+        Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('1.9.2')
+      end
+
+      # Initializes a WDM monitor and adds a watcher for
+      # each directory passed to the adapter.
+      #
+      # @return [WDM::Monitor] initialized worker
+      #
+      # @see Listen::Adapter#initialize_worker
+      #
+      def initialize_worker
+        callback = Proc.new do |change|
+          next if paused
+
+          mutex.synchronize do
+            @changed_directories << File.dirname(change.path)
+          end
+        end
+
+        WDM::Monitor.new.tap do |worker|
+          directories.each { |dir| worker.watch_recursively(dir, &callback) }
+        end
+      end
+
+      # Start the worker in a new thread and sleep 0.1 second.
+      #
+      # @see Listen::Adapter#start_worker
+      #
+      def start_worker
+        @worker_thread = Thread.new { worker.run! }
+        # Wait for the worker to start. This is needed to avoid a deadlock
+        # when stopping immediately after starting.
+        sleep 0.1
+      end
+
+    end
+
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/directory_record.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/directory_record.rb
new file mode 100644
index 0000000..3729d51
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/directory_record.rb
@@ -0,0 +1,406 @@
+require 'set'
+require 'find'
+require 'digest/sha1'
+
+module Listen
+
+  # The directory record stores information about
+  # a directory and keeps track of changes to
+  # the structure of its childs.
+  #
+  class DirectoryRecord
+    attr_reader :directory, :paths, :sha1_checksums
+
+    # The default list of directories that get ignored by the listener.
+    DEFAULT_IGNORED_DIRECTORIES = %w[.rbx .bundle .git .svn bundle log tmp vendor]
+
+    # The default list of files that get ignored by the listener.
+    DEFAULT_IGNORED_EXTENSIONS  = %w[.DS_Store]
+
+    # Defines the used precision based on the type of mtime returned by the
+    # system (whether its in milliseconds or just seconds)
+    #
+    begin
+      HIGH_PRECISION_SUPPORTED = File.mtime(__FILE__).to_f.to_s[-2..-1] != '.0'
+    rescue
+      HIGH_PRECISION_SUPPORTED = false
+    end
+
+    # Data structure used to save meta data about a path
+    #
+    MetaData = Struct.new(:type, :mtime)
+
+    # Class methods
+    #
+    class << self
+
+      # Creates the ignoring patterns from the default ignored
+      # directories and extensions. It memoizes the generated patterns
+      # to avoid unnecessary computation.
+      #
+      def generate_default_ignoring_patterns
+        @@default_ignoring_patterns ||= Array.new.tap do |default_patterns|
+          # Add directories
+          ignored_directories = DEFAULT_IGNORED_DIRECTORIES.map { |d| Regexp.escape(d) }
+          default_patterns << %r{^(?:#{ignored_directories.join('|')})/}
+
+          # Add extensions
+          ignored_extensions = DEFAULT_IGNORED_EXTENSIONS.map { |e| Regexp.escape(e) }
+          default_patterns << %r{(?:#{ignored_extensions.join('|')})$}
+        end
+      end
+    end
+
+    # Initializes a directory record.
+    #
+    # @option [String] directory the directory to keep track of
+    #
+    def initialize(directory)
+      raise ArgumentError, "The path '#{directory}' is not a directory!" unless File.directory?(directory)
+
+      @directory, @sha1_checksums = File.expand_path(directory), Hash.new
+      @ignoring_patterns, @filtering_patterns = Set.new, Set.new
+
+      @ignoring_patterns.merge(DirectoryRecord.generate_default_ignoring_patterns)
+    end
+
+    # Returns the ignoring patterns in the record to know
+    # which paths should be ignored.
+    #
+    # @return [Array<Regexp>] the ignoring patterns
+    #
+    def ignoring_patterns
+      @ignoring_patterns.to_a
+    end
+
+    # Returns the filtering patterns in the record to know
+    # which paths should be stored.
+    #
+    # @return [Array<Regexp>] the filtering patterns
+    #
+    def filtering_patterns
+      @filtering_patterns.to_a
+    end
+
+    # Adds ignoring patterns to the record.
+    #
+    # @example Ignore some paths
+    #   ignore %r{^ignored/path/}, /man/
+    #
+    # @param [Regexp] regexps a list of patterns for ignoring paths
+    #
+    def ignore(*regexps)
+      @ignoring_patterns.merge(regexps).reject! { |r| r.nil? }
+    end
+
+    # Replaces ignoring patterns in the record.
+    #
+    # @example Ignore only these paths
+    #   ignore! %r{^ignored/path/}, /man/
+    #
+    # @param [Regexp] regexps a list of patterns for ignoring paths
+    #
+    def ignore!(*regexps)
+      @ignoring_patterns.replace(regexps).reject! { |r| r.nil? }
+    end
+
+    # Adds filtering patterns to the record.
+    #
+    # @example Filter some files
+    #   filter /\.txt$/, /.*\.zip/
+    #
+    # @param [Regexp] regexps a list of patterns for filtering files
+    #
+    def filter(*regexps)
+      @filtering_patterns.merge(regexps).reject! { |r| r.nil? }
+    end
+
+    # Replaces filtering patterns in the record.
+    #
+    # @example Filter only these files
+    #   filter! /\.txt$/, /.*\.zip/
+    #
+    # @param [Regexp] regexps a list of patterns for filtering files
+    #
+    def filter!(*regexps)
+      @filtering_patterns.replace(regexps).reject! { |r| r.nil? }
+    end
+
+    # Returns whether a path should be ignored or not.
+    #
+    # @param [String] path the path to test
+    #
+    # @return [Boolean]
+    #
+    def ignored?(path)
+      path = relative_to_base(path)
+      @ignoring_patterns.any? { |pattern| pattern =~ path }
+    end
+
+    # Returns whether a path should be filtered or not.
+    #
+    # @param [String] path the path to test
+    #
+    # @return [Boolean]
+    #
+    def filtered?(path)
+      # When no filtering patterns are set, ALL files are stored.
+      return true if @filtering_patterns.empty?
+
+      path = relative_to_base(path)
+      @filtering_patterns.any? { |pattern| pattern =~ path }
+    end
+
+    # Finds the paths that should be stored and adds them
+    # to the paths' hash.
+    #
+    def build
+      @paths = Hash.new { |h, k| h[k] = Hash.new }
+      important_paths { |path| insert_path(path) }
+    end
+
+    # Detects changes in the passed directories, updates
+    # the record with the new changes and returns the changes.
+    #
+    # @param [Array] directories the list of directories to scan for changes
+    # @param [Hash] options
+    # @option options [Boolean] recursive scan all sub-directories recursively
+    # @option options [Boolean] relative_paths whether or not to use relative paths for changes
+    #
+    # @return [Hash<Array>] the changes
+    #
+    def fetch_changes(directories, options = {})
+      @changes    = { :modified => [], :added => [], :removed => [] }
+      directories = directories.sort_by { |el| el.length }.reverse # diff sub-dir first
+
+      directories.each do |directory|
+        next unless directory[ directory] # Path is or inside directory
+
+        detect_modifications_and_removals(directory, options)
+        detect_additions(directory, options)
+      end
+
+      @changes
+    end
+
+    # Converts an absolute path to a path that's relative to the base directory.
+    #
+    # @param [String] path the path to convert
+    #
+    # @return [String] the relative path
+    #
+    def relative_to_base(path)
+      path = path.dup
+      regexp = "\\A#{Regexp.quote directory}(#{File::SEPARATOR}|\\z)"
+      if path.respond_to?(:force_encoding)
+        path.force_encoding("BINARY")
+        regexp.force_encoding("BINARY")
+      end
+      if path.sub!(Regexp.new(regexp), '')
+        path
+      end
+    end
+
+    private
+
+    # Detects modifications and removals recursively in a directory.
+    #
+    # @note Modifications detection begins by checking the modification time (mtime)
+    #   of files and then by checking content changes (using SHA1-checksum)
+    #   when the mtime of files is not changed.
+    #
+    # @param [String] directory the path to analyze
+    # @param [Hash] options
+    # @option options [Boolean] recursive scan all sub-directories recursively
+    # @option options [Boolean] relative_paths whether or not to use relative paths for changes
+    #
+    def detect_modifications_and_removals(directory, options = {})
+      paths[directory].each do |basename, meta_data|
+        path = File.join(directory, basename)
+        case meta_data.type
+        when 'Dir'
+          detect_modification_or_removal_for_dir(path, options)
+        when 'File'
+          detect_modification_or_removal_for_file(path, meta_data, options)
+        end
+      end
+    end
+
+    def detect_modification_or_removal_for_dir(path, options)
+
+      # Directory still exists
+      if File.directory?(path)
+        detect_modifications_and_removals(path, options) if options[:recursive]
+
+      # Directory has been removed
+      else
+        detect_modifications_and_removals(path, options)
+        @paths[File.dirname(path)].delete(File.basename(path))
+        @paths.delete("#{File.dirname(path)}/#{File.basename(path)}")
+      end
+    end
+
+    def detect_modification_or_removal_for_file(path, meta_data, options)
+      # File still exists
+      if File.exist?(path)
+        detect_modification(path, meta_data, options)
+
+      # File has been removed
+      else
+        removal_detected(path, meta_data, options)
+      end
+    end
+
+    def detect_modification(path, meta_data, options)
+      new_mtime = mtime_of(path)
+
+      # First check if we are in the same second (to update checksums)
+      # before checking the time difference
+      if (meta_data.mtime.to_i == new_mtime.to_i && content_modified?(path)) || meta_data.mtime < new_mtime
+        modification_detected(path, meta_data, new_mtime, options)
+      end
+    end
+
+    def modification_detected(path, meta_data, new_mtime, options)
+      # Update the sha1 checksum of the file
+      update_sha1_checksum(path)
+
+      # Update the meta data of the file
+      meta_data.mtime = new_mtime
+      @paths[File.dirname(path)][File.basename(path)] = meta_data
+
+      @changes[:modified] << (options[:relative_paths] ? relative_to_base(path) : path)
+    end
+
+    def removal_detected(path, meta_data, options)
+      @paths[File.dirname(path)].delete(File.basename(path))
+      @sha1_checksums.delete(path)
+      @changes[:removed] << (options[:relative_paths] ? relative_to_base(path) : path)
+    end
+
+    # Detects additions in a directory.
+    #
+    # @param [String] directory the path to analyze
+    # @param [Hash] options
+    # @option options [Boolean] recursive scan all sub-directories recursively
+    # @option options [Boolean] relative_paths whether or not to use relative paths for changes
+    #
+    def detect_additions(directory, options = {})
+      # Don't process removed directories
+      return unless File.exist?(directory)
+
+      Find.find(directory) do |path|
+        next if path == @directory
+
+        if File.directory?(path)
+          # Add a trailing slash to directories when checking if a directory is
+          # ignored to optimize finding them as Find.find doesn't.
+          if ignored?(path + File::SEPARATOR) || (directory != path && (!options[:recursive] && 
existing_path?(path)))
+            Find.prune # Don't look any further into this directory.
+          else
+            insert_path(path)
+          end
+        elsif !ignored?(path) && filtered?(path) && !existing_path?(path)
+          if File.file?(path)
+            @changes[:added] << (options[:relative_paths] ? relative_to_base(path) : path)
+            insert_path(path)
+          end
+        end
+      end
+    end
+
+    # Returns whether or not a file's content has been modified by
+    # comparing the SHA1-checksum to a stored one.
+    # Ensure that the SHA1-checksum is inserted to the sha1_checksums
+    # array for later comparaison if false.
+    #
+    # @param [String] path the file path
+    #
+    def content_modified?(path)
+      return false unless File.ftype(path) == 'file'
+      @sha1_checksum = sha1_checksum(path)
+      if sha1_checksums[path] == @sha1_checksum || !sha1_checksums.key?(path)
+        update_sha1_checksum(path)
+        false
+      else
+        true
+      end
+    end
+
+    # Inserts a SHA1-checksum path in @SHA1-checksums hash.
+    #
+    # @param [String] path the SHA1-checksum path to insert in @sha1_checksums.
+    #
+    def update_sha1_checksum(path)
+      if @sha1_checksum ||= sha1_checksum(path)
+        @sha1_checksums[path] = @sha1_checksum
+        @sha1_checksum = nil
+      end
+    end
+
+    # Returns the SHA1-checksum for the file path.
+    #
+    # @param [String] path the file path
+    #
+    def sha1_checksum(path)
+      Digest::SHA1.file(path).to_s
+    rescue
+      nil
+    end
+
+    # Traverses the base directory looking for paths that should
+    # be stored; thus paths that are filtered or not ignored.
+    #
+    # @yield [path] an important path
+    #
+    def important_paths
+      Find.find(directory) do |path|
+        next if path == directory
+
+        if File.directory?(path)
+          # Add a trailing slash to directories when checking if a directory is
+          # ignored to optimize finding them as Find.find doesn't.
+          if ignored?(path + File::SEPARATOR)
+            Find.prune # Don't look any further into this directory.
+          else
+            yield(path)
+          end
+        elsif !ignored?(path) && filtered?(path)
+          yield(path)
+        end
+      end
+    end
+
+    # Inserts a path with its type (Dir or File) in paths hash.
+    #
+    # @param [String] path the path to insert in @paths.
+    #
+    def insert_path(path)
+      meta_data = MetaData.new
+      meta_data.type = File.directory?(path) ? 'Dir' : 'File'
+      meta_data.mtime = mtime_of(path) unless meta_data.type == 'Dir' # mtimes of dirs are not used yet
+      @paths[File.dirname(path)][File.basename(path)] = meta_data
+    rescue Errno::ENOENT
+    end
+
+    # Returns whether or not a path exists in the paths hash.
+    #
+    # @param [String] path the path to check
+    #
+    # @return [Boolean]
+    #
+    def existing_path?(path)
+      paths[File.dirname(path)][File.basename(path)] != nil
+    end
+
+    # Returns the modification time of a file based on the precision defined by the system
+    #
+    # @param [String] file the file for which the mtime must be returned
+    #
+    # @return [Fixnum, Float] the mtime of the file
+    #
+    def mtime_of(file)
+      File.lstat(file).mtime.send(HIGH_PRECISION_SUPPORTED ? :to_f : :to_i)
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/listener.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/listener.rb
new file mode 100644
index 0000000..b8bd506
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/listener.rb
@@ -0,0 +1,323 @@
+require 'pathname'
+
+module Listen
+  class Listener
+    attr_reader :directories, :directories_records, :block, :adapter, :adapter_options, :use_relative_paths
+
+    BLOCKING_PARAMETER_DEPRECATION_MESSAGE = <<-EOS.gsub(/^\s*/, '')
+      The blocking parameter of Listen::Listener#start is deprecated.\n
+      Please use Listen::Adapter#start for a non-blocking listener and Listen::Listener#start! for a 
blocking one.
+    EOS
+
+    RELATIVE_PATHS_WITH_MULTIPLE_DIRECTORIES_WARNING_MESSAGE = "The relative_paths option doesn't work when 
listening to multiple diretories."
+
+    # Initializes the directories listener.
+    #
+    # @param [String] directory the directories to listen to
+    # @param [Hash] options the listen options
+    # @option options [Regexp] ignore a pattern for ignoring paths
+    # @option options [Regexp] filter a pattern for filtering paths
+    # @option options [Float] latency the delay between checking for changes in seconds
+    # @option options [Boolean] relative_paths whether or not to use relative-paths in the callback
+    # @option options [Boolean] force_polling whether to force the polling adapter or not
+    # @option options [String, Boolean] polling_fallback_message to change polling fallback message or 
remove it
+    # @option options [Class] force_adapter force the use of this adapter class, skipping usual adapter 
selection
+    #
+    # @yield [modified, added, removed] the changed files
+    # @yieldparam [Array<String>] modified the list of modified files
+    # @yieldparam [Array<String>] added the list of added files
+    # @yieldparam [Array<String>] removed the list of removed files
+    #
+    def initialize(*args, &block)
+      options     = args.last.is_a?(Hash) ? args.pop : {}
+      directories = args.flatten
+      initialize_directories_and_directories_records(directories)
+      initialize_relative_paths_usage(options)
+      @block = block
+
+      ignore(*options.delete(:ignore))
+      filter(*options.delete(:filter))
+
+      @adapter_options = options
+    end
+
+    # Starts the listener by initializing the adapter and building
+    # the directory record concurrently, then it starts the adapter to watch
+    # for changes. The current thread is not blocked after starting.
+    #
+    # @see Listen::Listener#start!
+    #
+    def start(deprecated_blocking = nil)
+      Kernel.warn "[Listen warning]:\n#{BLOCKING_PARAMETER_DEPRECATION_MESSAGE}" unless 
deprecated_blocking.nil?
+      setup
+      adapter.start
+    end
+
+    # Starts the listener by initializing the adapter and building
+    # the directory record concurrently, then it starts the adapter to watch
+    # for changes. The current thread is blocked after starting.
+    #
+    # @see Listen::Listener#start
+    #
+    # @since 1.0.0
+    #
+    def start!
+      setup
+      adapter.start!
+    end
+
+    # Stops the listener.
+    #
+    def stop
+      adapter && adapter.stop
+    end
+
+    # Pauses the listener.
+    #
+    # @return [Listen::Listener] the listener
+    #
+    def pause
+      adapter.pause
+      self
+    end
+
+    # Unpauses the listener.
+    #
+    # @return [Listen::Listener] the listener
+    #
+    def unpause
+      build_directories_records
+      adapter.unpause
+      self
+    end
+
+    # Returns whether the listener is paused or not.
+    #
+    # @return [Boolean] adapter paused status
+    #
+    def paused?
+      !!adapter && adapter.paused?
+    end
+
+    # Adds ignoring patterns to the listener.
+    #
+    # @param (see Listen::DirectoryRecord#ignore)
+    #
+    # @return [Listen::Listener] the listener
+    #
+    # @see Listen::DirectoryRecord#ignore
+    #
+    def ignore(*regexps)
+      directories_records.each { |r| r.ignore(*regexps) }
+      self
+    end
+
+    # Replaces ignoring patterns in the listener.
+    #
+    # @param (see Listen::DirectoryRecord#ignore!)
+    #
+    # @return [Listen::Listener] the listener
+    #
+    # @see Listen::DirectoryRecord#ignore!
+    #
+    def ignore!(*regexps)
+      directories_records.each { |r| r.ignore!(*regexps) }
+      self
+    end
+
+    # Adds filtering patterns to the listener.
+    #
+    # @param (see Listen::DirectoryRecord#filter)
+    #
+    # @return [Listen::Listener] the listener
+    #
+    # @see Listen::DirectoryRecord#filter
+    #
+    def filter(*regexps)
+      directories_records.each { |r| r.filter(*regexps) }
+      self
+    end
+
+    # Replaces filtering patterns in the listener.
+    #
+    # @param (see Listen::DirectoryRecord#filter!)
+    #
+    # @return [Listen::Listener] the listener
+    #
+    # @see Listen::DirectoryRecord#filter!
+    #
+    def filter!(*regexps)
+      directories_records.each { |r| r.filter!(*regexps) }
+      self
+    end
+
+    # Sets the latency for the adapter. This is a helper method
+    # to simplify changing the latency directly from the listener.
+    #
+    # @example Wait 0.5 seconds each time before checking changes
+    #   latency 0.5
+    #
+    # @param [Float] seconds the amount of delay, in seconds
+    #
+    # @return [Listen::Listener] the listener
+    #
+    def latency(seconds)
+      @adapter_options[:latency] = seconds
+      self
+    end
+
+    # Sets whether the use of the polling adapter
+    # should be forced or not.
+    #
+    # @example Forcing the use of the polling adapter
+    #   force_polling true
+    #
+    # @param [Boolean] value whether to force the polling adapter or not
+    #
+    # @return [Listen::Listener] the listener
+    #
+    def force_polling(value)
+      @adapter_options[:force_polling] = value
+      self
+    end
+
+    # Sets whether to force the use of a particular adapter, rather than
+    # going through usual adapter selection process on start.
+    #
+    # @example Force use of Linux polling
+    #   force_adapter Listen::Adapters::Linux
+    #
+    # @param [Class] adapter class to use for file system event notification.
+    #
+    # @return [Listen::Listener] the listener
+    #
+    def force_adapter(adapter_class)
+      @adapter_options[:force_adapter] = adapter_class
+      self
+    end
+
+    # Sets whether the paths in the callback should be
+    # relative or absolute.
+    #
+    # @example Enabling relative paths in the callback
+    #   relative_paths true
+    #
+    # @param [Boolean] value whether to enable relative paths in the callback or not
+    #
+    # @return [Listen::Listener] the listener
+    #
+    def relative_paths(value)
+      @use_relative_paths = value
+      self
+    end
+
+    # Defines a custom polling fallback message or disable it.
+    #
+    # @example Disabling the polling fallback message
+    #   polling_fallback_message false
+    #
+    # @param [String, Boolean] value to change polling fallback message or remove it
+    #
+    # @return [Listen::Listener] the listener
+    #
+    def polling_fallback_message(value)
+      @adapter_options[:polling_fallback_message] = value
+      self
+    end
+
+    # Sets the callback that gets called on changes.
+    #
+    # @example Assign a callback to be called on changes
+    #   callback = lambda { |modified, added, removed| ... }
+    #   change &callback
+    #
+    # @param [Proc] block the callback proc
+    #
+    # @return [Listen::Listener] the listener
+    #
+    def change(&block) # modified, added, removed
+      @block = block
+      self
+    end
+
+    # Runs the callback passing it the changes if there are any.
+    #
+    # @param (see Listen::DirectoryRecord#fetch_changes)
+    #
+    # @see Listen::DirectoryRecord#fetch_changes
+    #
+    def on_change(directories, options = {})
+      changes = fetch_records_changes(directories, options)
+      unless changes.values.all? { |paths| paths.empty? }
+        block.call(changes[:modified], changes[:added], changes[:removed])
+      end
+    rescue => ex
+      Kernel.warn "[Listen warning]: Change block raise an execption: #{$!}"
+      Kernel.warn "Backtrace:\n\t#{ex.backtrace.join("\n\t")}"
+    end
+
+    private
+
+    # Initializes the directories to watch as well as the directories records.
+    #
+    # @see Listen::DirectoryRecord
+    #
+    def initialize_directories_and_directories_records(directories)
+      @directories = directories.map { |d| Pathname.new(d).realpath.to_s }
+      @directories_records = directories.map { |d| DirectoryRecord.new(d) }
+    end
+
+    # Initializes whether or not using relative paths.
+    #
+    def initialize_relative_paths_usage(options)
+      if directories.size > 1 && options[:relative_paths]
+        Kernel.warn "[Listen warning]: #{RELATIVE_PATHS_WITH_MULTIPLE_DIRECTORIES_WARNING_MESSAGE}"
+      end
+      @use_relative_paths = directories.one? && options.delete(:relative_paths) { false }
+    end
+
+    # Build the directory record concurrently and initialize the adapter.
+    #
+    def setup
+      t = Thread.new { build_directories_records }
+      @adapter = initialize_adapter
+      t.join
+    end
+
+    # Initializes an adapter passing it the callback and adapters' options.
+    #
+    def initialize_adapter
+      callback = lambda { |changed_directories, options| self.on_change(changed_directories, options) }
+      Adapter.select_and_initialize(directories, adapter_options, &callback)
+    end
+
+    # Build the watched directories' records.
+    #
+    def build_directories_records
+      directories_records.each { |r| r.build }
+    end
+
+    # Returns the sum of all the changes to the directories records
+    #
+    # @param (see Listen::DirectoryRecord#fetch_changes)
+    #
+    # @return [Hash] the changes
+    #
+    def fetch_records_changes(directories_to_search, options)
+      directories_records.inject({}) do |h, r|
+        # directory records skips paths outside their range, so passing the
+        # whole `directories` array is not a problem.
+        record_changes = r.fetch_changes(directories_to_search, options.merge(:relative_paths => 
use_relative_paths))
+
+        if h.empty?
+          h.merge!(record_changes)
+        else
+          h.each { |k, v| h[k] += record_changes[k] }
+        end
+
+        h
+      end
+    end
+
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/turnstile.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/turnstile.rb
new file mode 100644
index 0000000..a0dc696
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/turnstile.rb
@@ -0,0 +1,32 @@
+module Listen
+
+  # Allows two threads to wait on eachother.
+  #
+  # @note Only two threads can be used with this Turnstile
+  #   because of the current implementation.
+  class Turnstile
+    attr_accessor :queue
+
+    # Initialize the turnstile.
+    #
+    def initialize
+      # Until Ruby offers semahpores, only queues can be used
+      # to implement a turnstile.
+      @queue = Queue.new
+    end
+
+    # Blocks the current thread until a signal is received.
+    #
+    def wait
+      queue.pop if queue.num_waiting == 0
+    end
+
+    # Unblocks the waiting thread if any.
+    #
+    def signal
+      queue.push(:dummy) if queue.num_waiting == 1
+    end
+
+  end
+
+end
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/version.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/version.rb
new file mode 100644
index 0000000..fec74bf
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/lib/listen/version.rb
@@ -0,0 +1,3 @@
+module Listen
+  VERSION = '1.3.1'
+end
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/listen.gemspec 
b/backends/css/gems/sass-3.4.9/vendor/listen/listen.gemspec
new file mode 100644
index 0000000..2e0f17e
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/listen.gemspec
@@ -0,0 +1,28 @@
+# -*- encoding: utf-8 -*-
+$:.push File.expand_path('../lib', __FILE__)
+require 'listen/version'
+
+Gem::Specification.new do |s|
+  s.name        = 'listen'
+  s.version     = Listen::VERSION
+  s.platform    = Gem::Platform::RUBY
+  s.authors     = ['Thibaud Guillaume-Gentil', 'Maher Sallam']
+  s.email       = ['thibaud thibaud me', 'maher sallam me']
+  s.homepage    = 'https://github.com/guard/listen'
+  s.license     = 'MIT'
+  s.summary     = 'Listen to file modifications'
+  s.description = 'The Listen gem listens to file modifications and notifies you about the changes. Works 
everywhere!'
+
+  s.required_rubygems_version = '>= 1.3.6'
+  s.rubyforge_project = 'listen'
+
+  s.add_dependency 'rb-fsevent', '>= 0.9.3'
+  s.add_dependency 'rb-inotify', '>= 0.9'
+  s.add_dependency 'rb-kqueue',  '>= 0.2'
+
+  s.add_development_dependency 'bundler'
+  s.add_development_dependency 'rspec'
+
+  s.files        = Dir.glob('{lib}/**/*') + %w[CHANGELOG.md LICENSE README.md]
+  s.require_path = 'lib'
+end
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/adapter_spec.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/adapter_spec.rb
new file mode 100644
index 0000000..241c2a6
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/adapter_spec.rb
@@ -0,0 +1,149 @@
+require 'spec_helper'
+
+describe Listen::Adapter do
+  subject { described_class.new('dir') }
+
+  describe '#initialize' do
+    it 'sets the latency to the default one' do
+      subject.latency.should eq described_class::DEFAULT_LATENCY
+    end
+
+    it 'accepts a single directory to watch' do
+      described_class.new('dir').directories = %w{dir}
+    end
+
+    it 'accepts multiple directories to watch' do
+      described_class.new(%w{dir1 dir2}).directories.should eq %w{dir1 dir2}
+    end
+  end
+
+  describe ".select_and_initialize" do
+    before do
+      Listen::Adapter::OPTIMIZED_ADAPTERS.each do |adapter|
+        Listen::Adapters.const_get(adapter).stub(:usable_and_works?) { false }
+      end
+    end
+
+    context "with force_adapter option" do
+      it "returns an instance of the given adapter class" do
+        expected_adapter = Object.new
+        adapter_class = double('adapter_class')
+        options = {:force_adapter => adapter_class}
+
+        adapter_class.should_receive(:load_dependent_adapter)
+        adapter_class.should_receive(:new).with('dir', options) { expected_adapter }
+
+        adapter = described_class.select_and_initialize('dir', options)
+        adapter.should be(expected_adapter)
+      end
+    end
+
+    context "with no specific adapter usable" do
+      it "returns Listen::Adapters::Polling instance" do
+        Kernel.stub(:warn)
+        Listen::Adapters::Polling.should_receive(:new).with('dir', {})
+        described_class.select_and_initialize('dir')
+      end
+
+      it 'warns with the default polling fallback message' do
+        Kernel.should_receive(:warn).with(/#{Listen::Adapter::POLLING_FALLBACK_MESSAGE}/)
+        described_class.select_and_initialize('dir')
+      end
+
+      context "with custom polling_fallback_message option" do
+        it "warns with the custom polling fallback message" do
+          Kernel.should_receive(:warn).with(/custom/)
+          described_class.select_and_initialize('dir', :polling_fallback_message => 'custom')
+        end
+      end
+
+      context "with polling_fallback_message to false" do
+        it "doesn't warn with a polling fallback message" do
+          Kernel.should_not_receive(:warn)
+          described_class.select_and_initialize('dir', :polling_fallback_message => false)
+        end
+      end
+    end
+
+    Listen::Adapter::OPTIMIZED_ADAPTERS.each do |adapter|
+      adapter_class = Listen::Adapters.const_get(adapter)
+
+      context "on #{adapter}" do
+        before { adapter_class.stub(:usable_and_works?) { true } }
+
+        it "uses Listen::Adapters::#{adapter}" do
+          adapter_class.should_receive(:new).with('dir', {})
+          described_class.select_and_initialize('dir')
+        end
+
+        context 'when the use of the polling adapter is forced' do
+          it 'uses Listen::Adapters::Polling' do
+            Listen::Adapters::Polling.should_receive(:new).with('dir', {})
+            described_class.select_and_initialize('dir', :force_polling => true)
+          end
+        end
+      end
+    end
+  end
+
+  describe '.load_dependend_adapter' do
+    after(:each) { described_class.instance_variable_set('@loaded', nil) }
+
+    it 'returns true (success) even if the adapter_gem has already been required' do
+      described_class.stub(:adapter_gem => 'already_loaded_gem')
+      described_class.stub(:require => false)
+
+      described_class.load_dependent_adapter.should be_true
+    end
+
+    it 'returns false (failure) if the adapter_gem cannot be required' do
+      described_class.stub(:adapter_gem => 'unloadable_gem')
+      described_class.stub(:require) do
+        raise LoadError.new('no such file to load -- unloadable_gem')
+      end
+
+      described_class.load_dependent_adapter.should be_false
+    end
+  end
+
+  Listen::Adapter::OPTIMIZED_ADAPTERS.each do |adapter|
+    adapter_class = Listen::Adapters.const_get(adapter)
+    if adapter_class.usable?
+      describe '.usable_and_works?' do
+        it 'checks if the adapter is usable' do
+          adapter_class.stub(:works?)
+          adapter_class.should_receive(:usable?)
+          adapter_class.usable_and_works?('dir')
+        end
+
+        context 'with one directory' do
+          it 'tests if that directory actually work' do
+            fixtures do |path|
+              adapter_class.should_receive(:works?).with(path, anything).and_return(true)
+              adapter_class.usable_and_works?(path)
+            end
+          end
+        end
+
+        context 'with multiple directories' do
+          it 'tests if each directory passed does actually work' do
+            fixtures(3) do |path1, path2, path3|
+              adapter_class.should_receive(:works?).exactly(3).times.with do |path, options|
+                [path1, path2, path3].include? path
+              end.and_return(true)
+              adapter_class.usable_and_works?([path1, path2, path3])
+            end
+          end
+        end
+      end
+
+      describe '.works?' do
+        it 'does work' do
+          fixtures do |path|
+            adapter_class.works?(path).should be_true
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.2.12/vendor/listen/spec/listen/adapters/bsd_spec.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/adapters/bsd_spec.rb
similarity index 100%
rename from backends/css/gems/sass-3.2.12/vendor/listen/spec/listen/adapters/bsd_spec.rb
rename to backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/adapters/bsd_spec.rb
diff --git a/backends/css/gems/sass-3.2.12/vendor/listen/spec/listen/adapters/darwin_spec.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/adapters/darwin_spec.rb
similarity index 100%
rename from backends/css/gems/sass-3.2.12/vendor/listen/spec/listen/adapters/darwin_spec.rb
rename to backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/adapters/darwin_spec.rb
diff --git a/backends/css/gems/sass-3.2.12/vendor/listen/spec/listen/adapters/linux_spec.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/adapters/linux_spec.rb
similarity index 100%
rename from backends/css/gems/sass-3.2.12/vendor/listen/spec/listen/adapters/linux_spec.rb
rename to backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/adapters/linux_spec.rb
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/adapters/polling_spec.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/adapters/polling_spec.rb
new file mode 100644
index 0000000..33b98b3
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/adapters/polling_spec.rb
@@ -0,0 +1,68 @@
+require 'spec_helper'
+
+describe Listen::Adapters::Polling do
+  subject { described_class.new('dir') }
+
+  it_should_behave_like 'a filesystem adapter'
+
+  describe '#initialize' do
+    it 'sets the latency to the default polling one' do
+      subject.latency.should eq Listen::Adapters::DEFAULT_POLLING_LATENCY
+    end
+  end
+
+  describe '#poll' do
+    let(:listener) { double(Listen::Listener) }
+    let(:callback) { lambda { |changed_directories, options| @called = true; 
listener.on_change(changed_directories, options) } }
+
+    after { subject.stop }
+
+    context 'with one directory to watch' do
+      subject { Listen::Adapters::Polling.new('dir', {}, &callback) }
+
+      it 'calls listener.on_change' do
+        listener.should_receive(:on_change).at_least(1).times.with(['dir'], :recursive => true)
+        subject.start
+        subject.wait_for_callback
+      end
+
+      it 'calls listener.on_change continuously' do
+        subject.latency = 0.001
+        listener.should_receive(:on_change).at_least(10).times.with(['dir'], :recursive => true)
+        subject.start
+        10.times { subject.wait_for_callback }
+      end
+
+      it "doesn't call listener.on_change if paused" do
+        subject.paused = true
+        subject.start
+        subject.wait_for_callback
+        @called.should be_nil
+      end
+    end
+
+    context 'with multiple directories to watch' do
+      subject { Listen::Adapters::Polling.new(%w{dir1 dir2}, {}, &callback) }
+
+      it 'calls listener.on_change' do
+        listener.should_receive(:on_change).at_least(1).times.with(%w{dir1 dir2}, :recursive => true)
+        subject.start
+        subject.wait_for_callback
+      end
+
+      it 'calls listener.on_change continuously' do
+        subject.latency = 0.001
+        listener.should_receive(:on_change).at_least(10).times.with(%w{dir1 dir2}, :recursive => true)
+        subject.start
+        10.times { subject.wait_for_callback }
+      end
+
+      it "doesn't call listener.on_change if paused" do
+        subject.paused = true
+        subject.start
+        subject.wait_for_callback
+        @called.should be_nil
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.2.12/vendor/listen/spec/listen/adapters/windows_spec.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/adapters/windows_spec.rb
similarity index 100%
rename from backends/css/gems/sass-3.2.12/vendor/listen/spec/listen/adapters/windows_spec.rb
rename to backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/adapters/windows_spec.rb
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/directory_record_spec.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/directory_record_spec.rb
new file mode 100644
index 0000000..e3b7964
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/directory_record_spec.rb
@@ -0,0 +1,1250 @@
+# encoding: UTF-8
+require 'spec_helper'
+
+describe Listen::DirectoryRecord do
+  let(:base_directory) { File.dirname(__FILE__) }
+
+  subject { described_class.new(base_directory) }
+
+  describe '.generate_default_ignoring_patterns' do
+    it 'creates regexp patterns from the default ignored directories and extensions' do
+      described_class.generate_default_ignoring_patterns.should include(
+        %r{^(?:\.rbx|\.bundle|\.git|\.svn|bundle|log|tmp|vendor)/},
+        %r{(?:\.DS_Store)$}
+      )
+    end
+
+    it 'memoizes the generated results' do
+      described_class.generate_default_ignoring_patterns.should equal 
described_class.generate_default_ignoring_patterns
+    end
+  end
+
+  describe '#initialize' do
+    it 'sets the base directory' do
+      subject.directory.should eq base_directory
+    end
+
+    it 'sets the base directory expanded' do
+      cd File.dirname(base_directory)
+      subject = described_class.new(File.basename(base_directory))
+      subject.directory.should eq base_directory
+    end
+
+    it 'sets the default ignoring patterns' do
+      subject.ignoring_patterns.should =~ described_class.generate_default_ignoring_patterns
+    end
+
+    it 'sets the default filtering patterns' do
+      subject.filtering_patterns.should eq []
+    end
+
+    it 'raises an error when the passed path does not exist' do
+      expect { described_class.new('no way I exist') }.to raise_error(ArgumentError)
+    end
+
+    it 'raises an error when the passed path is not a directory' do
+      expect { described_class.new(__FILE__) }.to raise_error(ArgumentError)
+    end
+  end
+
+  describe '#ignore' do
+    it 'adds the passed paths to the list of ignored paths in the record' do
+      subject.ignore(%r{^\.old/}, %r{\.pid$}, nil)
+      subject.ignoring_patterns.should include(%r{^\.old/}, %r{\.pid$})
+      subject.ignoring_patterns.should_not include(nil)
+    end
+  end
+
+  describe '#ignore!' do
+    it 'replace the ignored paths in the record' do
+      subject.ignore!(%r{^\.old/}, %r{\.pid$}, nil)
+      subject.ignoring_patterns.should eq [%r{^\.old/}, %r{\.pid$}]
+    end
+  end
+
+  describe '#filter' do
+    it 'adds the passed regexps to the list of filters that determine the stored paths' do
+      subject.filter(%r{\.(?:jpe?g|gif|png)}, %r{\.(?:mp3|ogg|a3c)}, nil)
+      subject.filtering_patterns.should include(%r{\.(?:jpe?g|gif|png)}, %r{\.(?:mp3|ogg|a3c)})
+      subject.filtering_patterns.should_not include(nil)
+    end
+  end
+
+  describe '#filter!' do
+    it 'replaces the passed regexps in the list of filters that determine the stored paths' do
+      subject.filter!(%r{\.(?:jpe?g|gif|png)}, %r{\.(?:mp3|ogg|a3c)})
+      subject.filtering_patterns.should have(2).regexps
+      subject.filtering_patterns.should =~ [%r{\.(?:mp3|ogg|a3c)}, %r{\.(?:jpe?g|gif|png)}]
+    end
+  end
+
+  describe '#ignored?' do
+    before { subject.stub(:relative_to_base) { |path| path } }
+
+    it 'tests paths relative to the base directory' do
+      subject.should_receive(:relative_to_base).with('file.txt')
+      subject.ignored?('file.txt')
+    end
+
+    it 'returns true when the passed path is a default ignored path' do
+      subject.ignored?('tmp/some_process.pid').should be_true
+      subject.ignored?('dir/.DS_Store').should be_true
+      subject.ignored?('.git/config').should be_true
+    end
+
+    it 'returns false when the passed path is not a default ignored path' do
+      subject.ignored?('nested/tmp/some_process.pid').should be_false
+      subject.ignored?('nested/.git').should be_false
+      subject.ignored?('dir/.DS_Store/file').should be_false
+      subject.ignored?('file.git').should be_false
+    end
+
+    it 'returns true when the passed path is ignored' do
+      subject.ignore(%r{\.pid$})
+      subject.ignored?('dir/some_process.pid').should be_true
+    end
+
+    it 'returns false when the passed path is not ignored' do
+      subject.ignore(%r{\.pid$})
+      subject.ignored?('dir/some_file.txt').should be_false
+    end
+  end
+
+  describe '#filtered?' do
+    before { subject.stub(:relative_to_base) { |path| path } }
+
+    context 'when no filtering patterns are set' do
+      it 'returns true for any path' do
+        subject.filtered?('file.txt').should be_true
+      end
+    end
+
+    context 'when filtering patterns are set' do
+      before { subject.filter(%r{\.(?:jpe?g|gif|png)}) }
+
+      it 'tests paths relative to the base directory' do
+        subject.should_receive(:relative_to_base).with('file.txt')
+        subject.filtered?('file.txt')
+      end
+
+      it 'returns true when the passed path is filtered' do
+        subject.filter(%r{\.(?:jpe?g|gif|png)})
+        subject.filtered?('dir/picture.jpeg').should be_true
+      end
+
+      it 'returns false when the passed path is not filtered' do
+        subject.filter(%r{\.(?:jpe?g|gif|png)})
+        subject.filtered?('dir/song.mp3').should be_false
+      end
+    end
+  end
+
+  describe '#build' do
+    it 'stores all files' do
+      fixtures do |path|
+        touch 'file.rb'
+        mkdir 'a_directory'
+        touch 'a_directory/file.txt'
+
+        record = described_class.new(path)
+        record.build
+
+        record.paths[path]['file.rb'].type.should eq 'File'
+        record.paths[path]['a_directory'].type.should eq 'Dir'
+        record.paths["#{path}/a_directory"]['file.txt'].type.should eq 'File'
+      end
+    end
+
+    context 'with ignored path set' do
+      it 'does not store ignored directory or its childs' do
+        fixtures do |path|
+          mkdir 'ignored_directory'
+          mkdir 'ignored_directory/child_directory'
+          touch 'ignored_directory/file.txt'
+
+          record = described_class.new(path)
+          record.ignore %r{^ignored_directory/}
+          record.build
+
+          record.paths[path]['/a_ignored_directory'].should be_nil
+          record.paths["#{path}/a_ignored_directory"]['child_directory'].should be_nil
+          record.paths["#{path}/a_ignored_directory"]['file.txt'].should be_nil
+        end
+      end
+
+      it 'does not store ignored files' do
+        fixtures do |path|
+          touch 'ignored_file.rb'
+
+          record = described_class.new(path)
+          record.ignore %r{^ignored_file.rb$}
+          record.build
+
+          record.paths[path]['ignored_file.rb'].should be_nil
+        end
+      end
+    end
+
+    context 'with filters set' do
+      it 'only stores filterd files' do
+        fixtures do |path|
+          touch 'file.rb'
+          touch 'file.zip'
+          mkdir 'a_directory'
+          touch 'a_directory/file.txt'
+          touch 'a_directory/file.rb'
+
+          record = described_class.new(path)
+          record.filter(/\.txt$/, /.*\.zip/)
+          record.build
+
+          record.paths[path]['file.rb'].should be_nil
+          record.paths[path]['file.zip'].type.should eq 'File'
+          record.paths[path]['a_directory'].type.should eq 'Dir'
+          record.paths["#{path}/a_directory"]['file.txt'].type.should eq 'File'
+          record.paths["#{path}/a_directory"]['file.rb'].should be_nil
+        end
+      end
+    end
+  end
+
+  describe '#relative_to_base' do
+    it 'removes the path of the base-directory from the passed path' do
+      path = 'dir/to/app/file.rb'
+      subject.relative_to_base(File.join(base_directory, path)).should eq path
+    end
+
+    it 'returns nil when the passed path is not inside the base-directory' do
+      subject.relative_to_base('/tmp/some_random_path').should be_nil
+    end
+
+    it 'works with non UTF-8 paths' do
+      path = "tmp/\xE4\xE4"
+      subject.relative_to_base(File.join(base_directory, path))
+    end
+
+    context 'when there are utf-8 chars in base directory' do
+      before do
+        fixtures do |path|
+          mkdir '目录'
+          @dir = described_class.new(path + '/目录')
+          @dir.build
+        end
+      end
+
+      it 'works' do
+        path = File.join @dir.directory, 'tmp/file.rb'
+        @dir.relative_to_base path
+      end
+    end
+
+    context 'when containing regexp characters in the base directory' do
+      before do
+        fixtures do |path|
+          mkdir 'a_directory$'
+          @dir = described_class.new(path + '/a_directory$')
+          @dir.build
+        end
+      end
+
+      it 'removes the path of the base-directory from the passed path' do
+        path = 'dir/to/app/file.rb'
+        @dir.relative_to_base(File.join(@dir.directory, path)).should eq path
+      end
+
+      it 'returns nil when the passed path is not inside the base-directory' do
+        @dir.relative_to_base('/tmp/some_random_path').should be_nil
+      end
+    end
+  end
+
+  describe '#fetch_changes' do
+    context 'with single file changes' do
+      context 'when a file is created' do
+        it 'detects the added file' do
+          fixtures do |path|
+            modified, added, removed = changes(path) do
+              touch 'new_file.rb'
+            end
+
+            added.should =~ %w(new_file.rb)
+            modified.should be_empty
+            removed.should be_empty
+          end
+        end
+
+        it 'stores the added file in the record' do
+          fixtures do |path|
+            changes(path) do
+              @record.paths.should be_empty
+
+              touch 'new_file.rb'
+            end
+
+            @record.paths[path]['new_file.rb'].should_not be_nil
+          end
+        end
+
+        context 'given a new created directory' do
+          it 'detects the added file' do
+            fixtures do |path|
+              modified, added, removed = changes(path) do
+                mkdir 'a_directory'
+                touch 'a_directory/new_file.rb'
+              end
+
+              added.should =~ %w(a_directory/new_file.rb)
+              modified.should be_empty
+              removed.should be_empty
+            end
+          end
+
+          it 'stores the added directory and file in the record' do
+            fixtures do |path|
+              changes(path) do
+                @record.paths.should be_empty
+
+                mkdir 'a_directory'
+                touch 'a_directory/new_file.rb'
+              end
+
+              @record.paths[path]['a_directory'].should_not be_nil
+              @record.paths["#{path}/a_directory"]['new_file.rb'].should_not be_nil
+            end
+          end
+        end
+
+        context 'given an existing directory' do
+          context 'with recursive option set to true' do
+            it 'detects the added file' do
+              fixtures do |path|
+                mkdir 'a_directory'
+
+                modified, added, removed = changes(path, :recursive => true) do
+                  touch 'a_directory/new_file.rb'
+                end
+
+                added.should =~ %w(a_directory/new_file.rb)
+                modified.should be_empty
+                removed.should be_empty
+              end
+            end
+
+            context 'with an ignored directory' do
+              it "doesn't detect the added file" do
+                fixtures do |path|
+                  mkdir 'ignored_directory'
+
+                  modified, added, removed = changes(path, :ignore => %r{^ignored_directory/}, :recursive => 
true) do
+                    touch 'ignored_directory/new_file.rb'
+                  end
+
+                  added.should be_empty
+                  modified.should be_empty
+                  removed.should be_empty
+                end
+              end
+
+              it "doesn't detect the added file when it's asked to fetch the changes of the ignored 
directory"do
+                fixtures do |path|
+                  mkdir 'ignored_directory'
+
+                  modified, added, removed = changes(path, :paths => ["#{path}/ignored_directory"], :ignore 
=> %r{^ignored_directory/}, :recursive => true) do
+                    touch 'ignored_directory/new_file.rb'
+                  end
+
+                  added.should be_empty
+                  modified.should be_empty
+                  removed.should be_empty
+                end
+              end
+            end
+          end
+
+          context 'with recursive option set to false' do
+            it "doesn't detect deeply-nested added files" do
+              fixtures do |path|
+                mkdir 'a_directory'
+
+                modified, added, removed = changes(path, :recursive => false) do
+                  touch 'a_directory/new_file.rb'
+                end
+
+                added.should be_empty
+                modified.should be_empty
+                removed.should be_empty
+              end
+            end
+          end
+        end
+
+        context 'given a directory with subdirectories' do
+          it 'detects the added file' do
+            fixtures do |path|
+              mkdir_p 'a_directory/subdirectory'
+
+              modified, added, removed = changes(path, :recursive => true) do
+                touch 'a_directory/subdirectory/new_file.rb'
+              end
+
+              added.should =~ %w(a_directory/subdirectory/new_file.rb)
+              modified.should be_empty
+              removed.should be_empty
+            end
+          end
+
+          context 'with an ignored directory' do
+            it "doesn't detect added files in neither the directory nor the subdirectory" do
+              fixtures do |path|
+                mkdir_p 'ignored_directory/subdirectory'
+
+                modified, added, removed = changes(path, :ignore => %r{^ignored_directory/}, :recursive => 
true) do
+                  touch 'ignored_directory/new_file.rb'
+                  touch 'ignored_directory/subdirectory/new_file.rb'
+                end
+
+                added.should be_empty
+                modified.should be_empty
+                removed.should be_empty
+              end
+            end
+          end
+        end
+      end
+
+      context 'when a file is modified' do
+        it 'detects the modified file' do
+          fixtures do |path|
+            touch 'existing_file.txt'
+
+            modified, added, removed = changes(path) do
+              small_time_difference
+              touch 'existing_file.txt'
+            end
+
+            added.should be_empty
+            modified.should =~ %w(existing_file.txt)
+            removed.should be_empty
+          end
+        end
+
+        context 'during the same second at which we are checking for changes' do
+          before { ensure_same_second }
+
+          # The following test can only be run on systems that report
+          # modification times in milliseconds.
+          it 'always detects the modified file the first time', :if => 
described_class::HIGH_PRECISION_SUPPORTED do
+            fixtures do |path|
+              touch 'existing_file.txt'
+
+              modified, added, removed = changes(path) do
+                small_time_difference
+                touch 'existing_file.txt'
+              end
+
+              added.should be_empty
+              modified.should =~ %w(existing_file.txt)
+              removed.should be_empty
+            end
+          end
+
+          context 'when a file is created and then checked for modifications at the same second - #27' do
+            # This issue was the result of checking a file for content changes when
+            # the mtime and the checking time are the same. In this case there
+            # is no checksum saved, so the file was reported as being changed.
+            it 'does not report any changes' do
+              fixtures do |path|
+                touch 'a_file.rb'
+
+                modified, added, removed = changes(path)
+
+                added.should be_empty
+                modified.should be_empty
+                removed.should be_empty
+              end
+            end
+          end
+
+          it 'detects the modified file the second time if the content have changed' do
+            fixtures do |path|
+              touch 'existing_file.txt'
+
+              # Set sha1 path checksum
+              changes(path) do
+                touch 'existing_file.txt'
+              end
+
+              changes(path) do
+                small_time_difference
+                touch 'existing_file.txt'
+              end
+
+              modified, added, removed = changes(path, :use_last_record => true) do
+                open('existing_file.txt', 'w') { |f| f.write('foo') }
+              end
+
+              added.should be_empty
+              modified.should =~ %w(existing_file.txt)
+              removed.should be_empty
+            end
+          end
+
+          it "doesn't checksum the contents of local sockets (#85)", :unless => windows? do
+            require 'socket'
+            fixtures do |path|
+              Digest::SHA1.should_not_receive(:file)
+              socket_path = File.join(path, "unix_domain_socket")
+              server = UNIXServer.new(socket_path)
+              modified, added, removed = changes(path) do
+                t = Thread.new do
+                  client = UNIXSocket.new(socket_path)
+                  client.write("foo")
+                end
+                t.join
+              end
+              added.should be_empty
+              modified.should be_empty
+              removed.should be_empty
+            end
+          end
+
+          it "doesn't detects the modified file the second time if just touched - #62", :unless => 
described_class::HIGH_PRECISION_SUPPORTED do
+            fixtures do |path|
+              touch 'existing_file.txt'
+
+              # Set sha1 path checksum
+              changes(path) do
+                touch 'existing_file.txt'
+              end
+
+              changes(path, :use_last_record => true) do
+                small_time_difference
+                open('existing_file.txt', 'w') { |f| f.write('foo') }
+              end
+
+              modified, added, removed = changes(path, :use_last_record => true) do
+                touch 'existing_file.txt'
+              end
+
+              added.should be_empty
+              modified.should be_empty
+              removed.should be_empty
+            end
+          end
+
+          it "adds the path in the paths checksums if just touched - #62" do
+            fixtures do |path|
+              touch 'existing_file.txt'
+
+              changes(path) do
+                small_time_difference
+                touch 'existing_file.txt'
+              end
+
+              @record.sha1_checksums["#{path}/existing_file.txt"].should_not be_nil
+            end
+          end
+
+          it "deletes the path from the paths checksums" do
+            fixtures do |path|
+              touch 'unnecessary.txt'
+
+              changes(path) do
+                @record.sha1_checksums["#{path}/unnecessary.txt"] = 'foo'
+
+                rm 'unnecessary.txt'
+              end
+
+              @record.sha1_checksums["#{path}/unnecessary.txt"].should be_nil
+            end
+          end
+        end
+
+        context 'given a hidden file' do
+          it 'detects the modified file' do
+            fixtures do |path|
+              touch '.hidden'
+
+              modified, added, removed = changes(path) do
+                small_time_difference
+                touch '.hidden'
+              end
+
+              added.should be_empty
+              modified.should =~ %w(.hidden)
+              removed.should be_empty
+            end
+          end
+        end
+
+        context 'given a file mode change' do
+          it 'does not detect the mode change' do
+            fixtures do |path|
+              touch 'run.rb'
+
+              modified, added, removed = changes(path) do
+                small_time_difference
+                chmod 0777, 'run.rb'
+              end
+
+              added.should be_empty
+              modified.should be_empty
+              removed.should be_empty
+            end
+          end
+        end
+
+        context 'given an existing directory' do
+          context 'with recursive option set to true' do
+            it 'detects the modified file' do
+              fixtures do |path|
+                mkdir 'a_directory'
+                touch 'a_directory/existing_file.txt'
+
+                modified, added, removed = changes(path, :recursive => true) do
+                  small_time_difference
+                  touch 'a_directory/existing_file.txt'
+                end
+
+                added.should be_empty
+                modified.should =~ %w(a_directory/existing_file.txt)
+                removed.should be_empty
+              end
+            end
+          end
+
+          context 'with recursive option set to false' do
+            it "doesn't detects the modified file" do
+              fixtures do |path|
+                mkdir 'a_directory'
+                touch 'a_directory/existing_file.txt'
+
+                modified, added, removed = changes(path, :recursive => false) do
+                  small_time_difference
+                  touch 'a_directory/existing_file.txt'
+                end
+
+                added.should be_empty
+                modified.should be_empty
+                removed.should be_empty
+              end
+            end
+          end
+        end
+
+        context 'given a directory with subdirectories' do
+          it 'detects the modified file' do
+            fixtures do |path|
+              mkdir_p 'a_directory/subdirectory'
+              touch   'a_directory/subdirectory/existing_file.txt'
+
+              modified, added, removed = changes(path, :recursive => true) do
+                small_time_difference
+                touch 'a_directory/subdirectory/existing_file.txt'
+              end
+
+              added.should be_empty
+              modified.should =~ %w(a_directory/subdirectory/existing_file.txt)
+              removed.should be_empty
+            end
+          end
+
+          context 'with an ignored subdirectory' do
+            it "doesn't detect the modified files in neither the directory nor the subdirectory" do
+              fixtures do |path|
+                mkdir_p 'ignored_directory/subdirectory'
+                touch   'ignored_directory/existing_file.txt'
+                touch   'ignored_directory/subdirectory/existing_file.txt'
+
+                modified, added, removed = changes(path, :ignore => %r{^ignored_directory/}, :recursive => 
true) do
+                  touch 'ignored_directory/existing_file.txt'
+                  touch 'ignored_directory/subdirectory/existing_file.txt'
+                end
+
+                added.should be_empty
+                modified.should be_empty
+                removed.should be_empty
+              end
+            end
+          end
+        end
+      end
+
+      context 'when a file is moved' do
+        it 'detects the file movement' do
+          fixtures do |path|
+            touch 'move_me.txt'
+
+            modified, added, removed = changes(path) do
+              mv 'move_me.txt', 'new_name.txt'
+            end
+
+            added.should =~ %w(new_name.txt)
+            modified.should be_empty
+            removed.should =~ %w(move_me.txt)
+          end
+        end
+
+        context 'given an existing directory' do
+          context 'with recursive option set to true' do
+            it 'detects the file movement into the directory' do
+              fixtures do |path|
+                mkdir 'a_directory'
+                touch 'move_me.txt'
+
+                modified, added, removed = changes(path, :recursive => true) do
+                  mv 'move_me.txt', 'a_directory/move_me.txt'
+                end
+
+                added.should =~ %w(a_directory/move_me.txt)
+                modified.should be_empty
+                removed.should =~ %w(move_me.txt)
+              end
+            end
+
+            it 'detects a file movement out of the directory' do
+              fixtures do |path|
+                mkdir 'a_directory'
+                touch 'a_directory/move_me.txt'
+
+                modified, added, removed = changes(path, :recursive => true) do
+                  mv 'a_directory/move_me.txt', 'i_am_here.txt'
+                end
+
+                added.should =~ %w(i_am_here.txt)
+                modified.should be_empty
+                removed.should =~ %w(a_directory/move_me.txt)
+              end
+            end
+
+            it 'detects a file movement between two directories' do
+              fixtures do |path|
+                mkdir 'from_directory'
+                touch 'from_directory/move_me.txt'
+                mkdir 'to_directory'
+
+                modified, added, removed = changes(path, :recursive => true) do
+                  mv 'from_directory/move_me.txt', 'to_directory/move_me.txt'
+                end
+
+                added.should =~ %w(to_directory/move_me.txt)
+                modified.should be_empty
+                removed.should =~ %w(from_directory/move_me.txt)
+              end
+            end
+          end
+
+          context 'with recursive option set to false' do
+            it "doesn't detect the file movement into the directory" do
+              fixtures do |path|
+                mkdir 'a_directory'
+                touch 'move_me.txt'
+
+                modified, added, removed = changes(path, :recursive => false) do
+                  mv 'move_me.txt', 'a_directory/move_me.txt'
+                end
+
+                added.should be_empty
+                modified.should be_empty
+                removed.should =~ %w(move_me.txt)
+              end
+            end
+
+            it "doesn't detect a file movement out of the directory" do
+              fixtures do |path|
+                mkdir 'a_directory'
+                touch 'a_directory/move_me.txt'
+
+                modified, added, removed = changes(path, :recursive => false) do
+                  mv 'a_directory/move_me.txt', 'i_am_here.txt'
+                end
+
+                added.should =~ %w(i_am_here.txt)
+                modified.should be_empty
+                removed.should be_empty
+              end
+            end
+
+            it "doesn't detect a file movement between two directories" do
+              fixtures do |path|
+                mkdir 'from_directory'
+                touch 'from_directory/move_me.txt'
+                mkdir 'to_directory'
+
+                modified, added, removed = changes(path, :recursive => false) do
+                  mv 'from_directory/move_me.txt', 'to_directory/move_me.txt'
+                end
+
+                added.should be_empty
+                modified.should be_empty
+                removed.should be_empty
+              end
+            end
+
+            context 'given a directory with subdirectories' do
+              it 'detects a file movement between two subdirectories' do
+                fixtures do |path|
+                  mkdir_p 'a_directory/subdirectory'
+                  mkdir_p 'b_directory/subdirectory'
+                  touch   'a_directory/subdirectory/move_me.txt'
+
+                  modified, added, removed = changes(path, :recursive => true) do
+                    mv 'a_directory/subdirectory/move_me.txt', 'b_directory/subdirectory'
+                  end
+
+                  added.should =~ %w(b_directory/subdirectory/move_me.txt)
+                  modified.should be_empty
+                  removed.should =~ %w(a_directory/subdirectory/move_me.txt)
+                end
+              end
+
+              context 'with an ignored subdirectory' do
+                it "doesn't detect the file movement between subdirectories" do
+                  fixtures do |path|
+                    mkdir_p 'a_ignored_directory/subdirectory'
+                    mkdir_p 'b_ignored_directory/subdirectory'
+                    touch   'a_ignored_directory/subdirectory/move_me.txt'
+
+                    modified, added, removed = changes(path, :ignore => %r{^(?:a|b)_ignored_directory/}, 
:recursive => true) do
+                      mv 'a_ignored_directory/subdirectory/move_me.txt', 'b_ignored_directory/subdirectory'
+                    end
+
+                    added.should be_empty
+                    modified.should be_empty
+                    removed.should be_empty
+                  end
+                end
+              end
+            end
+
+            context 'with all paths passed as params' do
+              it 'detects the file movement into the directory' do
+                fixtures do |path|
+                  mkdir 'a_directory'
+                  touch 'move_me.txt'
+
+                  modified, added, removed = changes(path, :recursive => false, :paths => [path, 
"#{path}/a_directory"]) do
+                    mv 'move_me.txt', 'a_directory/move_me.txt'
+                  end
+
+                  added.should =~ %w(a_directory/move_me.txt)
+                  modified.should be_empty
+                  removed.should =~ %w(move_me.txt)
+                end
+              end
+
+              it 'detects a file moved outside of a directory' do
+                fixtures do |path|
+                  mkdir 'a_directory'
+                  touch 'a_directory/move_me.txt'
+
+                  modified, added, removed = changes(path, :recursive => false, :paths => [path, 
"#{path}/a_directory"]) do
+                    mv 'a_directory/move_me.txt', 'i_am_here.txt'
+                  end
+
+                  added.should =~ %w(i_am_here.txt)
+                  modified.should be_empty
+                  removed.should =~ %w(a_directory/move_me.txt)
+                end
+              end
+
+              it 'detects a file movement between two directories' do
+                fixtures do |path|
+                  mkdir 'from_directory'
+                  touch 'from_directory/move_me.txt'
+                  mkdir 'to_directory'
+
+                  modified, added, removed = changes(path, :recursive => false, :paths => [path, 
"#{path}/from_directory", "#{path}/to_directory"]) do
+                    mv 'from_directory/move_me.txt', 'to_directory/move_me.txt'
+                  end
+
+                  added.should =~ %w(to_directory/move_me.txt)
+                  modified.should be_empty
+                  removed.should =~ %w(from_directory/move_me.txt)
+                end
+              end
+            end
+          end
+        end
+      end
+
+      context 'when a file is deleted' do
+        it 'detects the file removal' do
+          fixtures do |path|
+            touch 'unnecessary.txt'
+
+            modified, added, removed = changes(path) do
+              rm 'unnecessary.txt'
+            end
+
+            added.should be_empty
+            modified.should be_empty
+            removed.should =~ %w(unnecessary.txt)
+          end
+        end
+
+        it "deletes the file from the record" do
+          fixtures do |path|
+            touch 'unnecessary.txt'
+
+            changes(path) do
+              @record.paths[path]['unnecessary.txt'].should_not be_nil
+
+              rm 'unnecessary.txt'
+            end
+
+            @record.paths[path]['unnecessary.txt'].should be_nil
+          end
+        end
+
+        it "deletes the path from the paths checksums" do
+          fixtures do |path|
+            touch 'unnecessary.txt'
+
+            changes(path) do
+              @record.sha1_checksums["#{path}/unnecessary.txt"] = 'foo'
+
+              rm 'unnecessary.txt'
+            end
+
+            @record.sha1_checksums["#{path}/unnecessary.txt"].should be_nil
+          end
+        end
+
+        context 'given an existing directory' do
+          context 'with recursive option set to true' do
+            it 'detects the file removal' do
+              fixtures do |path|
+                mkdir 'a_directory'
+                touch 'a_directory/do_not_use.rb'
+
+                modified, added, removed = changes(path, :recursive => true) do
+                  rm 'a_directory/do_not_use.rb'
+                end
+
+                added.should be_empty
+                modified.should be_empty
+                removed.should =~ %w(a_directory/do_not_use.rb)
+              end
+            end
+          end
+
+          context 'with recursive option set to false' do
+            it "doesn't detect the file removal" do
+              fixtures do |path|
+                mkdir 'a_directory'
+                touch 'a_directory/do_not_use.rb'
+
+                modified, added, removed = changes(path, :recursive => false) do
+                  rm 'a_directory/do_not_use.rb'
+                end
+
+                added.should be_empty
+                modified.should be_empty
+                removed.should be_empty
+              end
+            end
+          end
+        end
+
+        context 'given a directory with subdirectories' do
+          it 'detects the file removal in subdirectories' do
+            fixtures do |path|
+              mkdir_p 'a_directory/subdirectory'
+              touch   'a_directory/subdirectory/do_not_use.rb'
+
+              modified, added, removed = changes(path, :recursive => true) do
+                rm 'a_directory/subdirectory/do_not_use.rb'
+              end
+
+              added.should be_empty
+              modified.should be_empty
+              removed.should =~ %w(a_directory/subdirectory/do_not_use.rb)
+            end
+          end
+
+          context 'with an ignored subdirectory' do
+            it "doesn't detect files removals in neither the directory nor its subdirectories" do
+              fixtures do |path|
+                mkdir_p 'ignored_directory/subdirectory'
+                touch   'ignored_directory/do_not_use.rb'
+                touch   'ignored_directory/subdirectory/do_not_use.rb'
+
+                modified, added, removed = changes(path, :ignore => %r{^ignored_directory/}, :recursive => 
true) do
+                  rm 'ignored_directory/do_not_use.rb'
+                  rm 'ignored_directory/subdirectory/do_not_use.rb'
+                end
+
+                added.should be_empty
+                modified.should be_empty
+                removed.should be_empty
+              end
+            end
+          end
+        end
+      end
+    end
+
+    context 'multiple file operations' do
+      it 'detects the added files' do
+        fixtures do |path|
+          modified, added, removed = changes(path) do
+            touch 'a_file.rb'
+            touch 'b_file.rb'
+            mkdir 'a_directory'
+            touch 'a_directory/a_file.rb'
+            touch 'a_directory/b_file.rb'
+          end
+
+          added.should =~ %w(a_file.rb b_file.rb a_directory/a_file.rb a_directory/b_file.rb)
+          modified.should be_empty
+          removed.should be_empty
+        end
+      end
+
+      it 'detects the modified files' do
+        fixtures do |path|
+          touch 'a_file.rb'
+          touch 'b_file.rb'
+          mkdir 'a_directory'
+          touch 'a_directory/a_file.rb'
+          touch 'a_directory/b_file.rb'
+
+          modified, added, removed = changes(path) do
+            small_time_difference
+            touch 'b_file.rb'
+            touch 'a_directory/a_file.rb'
+          end
+
+          added.should be_empty
+          modified.should =~ %w(b_file.rb a_directory/a_file.rb)
+          removed.should be_empty
+        end
+      end
+
+      it 'detects the removed files' do
+        fixtures do |path|
+          touch 'a_file.rb'
+          touch 'b_file.rb'
+          mkdir 'a_directory'
+          touch 'a_directory/a_file.rb'
+          touch 'a_directory/b_file.rb'
+
+          modified, added, removed = changes(path) do
+            rm 'b_file.rb'
+            rm 'a_directory/a_file.rb'
+          end
+
+          added.should be_empty
+          modified.should be_empty
+          removed.should =~ %w(b_file.rb a_directory/a_file.rb)
+        end
+      end
+    end
+
+    context 'single directory operations' do
+      it 'detects a moved directory' do
+        fixtures do |path|
+          mkdir 'a_directory'
+          mkdir 'a_directory/nested'
+          touch 'a_directory/a_file.rb'
+          touch 'a_directory/b_file.rb'
+          touch 'a_directory/nested/c_file.rb'
+
+          modified, added, removed = changes(path) do
+            mv 'a_directory', 'renamed'
+          end
+
+          added.should =~ %w(renamed/a_file.rb renamed/b_file.rb renamed/nested/c_file.rb)
+          modified.should be_empty
+          removed.should =~ %w(a_directory/a_file.rb a_directory/b_file.rb a_directory/nested/c_file.rb)
+        end
+      end
+
+      it 'detects a removed directory' do
+        fixtures do |path|
+          mkdir 'a_directory'
+          touch 'a_directory/a_file.rb'
+          touch 'a_directory/b_file.rb'
+
+          modified, added, removed = changes(path) do
+            rm_rf 'a_directory'
+          end
+
+          added.should be_empty
+          modified.should be_empty
+          removed.should =~ %w(a_directory/a_file.rb a_directory/b_file.rb)
+        end
+      end
+
+      it "deletes the directory from the record" do
+        fixtures do |path|
+          mkdir 'a_directory'
+          touch 'a_directory/file.rb'
+
+          changes(path) do
+            @record.paths.should have(2).paths
+            @record.paths[path]['a_directory'].should_not be_nil
+            @record.paths["#{path}/a_directory"]['file.rb'].should_not be_nil
+
+            rm_rf 'a_directory'
+          end
+
+          @record.paths.should have(1).paths
+          @record.paths[path]['a_directory'].should be_nil
+          @record.paths["#{path}/a_directory"]['file.rb'].should be_nil
+        end
+      end
+
+      context 'with nested paths' do
+        it 'detects removals without crashing - #18' do
+          fixtures do |path|
+            mkdir_p 'a_directory/subdirectory'
+            touch   'a_directory/subdirectory/do_not_use.rb'
+
+            modified, added, removed = changes(path) do
+              rm_r 'a_directory'
+            end
+
+            added.should be_empty
+            modified.should be_empty
+            removed.should =~ %w(a_directory/subdirectory/do_not_use.rb)
+          end
+        end
+      end
+    end
+
+    context 'with a path outside the directory for which a record is made' do
+      it "skips that path and doesn't check for changes" do
+          fixtures do |path|
+            modified, added, removed = changes(path, :paths => ['some/where/outside']) do
+              @record.should_not_receive(:detect_additions)
+              @record.should_not_receive(:detect_modifications_and_removals)
+
+              touch 'new_file.rb'
+            end
+
+            added.should be_empty
+            modified.should be_empty
+            removed.should be_empty
+          end
+      end
+    end
+
+    context 'with the relative_paths option set to false' do
+      it 'returns full paths in the changes hash' do
+        fixtures do |path|
+          touch 'a_file.rb'
+          touch 'b_file.rb'
+
+          modified, added, removed = changes(path, :relative_paths => false) do
+            small_time_difference
+            rm    'a_file.rb'
+            touch 'b_file.rb'
+            touch 'c_file.rb'
+            mkdir 'a_directory'
+            touch 'a_directory/a_file.rb'
+          end
+
+          added.should =~ ["#{path}/c_file.rb", "#{path}/a_directory/a_file.rb"]
+          modified.should =~ ["#{path}/b_file.rb"]
+          removed.should =~ ["#{path}/a_file.rb"]
+        end
+      end
+    end
+
+    context 'within a directory containing unreadble paths - #32' do
+      it 'detects changes more than a second apart' do
+        fixtures do |path|
+          touch 'unreadable_file.txt'
+          chmod 000, 'unreadable_file.txt'
+
+          modified, added, removed = changes(path) do
+            small_time_difference
+            touch 'unreadable_file.txt'
+          end
+
+          added.should be_empty
+          modified.should =~ %w(unreadable_file.txt)
+          removed.should be_empty
+        end
+      end
+
+      context 'with multiple changes within the same second' do
+        before { ensure_same_second }
+
+        it 'does not detect changes even if content changes', :unless => 
described_class::HIGH_PRECISION_SUPPORTED do
+          fixtures do |path|
+            touch 'unreadable_file.txt'
+
+            modified, added, removed = changes(path) do
+              open('unreadable_file.txt', 'w') { |f| f.write('foo') }
+              chmod 000, 'unreadable_file.txt'
+            end
+
+            added.should be_empty
+            modified.should be_empty
+            removed.should be_empty
+          end
+        end
+      end
+    end
+
+    context 'within a directory containing a removed file - #39' do
+      it 'does not raise an exception when hashing a removed file' do
+
+        # simulate a race condition where the file is removed after the
+        # change event is tracked, but before the hash is calculated
+        Digest::SHA1.should_receive(:file).twice.and_raise(Errno::ENOENT)
+
+        fixtures do |path|
+          lambda {
+            touch 'removed_file.txt'
+            changes(path) { touch 'removed_file.txt' }
+          }.should_not raise_error
+        end
+      end
+    end
+
+    context 'within a directory containing a unix domain socket file', :unless => windows? do
+      it 'does not raise an exception when hashing a unix domain socket file' do
+        fixtures do |path|
+          require 'socket'
+          UNIXServer.new('unix_domain_socket.sock')
+          lambda { changes(path){} }.should_not raise_error
+        end
+      end
+    end
+
+    context 'with symlinks', :unless => windows? do
+      it 'looks at symlinks not their targets' do
+        fixtures do |path|
+          touch 'target'
+          symlink 'target', 'symlink'
+
+          record = described_class.new(path)
+          record.build
+
+          sleep 1
+          touch 'target'
+
+          record.fetch_changes([path], :relative_paths => true)[:modified].should == ['target']
+        end
+      end
+
+      it 'handles broken symlinks' do
+        fixtures do |path|
+          symlink 'target', 'symlink'
+
+          record = described_class.new(path)
+          record.build
+
+          sleep 1
+          rm 'symlink'
+          symlink 'new-target', 'symlink'
+          record.fetch_changes([path], :relative_paths => true)
+        end
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/listener_spec.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/listener_spec.rb
new file mode 100644
index 0000000..58991a8
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/listener_spec.rb
@@ -0,0 +1,258 @@
+require 'spec_helper'
+
+describe Listen::Listener do
+  let(:adapter)             { double(Listen::Adapter, :start => true).as_null_object }
+  let(:watched_directories) { [File.dirname(__FILE__), File.expand_path('../..', __FILE__)] }
+
+  before do
+    Listen::Adapter.stub(:select_and_initialize) { adapter }
+    # Don't build a record of the files inside the base directory.
+    Listen::DirectoryRecord.any_instance.stub(:build)
+    Kernel.stub(:warn)
+  end
+  subject { described_class.new(watched_directories) }
+
+  it_should_behave_like 'a listener to changes on a file-system'
+
+  describe '#initialize' do
+    context 'listening to a single directory' do
+      let(:watched_directory)   { File.dirname(__FILE__) }
+      let(:watched_directories) { nil }
+      subject { described_class.new(watched_directory) }
+
+      it 'sets the directories' do
+        subject.directories.should eq [watched_directory]
+      end
+
+      context 'with no options' do
+        it 'sets the option for using relative paths in the callback to false' do
+          subject.instance_variable_get(:@use_relative_paths).should eq false
+        end
+      end
+
+      context 'with :relative_paths => false' do
+        it 'sets the option for using relative paths in the callback to false' do
+          listener = described_class.new(watched_directory, :relative_paths => false)
+          listener.instance_variable_get(:@use_relative_paths).should eq false
+        end
+      end
+
+      context 'with :relative_paths => true' do
+        it 'sets the option for using relative paths in the callback to true' do
+          listener = described_class.new(watched_directory, :relative_paths => true)
+          listener.instance_variable_get(:@use_relative_paths).should eq true
+        end
+      end
+    end
+
+    context 'listening to multiple directories' do
+      subject { described_class.new(watched_directories) }
+
+      it 'sets the directories' do
+        subject.directories.should eq watched_directories
+      end
+
+      context 'with no options' do
+        it 'sets the option for using relative paths in the callback to false' do
+          subject.instance_variable_get(:@use_relative_paths).should eq false
+        end
+      end
+
+      context 'with :relative_paths => false' do
+        it 'sets the option for using relative paths in the callback to false' do
+          listener = described_class.new(watched_directories, :relative_paths => false)
+          listener.instance_variable_get(:@use_relative_paths).should eq false
+        end
+      end
+
+      context 'with :relative_paths => true' do
+        it 'warns' do
+          Kernel.should_receive(:warn).with("[Listen warning]: 
#{Listen::Listener::RELATIVE_PATHS_WITH_MULTIPLE_DIRECTORIES_WARNING_MESSAGE}")
+          listener = described_class.new(watched_directories, :relative_paths => true)
+        end
+
+        it 'sets the option for using relative paths in the callback to false' do
+          listener = described_class.new(watched_directories, :relative_paths => true)
+          listener.instance_variable_get(:@use_relative_paths).should eq false
+        end
+      end
+    end
+
+    context 'with a directory' do
+      let(:watched_directory)   { File.dirname(__FILE__) }
+      it 'converts the passed path into an absolute path - #21' do
+        described_class.new(File.join(watched_directory, '..')).directories.should eq 
[File.expand_path('..', watched_directory)]
+      end
+    end
+
+    context 'with custom options' do
+      let(:watched_directory)   { File.dirname(__FILE__) }
+      let(:adapter_class) { double('adapter class') }
+
+      let(:options) do
+        {
+          :ignore => /\.ssh/, :filter => [/.*\.rb/, /.*\.md/],
+          :latency => 0.5, :force_polling => true, :relative_paths => true,
+          :force_adapter => adapter_class
+        }
+      end
+      subject { described_class.new(watched_directory, options) }
+
+      it 'passes the custom ignored paths to the directory record' do
+        subject.directories_records.each do |directory_record|
+          directory_record.ignoring_patterns.should include /\.ssh/
+        end
+      end
+
+      it 'passes the custom filters to the directory record' do
+        subject.directories_records.each do |directory_record|
+          directory_record.filtering_patterns.should =~  [/.*\.rb/,/.*\.md/]
+        end
+      end
+
+      it 'sets adapter_options' do
+        subject.instance_variable_get(:@adapter_options).should eq(:latency => 0.5, :force_polling => true, 
:force_adapter => adapter_class)
+      end
+    end
+  end
+
+  describe '#start' do
+    it 'selects and initializes an adapter' do
+      Listen::Adapter.should_receive(:select_and_initialize).with(watched_directories, {}) { adapter }
+      subject.start
+    end
+
+    it 'builds the directory record' do
+      subject.directories_records.each do |directory_record|
+        directory_record.should_receive(:build)
+      end
+      subject.start
+    end
+  end
+
+  context 'with a started listener' do
+    before do
+      subject.stub(:initialize_adapter) { adapter }
+      subject.start
+    end
+
+    describe '#unpause' do
+      it 'rebuilds the directory record' do
+        subject.directories_records.each do |directory_record|
+          directory_record.should_receive(:build)
+        end
+        subject.unpause
+      end
+    end
+  end
+
+  describe '#ignore'do
+    it 'delegates the work to the directory record' do
+      subject.directories_records.each do |directory_record|
+        directory_record.should_receive(:ignore).with 'some_directory'
+      end
+      subject.ignore 'some_directory'
+    end
+  end
+
+  describe '#ignore!'do
+    it 'delegates the work to the directory record' do
+      subject.directories_records.each do |directory_record|
+        directory_record.should_receive(:ignore!).with 'some_directory'
+      end
+      subject.ignore! 'some_directory'
+    end
+  end
+
+  describe '#filter' do
+    it 'delegates the work to the directory record' do
+      subject.directories_records.each do |directory_record|
+        directory_record.should_receive(:filter).with /\.txt$/
+      end
+      subject.filter /\.txt$/
+    end
+  end
+
+  describe '#filter!' do
+    it 'delegates the work to the directory record' do
+      subject.directories_records.each do |directory_record|
+        directory_record.should_receive(:filter!).with /\.txt$/
+      end
+      subject.filter! /\.txt$/
+    end
+  end
+
+  describe '#on_change' do
+    let(:directories) { %w{dir1 dir2 dir3} }
+    let(:changes)     { {:modified => [], :added => [], :removed => []} }
+    let(:callback)    { Proc.new { @called = true } }
+
+    before do
+      @called = false
+      subject.stub(:fetch_records_changes => changes)
+    end
+
+    it 'fetches the changes of all directories records' do
+      subject.unstub(:fetch_records_changes)
+
+      subject.directories_records.each do |record|
+        record.should_receive(:fetch_changes).with(directories, an_instance_of(Hash)).and_return(changes)
+      end
+      subject.on_change(directories)
+    end
+
+    context "with a callback raising an exception" do
+      let(:callback) { Proc.new { raise 'foo' } }
+
+      before do
+        subject.change(&callback)
+        subject.stub(:fetch_records_changes => { :modified => ['foo'], :added => [], :removed => [] } )
+      end
+
+      it "stops the adapter and warns" do
+        Kernel.should_receive(:warn).with("[Listen warning]: Change block raise an execption: foo")
+        Kernel.should_receive(:warn).with(/^Backtrace:.*/)
+        subject.on_change(directories)
+      end
+
+    end
+
+    context 'with no changes to report' do
+      if RUBY_VERSION[/^1.8/]
+        it 'does not run the callback' do
+            subject.change(&callback)
+            subject.on_change(directories)
+            @called.should be_false
+        end
+      else
+        it 'does not run the callback' do
+          callback.should_not_receive(:call)
+          subject.change(&callback)
+          subject.on_change(directories)
+        end
+      end
+    end
+
+    context 'with changes to report' do
+      let(:changes) do
+        {
+          :modified => %w{path1}, :added => [], :removed => %w{path2}
+        }
+      end
+
+      if RUBY_VERSION[/^1.8/]
+        it 'runs the callback passing it the changes' do
+          subject.change(&callback)
+          subject.on_change(directories)
+          @called.should be_true
+        end
+      else
+        it 'runs the callback passing it the changes' do
+          callback.should_receive(:call).with(changes[:modified], changes[:added], changes[:removed])
+          subject.change(&callback)
+          subject.on_change(directories)
+        end
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.2.12/vendor/listen/spec/listen/turnstile_spec.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/turnstile_spec.rb
similarity index 100%
rename from backends/css/gems/sass-3.2.12/vendor/listen/spec/listen/turnstile_spec.rb
rename to backends/css/gems/sass-3.4.9/vendor/listen/spec/listen/turnstile_spec.rb
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/spec/listen_spec.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/spec/listen_spec.rb
new file mode 100644
index 0000000..a5be1f5
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/spec/listen_spec.rb
@@ -0,0 +1,67 @@
+require 'spec_helper'
+
+describe Listen do
+  describe '#to' do
+    let(:listener)       { double(Listen::Listener) }
+    let(:listener_class) { Listen::Listener }
+    before { listener_class.stub(:new => listener) }
+
+    context 'with one path to listen to' do
+      context 'without options' do
+        it 'creates an instance of Listener' do
+          listener_class.should_receive(:new).with('/path')
+          described_class.to('/path')
+        end
+      end
+
+      context 'with options' do
+        it 'creates an instance of Listener with the passed params' do
+          listener_class.should_receive(:new).with('/path', :filter => '**/*')
+          described_class.to('/path', :filter => '**/*')
+        end
+      end
+
+      context 'without a block' do
+        it 'returns the listener' do
+          described_class.to('/path', :filter => '**/*').should eq listener
+        end
+      end
+
+      context 'with a block' do
+        it 'starts the listener after creating it' do
+          listener.should_receive(:start)
+          described_class.to('/path', :filter => '**/*') { |modified, added, removed| }
+        end
+      end
+    end
+
+    context 'with multiple paths to listen to' do
+      context 'without options' do
+        it 'creates an instance of Listener' do
+          listener_class.should_receive(:new).with('path1', 'path2')
+          described_class.to('path1', 'path2')
+        end
+      end
+
+      context 'with options' do
+        it 'creates an instance of Listener with the passed params' do
+          listener_class.should_receive(:new).with('path1', 'path2', :filter => '**/*')
+          described_class.to('path1', 'path2', :filter => '**/*')
+        end
+      end
+
+      context 'without a block' do
+        it 'returns a Listener instance created with the passed params' do
+          described_class.to('path1', 'path2', :filter => '**/*').should eq listener
+        end
+      end
+
+      context 'with a block' do
+        it 'starts a Listener instance after creating it with the passed params' do
+          listener.should_receive(:start)
+          described_class.to('path1', 'path2', :filter => '**/*') { |modified, added, removed| }
+        end
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/spec/spec_helper.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/spec/spec_helper.rb
new file mode 100644
index 0000000..78590ba
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/spec/spec_helper.rb
@@ -0,0 +1,25 @@
+require 'rubygems'
+require 'coveralls'
+Coveralls.wear!
+
+require 'listen'
+
+Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
+
+# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
+RSpec.configure do |config|
+  config.color_enabled = true
+  config.order = :random
+  config.filter_run :focus => true
+  config.treat_symbols_as_metadata_keys_with_true_values = true
+  config.run_all_when_everything_filtered = true
+  config.filter_run_excluding :broken => true
+  config.fail_fast = true
+end
+
+def test_latency
+  0.1
+end
+
+# Crash loud in tests!
+Thread.abort_on_exception = true
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/spec/support/adapter_helper.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/spec/support/adapter_helper.rb
new file mode 100644
index 0000000..5efed33
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/spec/support/adapter_helper.rb
@@ -0,0 +1,666 @@
+# Adapter watch
+#
+# @param [Listen::Listener] listener the adapter listener
+# @param [String] path the path to watch
+#
+def watch(listener, expected_changes, *paths)
+  sleep 0.05 # allow file/creation to be done (!)
+
+  callback = lambda do |changed_directories, options|
+    @called = true
+    listener.on_change(changed_directories)
+  end
+  @adapter = Listen::Adapter.select_and_initialize(paths, { :latency => test_latency }, &callback)
+  @adapter.stub(:start_poller) { nil }
+
+  forced_stop = false
+  prevent_deadlock = lambda do
+    sleep(10)
+    puts 'Forcing stop'
+    @adapter.stop
+    forced_stop = true
+  end
+
+  @adapter.start
+
+  yield
+
+  t = Thread.new(&prevent_deadlock)
+  @adapter.wait_for_changes(expected_changes)
+
+  unless forced_stop
+    Thread.kill(t)
+    @adapter.report_changes
+  end
+ensure
+  unless forced_stop
+    Thread.kill(t) if t
+    @adapter.stop
+  end
+end
+
+shared_examples_for 'a filesystem adapter' do
+  subject { described_class.new(File.dirname(__FILE__), &Proc.new {}) }
+
+  describe '#start' do
+    before { Kernel.stub(:warn) }
+    after { subject.stop }
+
+    it 'do not block the current thread after starting the workers' do
+      @called = false
+      t = Thread.new { subject.start; @called = true }
+      sleep(test_latency * 3)
+      Thread.kill(t) if t
+      @called.should be_true
+    end
+
+    context 'with the blocking hash option set to false' do
+      subject { described_class.new(File.dirname(__FILE__), { :blocking => false }, &Proc.new {}) }
+
+      it 'does not block the current thread after starting the workers' do
+        @called = false
+        t = Thread.new { subject.start; @called = true }
+        sleep(test_latency * 3)
+        Thread.kill(t) if t
+        @called.should be_true
+      end
+    end
+  end
+
+  describe '#start!' do
+    before { Kernel.stub(:warn) }
+    after { subject.stop }
+
+    it 'blocks the current thread after starting the workers' do
+      @called = false
+      t = Thread.new { subject.start!; @called = true }
+      sleep(test_latency * 3)
+      Thread.kill(t) if t
+      @called.should be_false
+    end
+
+    context 'with the blocking hash option set to false' do
+      subject { described_class.new(File.dirname(__FILE__), { :blocking => true }, &Proc.new {}) }
+
+      it 'blocks the current thread after starting the workers' do
+        @called = false
+        t = Thread.new { subject.start!; @called = true }
+        sleep(test_latency * 3)
+        Thread.kill(t) if t
+        @called.should be_false
+      end
+    end
+  end
+
+  describe '#started?' do
+    context 'with a new adapter' do
+      it 'returns false' do
+        subject.should_not be_started
+      end
+    end
+
+    context 'with a stopped adapter' do
+      before { subject.start; subject.stop }
+
+      it 'returns false' do
+        subject.should_not be_started
+      end
+    end
+
+    context 'with a started adapter' do
+      before { subject.start }
+      after  { subject.stop }
+
+      it 'returns true' do
+        subject.should be_started
+      end
+    end
+  end
+end
+
+shared_examples_for 'an adapter that call properly listener#on_change' do |*args|
+  options = (args.first && args.first.is_a?(Hash)) ? args.first : {}
+  let(:listener) { double(Listen::Listener) }
+  before { described_class.stub(:works?) { true } }
+
+  context 'single file operations' do
+    context 'when a file is created' do
+      it 'detects the added file' do
+        fixtures do |path|
+          listener.should_receive(:on_change).once.with do |array|
+            array.should include(path)
+          end
+
+          watch(listener, 1, path) do
+            touch 'new_file.rb'
+          end
+        end
+      end
+
+      context 'given a symlink', :unless => windows? do
+        it 'detects the added file' do
+          fixtures do |path|
+            listener.should_receive(:on_change).once.with do |array|
+              array.should include(path)
+            end
+
+            touch 'new_file.rb'
+
+            watch(listener, 1, path) do
+              ln_s 'new_file.rb', 'new_file_symlink.rb'
+            end
+          end
+        end
+      end
+
+      context 'given a new created directory' do
+        it 'detects the added file' do
+          fixtures do |path|
+            listener.should_receive(:on_change).once.with do |array|
+              array.should include(path, "#{path}/a_directory")
+            end
+
+            watch(listener, 2, path) do
+              mkdir 'a_directory'
+              # Needed for INotify, because of :recursive rb-inotify custom flag?
+              sleep 0.05
+              touch 'a_directory/new_file.rb'
+            end
+          end
+        end
+      end
+
+      context 'given an existing directory' do
+        it 'detects the added file' do
+          fixtures do |path|
+            listener.should_receive(:on_change).once.with do |array|
+              array.should include("#{path}/a_directory")
+            end
+
+            mkdir 'a_directory'
+
+            watch(listener, 1, path) do
+              touch 'a_directory/new_file.rb'
+            end
+          end
+        end
+      end
+
+      context 'given a directory with subdirectories' do
+        it 'detects the added file' do
+          fixtures do |path|
+            listener.should_receive(:on_change).once.with do |array|
+              array.should include("#{path}/a_directory/subdirectory")
+            end
+
+            mkdir_p 'a_directory/subdirectory'
+
+            watch(listener, 1, path) do
+              touch 'a_directory/subdirectory/new_file.rb'
+            end
+          end
+        end
+      end
+    end
+
+    context 'when a file is modified' do
+      it 'detects the modified file' do
+        fixtures do |path|
+          listener.should_receive(:on_change).once.with do |array|
+            array.should include(path)
+          end
+
+          touch 'existing_file.txt'
+
+          watch(listener, 1, path) do
+            touch 'existing_file.txt'
+          end
+        end
+      end
+
+      context 'given a symlink', :unless => windows? do
+        it 'detects the modified file' do
+          fixtures do |path|
+            listener.should_receive(:on_change).once.with do |array|
+              array.should include(path)
+            end
+
+            touch 'existing_file.rb'
+            ln_s  'existing_file.rb', 'existing_file_symlink.rb'
+
+            watch(listener, 1, path) do
+              touch 'existing_file.rb'
+            end
+          end
+        end
+      end
+
+      context 'given a hidden file' do
+        it 'detects the modified file' do
+          fixtures do |path|
+            listener.should_receive(:on_change).once.with do |array|
+              array.should include(path)
+            end
+
+            touch '.hidden'
+
+            watch(listener, 1, path) do
+              touch '.hidden'
+            end
+          end
+        end
+      end
+
+      context 'given a file mode change', :unless => windows? do
+        it 'does not detect the mode change' do
+          fixtures do |path|
+            listener.should_receive(:on_change).once.with do |array|
+              array.should include(path)
+            end
+
+            touch 'run.rb'
+
+            watch(listener, 1, path) do
+              chmod 0777, 'run.rb'
+            end
+          end
+        end
+      end
+
+      context 'given an existing directory' do
+        it 'detects the modified file' do
+          fixtures do |path|
+            listener.should_receive(:on_change).once.with do |array|
+              array.should include("#{path}/a_directory")
+            end
+
+            mkdir 'a_directory'
+            touch 'a_directory/existing_file.txt'
+
+            watch(listener, 1, path) do
+              touch 'a_directory/existing_file.txt'
+            end
+          end
+        end
+      end
+
+      context 'given a directory with subdirectories' do
+        it 'detects the modified file' do
+          fixtures do |path|
+            listener.should_receive(:on_change).once.with do |array|
+              array.should include("#{path}/a_directory/subdirectory")
+            end
+
+            mkdir_p 'a_directory/subdirectory'
+            touch   'a_directory/subdirectory/existing_file.txt'
+
+            watch(listener, 1, path) do
+              touch 'a_directory/subdirectory/new_file.rb'
+            end
+          end
+        end
+      end
+    end
+
+    context 'when a file is moved' do
+      it 'detects the file move' do
+        fixtures do |path|
+          listener.should_receive(:on_change).once.with do |array|
+            array.should include(path)
+          end
+
+          touch 'move_me.txt'
+
+          watch(listener, 1, path) do
+            mv 'move_me.txt', 'new_name.txt'
+          end
+        end
+      end
+
+      context 'given a symlink', :unless => windows? do
+        it 'detects the file move' do
+          fixtures do |path|
+            listener.should_receive(:on_change).once.with do |array|
+              array.should include(path)
+            end
+
+            touch 'move_me.rb'
+            ln_s  'move_me.rb', 'move_me_symlink.rb'
+
+            watch(listener, 1, path) do
+              mv 'move_me_symlink.rb', 'new_symlink.rb'
+            end
+          end
+        end
+      end
+
+      context 'given an existing directory' do
+        it 'detects the file move into the directory' do
+          fixtures do |path|
+            listener.should_receive(:on_change).once.with do |array|
+              array.should include(path, "#{path}/a_directory")
+            end
+
+            mkdir 'a_directory'
+            touch 'move_me.txt'
+
+            watch(listener, 2, path) do
+              mv 'move_me.txt', 'a_directory/move_me.txt'
+            end
+          end
+        end
+
+        it 'detects a file move out of the directory' do
+          fixtures do |path|
+            listener.should_receive(:on_change).once.with do |array|
+              array.should include(path, "#{path}/a_directory")
+            end
+
+            mkdir 'a_directory'
+            touch 'a_directory/move_me.txt'
+
+            watch(listener, 2, path) do
+              mv 'a_directory/move_me.txt', 'i_am_here.txt'
+            end
+          end
+        end
+
+        it 'detects a file move between two directories' do
+          fixtures do |path|
+            listener.should_receive(:on_change).once.with do |array|
+              array.should include("#{path}/from_directory", "#{path}/to_directory")
+            end
+
+            mkdir 'from_directory'
+            touch 'from_directory/move_me.txt'
+            mkdir 'to_directory'
+
+            watch(listener, 2, path) do
+              mv 'from_directory/move_me.txt', 'to_directory/move_me.txt'
+            end
+          end
+        end
+      end
+
+      context 'given a directory with subdirectories' do
+        it 'detects files movements between subdirectories' do
+          fixtures do |path|
+            listener.should_receive(:on_change).once.with do |array|
+              array.should include("#{path}/a_directory/subdirectory", "#{path}/b_directory/subdirectory")
+            end
+
+            mkdir_p 'a_directory/subdirectory'
+            mkdir_p 'b_directory/subdirectory'
+            touch   'a_directory/subdirectory/move_me.txt'
+
+            watch(listener, 2, path) do
+              mv 'a_directory/subdirectory/move_me.txt', 'b_directory/subdirectory'
+            end
+          end
+        end
+      end
+    end
+
+    context 'when a file is deleted' do
+      it 'detects the file removal' do
+        fixtures do |path|
+          listener.should_receive(:on_change).once.with do |array|
+            array.should include(path)
+          end
+
+          touch 'unnecessary.txt'
+
+          watch(listener, 1, path) do
+            rm 'unnecessary.txt'
+          end
+        end
+      end
+
+      context 'given a symlink', :unless => windows? do
+        it 'detects the file removal' do
+          fixtures do |path|
+            listener.should_receive(:on_change).once.with do |array|
+              array.should include(path)
+            end
+
+            touch 'unnecessary.rb'
+            ln_s  'unnecessary.rb', 'unnecessary_symlink.rb'
+
+            watch(listener, 1, path) do
+              rm 'unnecessary_symlink.rb'
+            end
+          end
+        end
+      end
+
+      context 'given an existing directory' do
+        it 'detects the file removal' do
+          fixtures do |path|
+            listener.should_receive(:on_change).once.with do |array|
+              array.should include("#{path}/a_directory")
+            end
+
+            mkdir 'a_directory'
+            touch 'a_directory/do_not_use.rb'
+
+            watch(listener, 1, path) do
+              rm 'a_directory/do_not_use.rb'
+            end
+          end
+        end
+      end
+
+      context 'given a directory with subdirectories' do
+        it 'detects the file removal' do
+          fixtures do |path|
+            listener.should_receive(:on_change).once.with do |array|
+              array.should include("#{path}/a_directory/subdirectory")
+            end
+
+            mkdir_p 'a_directory/subdirectory'
+            touch   'a_directory/subdirectory/do_not_use.rb'
+
+            watch(listener, 1, path) do
+              rm 'a_directory/subdirectory/do_not_use.rb'
+            end
+          end
+        end
+      end
+    end
+  end
+
+  context 'multiple file operations' do
+    it 'detects the added files' do
+      fixtures do |path|
+        listener.should_receive(:on_change).once.with do |array|
+          array.should include(path, "#{path}/a_directory")
+        end
+
+        watch(listener, 2, path) do
+          touch 'a_file.rb'
+          touch 'b_file.rb'
+          mkdir 'a_directory'
+          # Needed for INotify, because of :recursive rb-inotify custom flag?
+          # Also needed for the osx adapter
+          sleep 0.05
+          touch 'a_directory/a_file.rb'
+          touch 'a_directory/b_file.rb'
+        end
+      end
+    end
+
+    it 'detects the modified files' do
+      fixtures do |path|
+        listener.should_receive(:on_change).once.with do |array|
+          array.should include(path, "#{path}/a_directory")
+        end
+
+        touch 'a_file.rb'
+        touch 'b_file.rb'
+        mkdir 'a_directory'
+        touch 'a_directory/a_file.rb'
+        touch 'a_directory/b_file.rb'
+
+        watch(listener, 2, path) do
+          touch 'b_file.rb'
+          touch 'a_directory/a_file.rb'
+        end
+      end
+    end
+
+    it 'detects the removed files' do
+      fixtures do |path|
+        listener.should_receive(:on_change).once.with do |array|
+          array.should include(path, "#{path}/a_directory")
+        end
+
+        touch 'a_file.rb'
+        touch 'b_file.rb'
+        mkdir 'a_directory'
+        touch 'a_directory/a_file.rb'
+        touch 'a_directory/b_file.rb'
+
+        watch(listener, 2, path) do
+          rm 'b_file.rb'
+          rm 'a_directory/a_file.rb'
+        end
+      end
+    end
+  end
+
+  context 'single directory operations' do
+    it 'detects a moved directory' do
+      fixtures do |path|
+        listener.should_receive(:on_change).once.with do |array|
+          array.should include(path)
+        end
+
+        mkdir 'a_directory'
+        touch 'a_directory/a_file.rb'
+        touch 'a_directory/b_file.rb'
+
+        watch(listener, 1, path) do
+          mv 'a_directory', 'renamed'
+        end
+      end
+    end
+
+    it 'detects a removed directory' do
+      fixtures do |path|
+        listener.should_receive(:on_change).once.with do |array|
+          array.should include(path, "#{path}/a_directory")
+        end
+
+        mkdir 'a_directory'
+        touch 'a_directory/a_file.rb'
+        touch 'a_directory/b_file.rb'
+
+        watch(listener, 2, path) do
+          rm_rf 'a_directory'
+        end
+      end
+    end
+  end
+
+  context "paused adapter" do
+    context 'when a file is created' do
+      it "doesn't detects the added file" do
+        fixtures do |path|
+          watch(listener, 1, path) do # The expected changes param is set to one!
+            @adapter.paused = true
+            touch 'new_file.rb'
+          end
+          @called.should be_nil
+        end
+      end
+    end
+  end
+
+  context "when multiple directories are listened to" do
+    context 'when files are added to one of multiple directories' do
+      it 'detects added files' do
+        fixtures(2) do |path1, path2|
+          listener.should_receive(:on_change).once.with do |array|
+            array.should include(path2)
+          end
+
+          watch(listener, 1, path1, path2) do
+            touch "#{path2}/new_file.rb"
+          end
+        end
+      end
+    end
+
+    context 'when files are added to multiple directories' do
+      it 'detects added files' do
+        fixtures(2) do |path1, path2|
+          listener.should_receive(:on_change).once.with do |array|
+            array.should include(path1, path2)
+          end
+
+          watch(listener, 2, path1, path2) do
+            touch "#{path1}/new_file.rb"
+            touch "#{path2}/new_file.rb"
+          end
+        end
+      end
+    end
+
+    context 'given a new and an existing directory on multiple directories' do
+      it 'detects the added file' do
+        fixtures(2) do |path1, path2|
+          listener.should_receive(:on_change).once.with do |array|
+            array.should include(path2, "#{path1}/a_directory", "#{path2}/b_directory")
+          end
+
+          mkdir "#{path1}/a_directory"
+
+          watch(listener, 3, path1, path2) do
+            mkdir "#{path2}/b_directory"
+            # Needed for INotify
+            sleep 0.05
+            touch "#{path1}/a_directory/new_file.rb"
+            touch "#{path2}/b_directory/new_file.rb"
+          end
+        end
+      end
+    end
+
+    context 'when a file is moved between the multiple watched directories' do
+      it 'detects the movements of the file' do
+        fixtures(3) do |path1, path2, path3|
+          listener.should_receive(:on_change).once.with do |array|
+            array.should include("#{path1}/from_directory", path2, "#{path3}/to_directory")
+          end
+
+          mkdir "#{path1}/from_directory"
+          touch "#{path1}/from_directory/move_me.txt"
+          mkdir "#{path3}/to_directory"
+
+          watch(listener, 3, path1, path2, path3) do
+            mv "#{path1}/from_directory/move_me.txt", "#{path2}/move_me.txt"
+            mv "#{path2}/move_me.txt", "#{path3}/to_directory/move_me.txt"
+          end
+        end
+      end
+    end
+
+    context 'when files are deleted from the multiple watched directories' do
+      it 'detects the files removal' do
+        fixtures(2) do |path1, path2|
+          listener.should_receive(:on_change).once.with do |array|
+            array.should include(path1, path2)
+          end
+
+          touch "#{path1}/unnecessary.txt"
+          touch "#{path2}/unnecessary.txt"
+
+          watch(listener, 2, path1, path2) do
+            rm "#{path1}/unnecessary.txt"
+            rm "#{path2}/unnecessary.txt"
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/spec/support/directory_record_helper.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/spec/support/directory_record_helper.rb
new file mode 100644
index 0000000..71bdf60
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/spec/support/directory_record_helper.rb
@@ -0,0 +1,57 @@
+# Prepares a record for the test and fetches changes
+# afterwards.
+#
+# @param [String] root_path the path to watch
+# @param [Hash] options
+# @option options [Array<string>] :paths optional paths fetch changes for
+# @option options [Boolean] :use_last_record allow the use of an already
+#   created record, handy for ordered tests.
+#
+# @return [Array, Array, Array] the changes
+#
+def changes(root_path, options = {})
+  unless @record || options[:use_last_record]
+    @record = Listen::DirectoryRecord.new(root_path)
+    @record.filter(options.delete(:filter)) if options[:filter]
+    @record.ignore(options.delete(:ignore)) if options[:ignore]
+
+    # Build the record after adding the filtering and ignoring patterns
+    @record.build
+  end
+
+  yield if block_given?
+
+  paths = options.delete(:paths) || [root_path]
+  options[:recursive] = true if options[:recursive].nil?
+
+  changes = @record.fetch_changes(paths, { :relative_paths => true }.merge(options))
+
+  [changes[:modified], changes[:added], changes[:removed]]
+end
+
+# Generates a small time difference before performing a time sensitive
+# task (like comparing mtimes of files).
+#
+# @note Modification time for files only includes the milliseconds on Linux with MRI > 1.9.2
+#   and platform that support it (OS X 10.8 not included),
+#   that's why we generate a difference that's greater than 1 second.
+#
+def small_time_difference
+  t = Time.now
+  diff = t.to_f - t.to_i
+
+  sleep(1.05 - diff)
+end
+
+# Ensures that the test runs at almost the same second at which
+# changes are being checked.
+#
+def ensure_same_second
+  t = Time.now
+  diff = t.to_f - t.to_i
+
+  # We are not at the end of a second
+  if diff >= (1 - Listen::Adapter::DEFAULT_LATENCY)
+    sleep(1.05 - diff)
+  end
+end
diff --git a/backends/css/gems/sass-3.2.12/vendor/listen/spec/support/fixtures_helper.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/spec/support/fixtures_helper.rb
similarity index 100%
rename from backends/css/gems/sass-3.2.12/vendor/listen/spec/support/fixtures_helper.rb
rename to backends/css/gems/sass-3.4.9/vendor/listen/spec/support/fixtures_helper.rb
diff --git a/backends/css/gems/sass-3.4.9/vendor/listen/spec/support/listeners_helper.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/spec/support/listeners_helper.rb
new file mode 100644
index 0000000..62992ac
--- /dev/null
+++ b/backends/css/gems/sass-3.4.9/vendor/listen/spec/support/listeners_helper.rb
@@ -0,0 +1,179 @@
+shared_examples_for 'a listener to changes on a file-system' do
+  describe '#start' do
+    before do
+      subject.stub(:initialize_adapter) { adapter }
+    end
+
+    it 'starts the adapter' do
+      adapter.should_receive(:start)
+      subject.start
+    end
+
+    context 'with the blocking deprecated param set to true' do
+      it 'displays a deprecation notice' do
+        Kernel.should_receive(:warn).with(/#{Listen::Listener::BLOCKING_PARAMETER_DEPRECATION_MESSAGE}/)
+        subject.start(true)
+      end
+    end
+
+    context 'with the blocking deprecated param set to false' do
+      it 'displays a deprecation notice' do
+        Kernel.should_receive(:warn).with(/#{Listen::Listener::BLOCKING_PARAMETER_DEPRECATION_MESSAGE}/)
+        subject.start(false)
+      end
+    end
+  end
+
+  describe '#start!' do
+    before do
+      subject.stub(:initialize_adapter) { adapter }
+    end
+
+    it 'starts the adapter' do
+      adapter.should_receive(:start!)
+      subject.start!
+    end
+
+    it 'passes the blocking param to the adapter' do
+      adapter.should_receive(:start!)
+      subject.start!
+    end
+  end
+
+  context 'with a started listener' do
+    before do
+      subject.start
+    end
+
+    describe '#stop' do
+      it "stops adapter" do
+        adapter.should_receive(:stop)
+        subject.stop
+      end
+    end
+
+    describe '#pause' do
+      it 'sets adapter.paused to true' do
+        adapter.should_receive(:pause)
+        subject.pause
+      end
+
+      it 'returns the same listener to allow chaining' do
+        subject.pause.should equal subject
+      end
+    end
+
+    describe '#unpause' do
+      it 'sets adapter.paused to false' do
+        adapter.should_receive(:unpause)
+        subject.unpause
+      end
+
+      it 'returns the same listener to allow chaining' do
+        subject.unpause.should equal subject
+      end
+    end
+
+    describe '#paused?' do
+      it 'returns false when there is no adapter' do
+        subject.instance_variable_set(:@adapter, nil)
+        subject.should_not be_paused
+      end
+
+      it 'returns true when adapter is paused' do
+        adapter.should_receive(:paused?) { true }
+        subject.should be_paused
+      end
+
+      it 'returns false when adapter is not paused' do
+        adapter.should_receive(:paused?) { false }
+        subject.should_not be_paused
+      end
+    end
+  end
+
+  describe '#change' do
+    it 'sets the callback block' do
+      callback = lambda { |modified, added, removed| }
+      subject.change(&callback)
+      subject.instance_variable_get(:@block).should eq callback
+    end
+
+    it 'returns the same listener to allow chaining' do
+      subject.change(&Proc.new{}).should equal subject
+    end
+  end
+
+  describe '#ignore' do
+    it 'returns the same listener to allow chaining' do
+      subject.ignore('some_directory').should equal subject
+    end
+  end
+
+  describe '#ignore!' do
+    it 'returns the same listener to allow chaining' do
+      subject.ignore!('some_directory').should equal subject
+    end
+  end
+
+  describe '#filter' do
+    it 'returns the same listener to allow chaining' do
+      subject.filter(/\.txt$/).should equal subject
+    end
+  end
+
+  describe '#filter!' do
+    it 'returns the same listener to allow chaining' do
+      subject.filter!(/\.txt$/).should equal subject
+    end
+  end
+
+  describe '#latency' do
+    it 'sets the latency to @adapter_options' do
+      subject.latency(0.7)
+      subject.instance_variable_get(:@adapter_options).should eq(:latency => 0.7)
+    end
+
+    it 'returns the same listener to allow chaining' do
+      subject.latency(0.7).should equal subject
+    end
+  end
+
+  describe '#force_polling' do
+    it 'sets force_polling to @adapter_options' do
+      subject.force_polling(false)
+      subject.instance_variable_get(:@adapter_options).should eq(:force_polling => false)
+    end
+
+    it 'returns the same listener to allow chaining' do
+      subject.force_polling(true).should equal subject
+    end
+  end
+
+  describe '#relative_paths' do
+    it 'sets the relative paths option for paths in the callback' do
+      subject.relative_paths(true)
+      subject.instance_variable_get(:@use_relative_paths).should be_true
+    end
+
+    it 'returns the same listener to allow chaining' do
+      subject.relative_paths(true).should equal subject
+    end
+  end
+
+  describe '#polling_fallback_message' do
+    it 'sets custom polling fallback message to @adapter_options' do
+      subject.polling_fallback_message('custom message')
+      subject.instance_variable_get(:@adapter_options).should eq(:polling_fallback_message => 'custom 
message')
+    end
+
+    it 'sets polling fallback message to false in @adapter_options' do
+      subject.polling_fallback_message(false)
+      subject.instance_variable_get(:@adapter_options).should eq(:polling_fallback_message => false)
+    end
+
+    it 'returns the same listener to allow chaining' do
+      subject.polling_fallback_message('custom message').should equal subject
+    end
+  end
+end
diff --git a/backends/css/gems/sass-3.2.12/vendor/listen/spec/support/platform_helper.rb 
b/backends/css/gems/sass-3.4.9/vendor/listen/spec/support/platform_helper.rb
similarity index 100%
rename from backends/css/gems/sass-3.2.12/vendor/listen/spec/support/platform_helper.rb
rename to backends/css/gems/sass-3.4.9/vendor/listen/spec/support/platform_helper.rb


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]