pax_global_header00006660000000000000000000000064140765707620014530gustar00rootroot0000000000000052 comment=8ef1d85c9a55a3866dbc47169dc4df35d40dd9d9 hamlit-2.15.1/000077500000000000000000000000001407657076200130745ustar00rootroot00000000000000hamlit-2.15.1/.github/000077500000000000000000000000001407657076200144345ustar00rootroot00000000000000hamlit-2.15.1/.github/FUNDING.yml000066400000000000000000000000201407657076200162410ustar00rootroot00000000000000github: k0kubun hamlit-2.15.1/.github/workflows/000077500000000000000000000000001407657076200164715ustar00rootroot00000000000000hamlit-2.15.1/.github/workflows/bench.yml000066400000000000000000000034441407657076200203000ustar00rootroot00000000000000name: bench on: push: branches: - master pull_request: types: - opened - synchronize - reopened schedule: - cron: "00 15 * * *" # 7:00 PST (-8), 8:00 PDT (-7) jobs: bench: runs-on: ubuntu-latest strategy: fail-fast: false matrix: include: - slim: 1 - template: 'benchmark/boolean_attribute.haml,benchmark/class_attribute.haml,benchmark/id_attribute.haml,benchmark/data_attribute.haml,benchmark/common_attribute.haml' - template: 'benchmark/dynamic_attributes/boolean_attribute.haml,benchmark/dynamic_attributes/class_attribute.haml,benchmark/dynamic_attributes/id_attribute.haml,benchmark/dynamic_attributes/data_attribute.haml,benchmark/dynamic_attributes/common_attribute.haml' - template: 'benchmark/etc/attribute_builder.haml' - template: 'benchmark/etc/static_analyzer.haml' - template: 'benchmark/etc/string_interpolation.haml' - template: 'test/haml/templates/standard.haml' compile: 1 steps: - uses: actions/checkout@v2 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: 3.0 - uses: actions/cache@v2 with: path: vendor/bundle key: ${{ runner.os }}-${{ matrix.ruby }}-gems-${{ hashFiles('**/Gemfile.lock') }} restore-keys: ${{ runner.os }}-gems- - run: sudo apt-get update && sudo apt-get install -y nodejs libxslt-dev # nodejs for execjs, libxslt for TruffleRuby nokogiri - name: bundle install run: bundle config path vendor/bundle && bundle install -j$(nproc) --retry 3 - run: bundle exec rake bench env: SLIM_BENCH: ${{ matrix.slim }} TEMPLATE: ${{ matrix.template }} COMPILE: ${{ matrix.compile }} hamlit-2.15.1/.github/workflows/test.yml000066400000000000000000000020721407657076200201740ustar00rootroot00000000000000name: test on: push: branches: - master pull_request: types: - opened - synchronize - reopened schedule: - cron: "00 15 * * *" # 7:00 PST (-8), 8:00 PDT (-7) jobs: test: runs-on: ubuntu-latest strategy: fail-fast: false matrix: ruby: - '2.5' - '2.6' - '2.7' - '3.0' - jruby - truffleruby-head steps: - uses: actions/checkout@v2 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} - uses: actions/cache@v2 with: path: vendor/bundle key: ${{ runner.os }}-${{ matrix.ruby }}-gems-${{ hashFiles('**/Gemfile.lock') }} restore-keys: ${{ runner.os }}-gems- - run: sudo apt-get update && sudo apt-get install -y nodejs libxslt-dev # nodejs for execjs, libxslt for TruffleRuby nokogiri - name: bundle install run: bundle config path vendor/bundle && bundle install -j$(nproc) --retry 3 - run: bundle exec rake test hamlit-2.15.1/.gitignore000066400000000000000000000002311407657076200150600ustar00rootroot00000000000000/.bundle/ /.yardoc /Gemfile.lock /_yardoc/ /coverage/ /doc/ /pkg/ /spec/reports/ /tmp/ /haml/ .sass-cache .ruby-version *.bundle *.so *.su *.a *.o *.swp hamlit-2.15.1/CHANGELOG.md000066400000000000000000000630441407657076200147140ustar00rootroot00000000000000# Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). This change log is based upon [keep-a-changelog](https://github.com/olivierlacan/keep-a-changelog). ## [2.15.1](https://github.com/k0kubun/hamlit/compare/v2.15.0...v2.15.1) - 2021-07-23 ### Fixed - Remove `benchmark` from the gem package to reduce its size [#186](https://github.com/k0kubun/hamlit/issues/186) *Thanks to @pocke* ## [2.15.0](https://github.com/k0kubun/hamlit/compare/v2.14.6...v2.15.0) - 2021-04-12 ### Added - Always use Hamlit when both haml.gem and hamlit.gem are installed in Rails *Thanks to @igor-drozdov* ## [2.14.6](https://github.com/k0kubun/hamlit/compare/v2.14.5...v2.14.6) - 2021-03-23 ### Fixed - Optimize v2.14.5's implementation a little ## [2.14.5](https://github.com/k0kubun/hamlit/compare/v2.14.4...v2.14.5) - 2021-03-23 ### Added - Support `config.action_view.annotate_rendered_view_with_filenames = true` of Rails 6.1 *Thanks to @kirin121* ## [2.14.4](https://github.com/k0kubun/hamlit/compare/v2.14.3...v2.14.4) - 2021-02-01 ### Fixed - Prevent another SEGV in a C extension after `GC.compact` [#177](https://github.com/k0kubun/hamlit/issues/177) *Thanks to @stanhu* ## [2.14.3](https://github.com/k0kubun/hamlit/compare/v2.14.2...v2.14.3) - 2021-01-24 ### Fixed - Ensure the Rails initializer is called before `:load_config_initializers` [#176](https://github.com/k0kubun/hamlit/issues/176) *Thanks to @sunny* ## [2.14.2](https://github.com/k0kubun/hamlit/compare/v2.14.1...v2.14.2) - 2021-01-21 ### Fixed - Prevent SEGV in a C extension after `GC.compact` [#171](https://github.com/k0kubun/hamlit/issues/171) *Thanks to @stanhu* ## [2.14.1](https://github.com/k0kubun/hamlit/compare/v2.14.0...v2.14.1) - 2021-01-07 ### Added - Add `-c` option to `hamlit compile` that works like `haml -c` [#166](https://github.com/k0kubun/hamlit/issues/166) *Thanks to @knightq* ## [2.14.0](https://github.com/k0kubun/hamlit/compare/v2.13.2...v2.14.0) - 2021-01-07 ### Changed - CLI changes - Remove `-c` shorthand of `--color`. - Make `--color` default. Please use `--no-color` to disable it. - `--color` uses IRB instead of Pry for syntax highlight. - Syntax highlight of `hamlit compile` is enabled only with IRB of Ruby 2.7+. - Syntax highlight of `hamlit parse` / `hamlit temple` is enabled only with IRB of Ruby 3.1+. ## [2.13.2](https://github.com/k0kubun/hamlit/compare/v2.13.1...v2.13.2) - 2020-12-27 ### Added - Speed up `hamlit` commands [#166](https://github.com/k0kubun/hamlit/issues/166) *Thanks to @knightq* ## [2.13.1](https://github.com/k0kubun/hamlit/compare/v2.13.0...v2.13.1) - 2020-12-27 ### Added - Support [multiline attributes](https://github.com/haml/haml/pull/1043) of Haml 5.2.1. ## [2.13.0](https://github.com/k0kubun/hamlit/compare/v2.12.0...v2.13.0) - 2020-10-02 ### Added - Support `--enable-frozen-string-literal` [#162](https://github.com/k0kubun/hamlit/issues/162). *Thanks to @aliismayilov* ### Changed - Upgrade the Haml parser from Haml 4.0 to 5.2 [#163](https://github.com/k0kubun/hamlit/issues/163). - Allow `@` as tag's class name. - Fix NameError on an `InvalidAttributeNameError` reference introduced at Hamlit v2.12.0. - You can no longer specify `ugly` option, which has had no effect. ## [2.12.0](https://github.com/k0kubun/hamlit/compare/v2.11.1...v2.12.0) - 2020-09-30 ### Changed - Class names are no longer ordered alphabetically. *Thanks to @aliismayilov* - This is compatible with [Haml 5.2](https://github.com/haml/haml/blob/v5.2.0/CHANGELOG.md#52) ## [2.11.1](https://github.com/k0kubun/hamlit/compare/v2.11.0...v2.11.1) - 2020-08-25 ### Fixed - Fix a line number on an error after filters like preserve, plain, and ruby. *Thanks to @rgisiger* ## [2.11.0](https://github.com/k0kubun/hamlit/compare/v2.10.1...v2.11.0) - 2019-12-12 ### Added - Support Haml's _revealed_ conditional comment feature on `/![if !IE]` [#153](https://github.com/k0kubun/hamlit/issues/153). *Thanks to @esb* ## [2.10.1](https://github.com/k0kubun/hamlit/compare/v2.10.0...v2.10.1) - 2019-11-28 ### Added - Register `Hamlit::Template` to Tilt as :hamlit as well, in addition to :haml ## [2.10.0](https://github.com/k0kubun/hamlit/compare/v2.9.5...v2.10.0) - 2019-09-15 ### Added - Optimize template rendering by string interpolation [#146](https://github.com/k0kubun/hamlit/issues/146) - Exploiting pre-allocation of string interpolation introduced in Ruby 2.5 [ruby/ruby#1626](https://github.com/ruby/ruby/pull/1626) ### Changed - Require temple.gem >= 0.8.2 ## [2.9.5](https://github.com/k0kubun/hamlit/compare/v2.9.4...v2.9.5) - 2019-09-08 ### Added - Supported `:plain` filter in truffleruby ## [2.9.4](https://github.com/k0kubun/hamlit/compare/v2.9.3...v2.9.4) - 2019-09-08 ### Added - Experimental support of truffleruby [#145](https://github.com/k0kubun/hamlit/issues/145). ## [2.9.3](https://github.com/k0kubun/hamlit/compare/v2.9.2...v2.9.3) - 2019-04-09 ### Fixed - Fix deprecation warning on Rails 6 [#138](https://github.com/k0kubun/hamlit/issues/138). *Thanks to @r7kamura* ## [2.9.2](https://github.com/k0kubun/hamlit/compare/v2.9.1...v2.9.2) - 2018-11-30 ### Fixed - Fix possible `autoload` failure of dependency [#131](https://github.com/k0kubun/hamlit/issues/131). *Thanks to @wimrijnders* ## [2.9.1](https://github.com/k0kubun/hamlit/compare/v2.9.0...v2.9.1) - 2018-11-01 ### Added - Start supporting JRuby [#100](https://github.com/k0kubun/hamlit/issues/100). ## [2.9.0](https://github.com/k0kubun/hamlit/compare/v2.8.10...v2.9.0) - 2018-10-16 ### Added - Consider aria attribute as another attribute that supports hyphenation and boolean like data attribute [#57](https://github.com/k0kubun/hamlit/pull/57). *Thanks to @francesco-loreti* ## [2.8.10](https://github.com/k0kubun/hamlit/compare/v2.8.9...v2.8.10) - 2018-09-05 ### Fixed - Fix uninitialized constant error introduced in v2.8.9 [#125](https://github.com/k0kubun/hamlit/pull/125). *Thanks to @vovchynniko* ## [2.8.9](https://github.com/k0kubun/hamlit/compare/v2.8.8...v2.8.9) - 2018-09-05 [YANKED] ### Fixed - Don't raise an error on UTF-8 BOM [#117](https://github.com/k0kubun/hamlit/pull/117) [#124](https://github.com/k0kubun/hamlit/pull/124). *Thanks to @southwolf* ## [2.8.8](https://github.com/k0kubun/hamlit/compare/v2.8.7...v2.8.8) - 2018-04-06 ### Fixed - Don't require Tilt dependencies if unregistered [#121](https://github.com/k0kubun/hamlit/pull/121). *Thanks to @michaelglass* ## [2.8.7](https://github.com/k0kubun/hamlit/compare/v2.8.6...v2.8.7) - 2018-02-17 ### Fixed - Fix parser error on string interpolation in attributes ## [2.8.6](https://github.com/k0kubun/hamlit/compare/v2.8.5...v2.8.6) - 2017-12-22 ### Fixed - Fix some unused-variable / method-redefinition warnings ## [2.8.5](https://github.com/k0kubun/hamlit/compare/v2.8.4...v2.8.5) - 2017-11-06 ### Fixed - Fix lexer to work with Ripper of Ruby 2.5 ## [2.8.4](https://github.com/k0kubun/hamlit/compare/v2.8.3...v2.8.4) - 2017-06-23 ### Added - Allow filename `-` to read input from STDIN for `hamlit [parse|temple|compile|render]` [#113](https://github.com/k0kubun/hamlit/issues/113). *Thanks to @gfx* ## [2.8.3](https://github.com/k0kubun/hamlit/compare/v2.8.2...v2.8.3) - 2017-06-19 ### Added - Add `--color` option to `hamlit parse` and `hamlit temple` commands too. ## [2.8.2](https://github.com/k0kubun/hamlit/compare/v2.8.1...v2.8.2) - 2017-06-19 ### Added - Add `--color` option to opt-in coloring in `hamlit compile` command [#111](https://github.com/k0kubun/hamlit/issues/111). ## [2.8.1](https://github.com/k0kubun/hamlit/compare/v2.8.0...v2.8.1) - 2017-04-03 ### Fixed - Fix SEGV caused by nil in old attributes [#101](https://github.com/k0kubun/hamlit/issues/101). *Thanks to @FND* ## [2.8.0](https://github.com/k0kubun/hamlit/compare/v2.7.5...v2.8.0) - 2017-02-12 ### Changed - Support Temple >= 0.8.0 and change to use StaticAnalyzer in Temple - Optimize attribute building code a little ## [2.7.5](https://github.com/k0kubun/hamlit/compare/v2.7.4...v2.7.5) - 2016-10-15 ### Fixed - Resurrect `Hamlit::RailsTemplate.set_options` dropped in v2.7.4 unexpectedly. ## [2.7.4](https://github.com/k0kubun/hamlit/compare/v2.7.3...v2.7.4) - 2016-10-15 [YANKED] ### Fixed - Compile template as xhtml when ActionView regards template as text/xml [#92](https://github.com/k0kubun/hamlit/issues/92). *Thank to @shmargum* ## [2.7.3](https://github.com/k0kubun/hamlit/compare/v2.7.2...v2.7.3) - 2016-10-12 ### Fixed - Regard download as an boolean attribute [#91](https://github.com/k0kubun/hamlit/pull/91). *Thank to @pushcx* ## [2.7.2](https://github.com/k0kubun/hamlit/compare/v2.7.1...v2.7.2) - 2016-09-19 ### Fixed - Fix engine option warning [#90](https://github.com/k0kubun/hamlit/issues/90). *Thank to @kikonen* ## [2.7.1](https://github.com/k0kubun/hamlit/compare/v2.7.0...v2.7.1) - 2016-09-19 ### Fixed - Fix Rails handler to use `ActionView::OutputBuffer` instead of `ActionView::SafeBuffer` to justify encoding [#89](https://github.com/k0kubun/hamlit/pull/89). *Thanks to @akelmanson* ## [2.7.0](https://github.com/k0kubun/hamlit/compare/v2.6.2...v2.7.0) - 2016-08-31 ### Changed - Don't escape interpolated content in plain filter [#87](https://github.com/k0kubun/hamlit/pull/87). *Thanks to @shmargum* ## [2.6.2](https://github.com/k0kubun/hamlit/compare/v2.6.1...v2.6.2) - 2016-08-27 ### Added - Add cdata filter [#84](https://github.com/k0kubun/hamlit/issues/84). *Thanks to @shmargum* - Minimize string allocation on template comipilation using `# frozen_string_literal: true` ## [2.6.1](https://github.com/k0kubun/hamlit/compare/v2.6.0...v2.6.1) - 2016-08-18 ### Fixed - For Rails, escape attributes even if it's html\_safe - This is the same fix as Rails for [CVE-2016-6316](https://groups.google.com/forum/#!topic/ruby-security-ann/8B2iV2tPRSE) ## [2.6.0](https://github.com/k0kubun/hamlit/compare/v2.5.0...v2.6.0) - 2016-08-14 ### Changed - Stop using [houdini](https://github.com/vmg/houdini) and rewrite HTML escape function to resolve building or packaging problems [#82](https://github.com/k0kubun/hamlit/pull/82). - No behavior is changed ## [2.5.0](https://github.com/k0kubun/hamlit/compare/v2.4.2...v2.5.0) - 2016-06-04 ### Changed - Don't escape the result of `preserve` helper in Rails ## [2.4.2](https://github.com/k0kubun/hamlit/compare/v2.4.1...v2.4.2) - 2016-06-04 ### Fixed - Regard cygwin and bccwin as Windows environment too ## [2.4.1](https://github.com/k0kubun/hamlit/compare/v2.4.0...v2.4.1) - 2016-06-03 ### Fixed - Fix C extension builder to work with Ruby 2.3 on Windows [#69](https://github.com/k0kubun/hamlit/issues/69). *Thanks to @francesco-loreti* ## [2.4.0](https://github.com/k0kubun/hamlit/compare/v2.3.1...v2.4.0) - 2016-05-13 ### Added - Add `Hamlit::Helpers.preserve` method for Tilt templates ## [2.3.1](https://github.com/k0kubun/hamlit/compare/v2.3.0...v2.3.1) - 2016-05-09 ### Fixed - Specify Ruby version dependency on gemspec [#67](https://github.com/k0kubun/hamlit/issues/67). *Thanks to @grosser* ## [2.3.0](https://github.com/k0kubun/hamlit/compare/v2.2.3...v2.3.0) - 2016-04-24 ### Added - Add `Hamlit::Filters.remove_filter` method [#66](https://github.com/k0kubun/hamlit/issues/66). *Thanks to @connorshea* ### Changed - `:coffeescript` filter's internal class name is changed from `Coffee` to `CoffeeScript` ## [2.2.4](https://github.com/k0kubun/hamlit/compare/v2.2.3...v2.2.4) - 2017-12-05 ### Fixed - Fix to work with Ruby 2.5. This version is usable with both 2.0 and 2.5. ## [2.2.3](https://github.com/k0kubun/hamlit/compare/v2.2.2...v2.2.3) - 2016-03-10 ### Added - Add `hamlit version` subcommand [#60](https://github.com/k0kubun/hamlit/pull/60). *Thanks to @timoschilling* ### Fixed - Fix load path for CLI [#61](https://github.com/k0kubun/hamlit/pull/61). *Thanks to @timoschilling* ## [2.2.2](https://github.com/k0kubun/hamlit/compare/v2.2.1...v2.2.2) - 2016-02-21 ### Added - Optimize performance of plain filter ### Fixed - Escape only interpolated text for plain filter [#58](https://github.com/k0kubun/hamlit/issues/58). *Thanks to @shaneog* ## [2.2.1](https://github.com/k0kubun/hamlit/compare/v2.2.0...v2.2.1) - 2016-02-06 ### Added - Support Windows [#54](https://github.com/k0kubun/hamlit/issues/54). *Thanks to @francesco-loreti* ## [2.2.0](https://github.com/k0kubun/hamlit/compare/v2.1.2...v2.2.0) - 2015-12-24 ### Added - Optimize inline script inside a tag - Optimize string interpolation recursively ## [2.1.2](https://github.com/k0kubun/hamlit/compare/v2.1.1...v2.1.2) - 2015-12-16 ### Fixed - Fix rendering failure for static integer [#50](https://github.com/k0kubun/hamlit/pull/50). *Thanks to @yatmsu* ## [2.1.1](https://github.com/k0kubun/hamlit/compare/v2.1.0...v2.1.1) - 2015-12-15 ### Fixed - Use faster HTML-escape method for compiling - Show proper line number for unbalanced brackets error ## [2.1.0](https://github.com/k0kubun/hamlit/compare/v2.0.2...v2.1.0) - 2015-12-14 ### Added - `-I` and `-r` options are added to `hamlit render` command [#37](https://github.com/k0kubun/hamlit/issues/37). *Thanks to @jhurliman* ### Changed - Dropped obsolete `escape_utils` gem dependency [#48](https://github.com/k0kubun/hamlit/pull/48). *Thanks to @eagletmt* ### Fixed - Accept NUL character in attribute keys [#49](https://github.com/k0kubun/hamlit/pull/49). *Thanks to @eagletmt* ## [2.0.2](https://github.com/k0kubun/hamlit/compare/v2.0.1...v2.0.2) - 2015-12-12 ### Fixed - Fix a crash in compiling with CLI [#46](https://github.com/k0kubun/hamlit/pull/46). *Thanks to @walf443* - Use default engine options properly in CLI commands ## [2.0.1](https://github.com/k0kubun/hamlit/compare/v2.0.0...v2.0.1) - 2015-11-30 ### Fixed - Fix build failure of native extension ## [2.0.0](https://github.com/k0kubun/hamlit/compare/v1.7.2...v2.0.0) - 2015-11-30 [YANKED] ### Added - Support object reference ### Changed - Full scratch of internal implementation - Rendering is strongly optimized - Static analyzer is introduced - Built with C extension for runtime rendering - Optimized compilation for 5 types of attributes - Compilation became faster too - Many rendering incompatibilities are resolved - [**breaking**] Replaced parser with original Haml's one - Incompatible parsing error will never happen, but we can no longer parse attributes with Ripper - [**breaking**] Unified behavior for both static and dynamic attributes, see [5 types of attributes](REFERENCE.md#5-types-of-attributes) - Though inconsistent behavior is removed, we can no longer rely on completely-Haml-compatible behavior of static attributes and pass haml-spec - [**breaking**] Added :escape\_attrs option - You should specify HTML-escaping availability for script and attrs separately. ## [1.7.2](https://github.com/k0kubun/hamlit/compare/v1.7.1...v1.7.2) - 2015-07-22 ### Fixed - Bugfix about parsing a content of tag - This was introduced in v1.6.6. ## [1.7.1](https://github.com/k0kubun/hamlit/compare/v1.7.0...v1.7.1) - 2015-07-21 ### Fixed - Don't escape a block content of some helpers [#35](https://github.com/k0kubun/hamlit/issues/35). *Thanks to @felixbuenemann* ## [1.7.0](https://github.com/k0kubun/hamlit/compare/v1.6.7...v1.7.0) - 2015-07-09 ### Added - Support Ruby 2.2.0 hash syntax - like `{ "hyphened-key": "value" }` ## [1.6.7](https://github.com/k0kubun/hamlit/compare/v1.6.6...v1.6.7) - 2015-06-27 ### Fixed - Remove unused variables and avoid shadowing - To suppress warnings in application using `rspec --warnings` ## [1.6.6](https://github.com/k0kubun/hamlit/compare/v1.6.5...v1.6.6) - 2015-06-24 ### Added - Allow hyphenated HTML-style attributes [pull #29](https://github.com/k0kubun/hamlit/pull/29). *thanks to @babelfish* ## [1.6.5](https://github.com/k0kubun/hamlit/compare/v1.6.4...v1.6.5) - 2015-06-13 ### Fixed - Don't duplicate element class and attribute class - Raise an error for an empty tag name ## [1.6.4](https://github.com/k0kubun/hamlit/compare/v1.6.3...v1.6.4) - 2015-06-13 ### Changed - Show human-friendly error messages ### Fixed - Fix line number of runtime syntax error - Increase the number of checked cases for illegal nesting. *Thanks to @eagletmt* ## [1.6.3](https://github.com/k0kubun/hamlit/compare/v1.6.2...v1.6.3) - 2015-06-13 ### Fixed - Fix ! and & parsing inside a tag [#27](https://github.com/k0kubun/hamlit/issues/27#issuecomment-111593458). *Thanks to @leesmith* ## [1.6.2](https://github.com/k0kubun/hamlit/compare/v1.6.1...v1.6.2) - 2015-06-11 ### Fixed - Reject a content for self-closing tags - Reject nesing within self-closing tags ## [1.6.1](https://github.com/k0kubun/hamlit/compare/v1.6.0...v1.6.1) - 2015-06-11 ### Fixed - Parse N-space indentation [#26](https://github.com/k0kubun/hamlit/issues/26). *Thanks to @eagletmt* ## [1.6.0](https://github.com/k0kubun/hamlit/compare/v1.5.9...v1.6.0) - 2015-06-11 ### Fixed - Fix line number of compiled code for new attributes - Render HTML entities normally for plain text [#27](https://github.com/k0kubun/hamlit/issues/27). *Thanks to @jeffblake* ## [1.5.9](https://github.com/k0kubun/hamlit/compare/v1.5.8...v1.5.9) - 2015-06-08 ### Fixed - Reject silent script after a tag ## [1.5.8](https://github.com/k0kubun/hamlit/compare/v1.5.7...v1.5.8) - 2015-06-08 ### Fixed - Fix parsing inline script for != and &= ## [1.5.7](https://github.com/k0kubun/hamlit/compare/v1.5.6...v1.5.7) - 2015-06-08 ### Fixed - Fix the behavior for multi-line script ## [1.5.6](https://github.com/k0kubun/hamlit/compare/v1.5.5...v1.5.6) - 2015-06-07 ### Added - Raise error for unbalanced brackets ### Changed - Don't render newline after block script ## [1.5.5](https://github.com/k0kubun/hamlit/compare/v1.5.4...v1.5.5) - 2015-06-07 ### Added - Support &, &== operator ### Changed - Depend on v0.7.6 of temple for refactoring ### Fixed - Fix a trivial diff of rendering multiline operator ## [1.5.4](https://github.com/k0kubun/hamlit/compare/v1.5.3...v1.5.4) - 2015-06-07 ### Changed - Recursively remove whitespace inside a tag ### Fixed - Fix ! operator immediately before whitespace ## [1.5.3](https://github.com/k0kubun/hamlit/compare/v1.5.2...v1.5.3) - 2015-06-06 ### Added - Support !, !=, !==, &= and ~ as inline operators ## [1.5.2](https://github.com/k0kubun/hamlit/compare/v1.5.1...v1.5.2) - 2015-06-06 ### Changed - Disable html escaping in CSS and JavaScript filter ## [1.5.1](https://github.com/k0kubun/hamlit/compare/v1.5.0...v1.5.1) - 2015-06-05 ### Changed - Remove outer whitespace in the block ## [1.5.0](https://github.com/k0kubun/hamlit/compare/v1.4.7...v1.5.0) - 2015-06-03 ### Changed - Remake implementation of outer whitespace removal ## [1.4.7](https://github.com/k0kubun/hamlit/compare/v1.4.6...v1.4.7) - 2015-06-03 ### Changed - Sort static old attributes by name ### Fixed - Bugfix for old array attributes with class element ## [1.4.6](https://github.com/k0kubun/hamlit/compare/v1.4.5...v1.4.6) - 2015-06-03 ### Added - Support `!==`, `==` operator ### Fixed - Avoid regarding spaced block as multiline ## [1.4.5](https://github.com/k0kubun/hamlit/compare/v1.4.4...v1.4.5) - 2015-06-02 ### Fixed - Support Ruby 2.0 and 2.1 for v1.4.4 ## [1.4.4](https://github.com/k0kubun/hamlit/compare/v1.4.3...v1.4.4) - 2015-06-02 [YANKED] ### Fixed - Fix old attribute parser to be more flexible - Accept multiple hashes as old attributes - Accept old attributes with hash and literal ## [1.4.3](https://github.com/k0kubun/hamlit/compare/v1.4.2...v1.4.3) - 2015-06-02 ### Changed - Allow `when` to have multiple candidates - Allow `rescue` to specify an error variable ## [1.4.2](https://github.com/k0kubun/hamlit/compare/v1.4.1...v1.4.2) - 2015-05-31 ### Added - Support `!` operator - It disables html escaping for interpolated text ## [1.4.1](https://github.com/k0kubun/hamlit/compare/v1.4.0...v1.4.1) - 2015-05-31 ### Fixed - Fix code mistake in 1.4.0 ## [1.4.0](https://github.com/k0kubun/hamlit/compare/v1.3.2...v1.4.0) - 2015-05-31 [YANKED] ### Added - Escape interpolated string in plain text ## [1.3.2](https://github.com/k0kubun/hamlit/compare/v1.3.1...v1.3.2) - 2015-05-30 - Render `begin`, `rescue` and `ensure` ## [1.3.1](https://github.com/k0kubun/hamlit/compare/v1.3.0...v1.3.1) - 2015-05-30 ### Fixed - Bugfix about a backslash-only comment - Don't strip a plain text ## [1.3.0](https://github.com/k0kubun/hamlit/compare/v1.2.1...v1.3.0) - 2015-05-16 ### Added - Resurrect escape\_html option [#25](https://github.com/k0kubun/hamlit/issues/25). *Thanks to @resistorsoftware* - Still enabled by default - This has been dropped since v0.6.0 ## [1.2.1](https://github.com/k0kubun/hamlit/compare/v1.2.0...v1.2.1) - 2015-05-15 ### Fixed - Fix the list of boolean attributes [#24](https://github.com/k0kubun/hamlit/issues/24). *Thanks to @jeffblake* ## [1.2.0](https://github.com/k0kubun/hamlit/compare/v1.1.1...v1.2.0) - 2015-05-06 Added - Support `succeed`, `precede` and `surround` [#22](https://github.com/k0kubun/hamlit/issues/22). *Thanks to @sneakernets* ## [1.1.1](https://github.com/k0kubun/hamlit/compare/v1.1.0...v1.1.1) - 2015-05-06 ### Fixed - Bugfix of rendering array attributes ## [1.1.0](https://github.com/k0kubun/hamlit/compare/v1.0.0...v1.1.0) - 2015-05-06 ### Fixed - Join id and class attributes [#23](https://github.com/k0kubun/hamlit/issues/23). *Thanks to @felixbuenemann* ## [1.0.0](https://github.com/k0kubun/hamlit/compare/v0.6.2...v1.0.0) - 2015-04-12 ### Added - Use escape\_utils gem for faster escape\_html ## [0.6.2](https://github.com/k0kubun/hamlit/compare/v0.6.1...v0.6.2) - 2015-04-12 ### Fixed - Don't render falsy attributes [#2](https://github.com/k0kubun/hamlit/issues/2). *Thanks to @eagletmt* ## [0.6.1](https://github.com/k0kubun/hamlit/compare/v0.6.0...v0.6.1) - 2015-04-12 ### Fixed - Bugfix of line numbers for better error backtrace [pull #19](https://github.com/k0kubun/hamlit/pull/19) ## [0.6.0](https://github.com/k0kubun/hamlit/compare/v0.5.3...v0.6.0) - 2015-04-12 ### Added - Automatically escape html in all situations [pull #18](https://github.com/k0kubun/hamlit/pull/18) ## [0.5.3](https://github.com/k0kubun/hamlit/compare/v0.5.2...v0.5.3) - 2015-04-12 ### Fixed - Bugfix for syntax error in data attribute hash [#17](https://github.com/k0kubun/hamlit/issues/17). *Thanks to @eagletmt* ## [0.5.2](https://github.com/k0kubun/hamlit/compare/v0.5.1...v0.5.2) - 2015-04-12 ### Fixed - Bugfix for silent script without block [#16](https://github.com/k0kubun/hamlit/issues/16). *Thanks to @eagletmt* ## [0.5.1](https://github.com/k0kubun/hamlit/compare/v0.5.0...v0.5.1) - 2015-04-12 ### Fixed - Bugfix about duplicated id and class [#4](https://github.com/k0kubun/hamlit/issues/4). *Thanks to @os0x* ## [0.5.0](https://github.com/k0kubun/hamlit/compare/v0.4.3...v0.5.0) - 2015-04-12 ### Fixed - Escape special characters in attribute values [#10](https://github.com/k0kubun/hamlit/issues/10). *Thanks to @mono0x, @eagletmt* ## [0.4.3](https://github.com/k0kubun/hamlit/compare/v0.4.2...v0.4.3) - 2015-04-12 ### Fixed - Allow empty else statement [#14](https://github.com/k0kubun/hamlit/issues/14). *Thanks to @jeffblake* - Accept comment-only script [#13](https://github.com/k0kubun/hamlit/issues/13). *Thanks to @jeffblake* ## [0.4.2](https://github.com/k0kubun/hamlit/compare/v0.4.1...v0.4.2) - 2015-04-05 ### Fixed - Bugfix about parsing nested attributes [#12](https://github.com/k0kubun/hamlit/issues/12). *Thanks to @creasty* ## [0.4.1](https://github.com/k0kubun/hamlit/compare/v0.4.0...v0.4.1) - 2015-04-05 ### Removed - Automatic escape html is sintara, consult `README.md`. ### Fixed - Escape haml operators by backslash [#11](https://github.com/k0kubun/hamlit/issues/11). *Thanks to @mono0x* ## [0.4.0](https://github.com/k0kubun/hamlit/compare/v0.3.4...v0.4.0) - 2015-04-05 [YANKED] ### Added - Automatically escape html in sinatra ## [0.3.4](https://github.com/k0kubun/hamlit/compare/v0.3.3...v0.3.4) - 2015-04-02 ### Fixed - Allow tab indentation [#9](https://github.com/k0kubun/hamlit/issues/9). *Thanks to @tdtds* ## [0.3.3](https://github.com/k0kubun/hamlit/compare/v0.3.2...v0.3.3) - 2015-04-01 ### Fixed - Accept multi byte parsing [#8](https://github.com/k0kubun/hamlit/issues/8). *Thanks to @machu* ## [0.3.2](https://github.com/k0kubun/hamlit/compare/v0.3.1...v0.3.2) - 2015-03-31 ### Fixed - Bugfix for compiling old attributes [#7](https://github.com/k0kubun/hamlit/issues/7). *Thanks to @creasty* ## [0.3.1](https://github.com/k0kubun/hamlit/compare/v0.3.0...v0.3.1) - 2015-03-31 ### Fixed - Hyphenate data attributes [#5](https://github.com/k0kubun/hamlit/issues/5). *Thanks to @os0x* ## [0.3.0](https://github.com/k0kubun/hamlit/compare/v0.2.0...v0.3.0) - 2015-03-31 ### Added - Specify a version in dependency of temple ## [0.2.0](https://github.com/k0kubun/hamlit/compare/v0.1.3...v0.2.0) - 2015-03-30 ### Added - Allow comments in script [#3](https://github.com/k0kubun/hamlit/issues/3). *Thanks to @eagletmt* ## [0.1.3](https://github.com/k0kubun/hamlit/compare/v0.1.2...v0.1.3) - 2015-03-30 ### Fixed - Bugfix for [#1](https://github.com/k0kubun/hamlit/issues/1) attribute nesting on runtime. *Thanks to @eagletmt* ## [0.1.2](https://github.com/k0kubun/hamlit/compare/v0.1.1...v0.1.2) - 2015-03-30 ### Fixed - Ignore false or nil values in attributes - Partial fix for [#2](https://github.com/k0kubun/hamlit/issues/2). *Thanks to @eagletmt* ## [0.1.1](https://github.com/k0kubun/hamlit/compare/v0.1.0...v0.1.1) - 2015-03-30 ### Removed - Drop obsolete `--ugly` option for CLI - Currently pretty mode is not implemented #2 ## [0.1.0](https://github.com/k0kubun/hamlit/compare/9cf8216...v0.1.0) - 2015-03-30 - Initial release - Passing haml-spec with ugly mode hamlit-2.15.1/Gemfile000066400000000000000000000007551407657076200143760ustar00rootroot00000000000000source 'https://rubygems.org' git_source(:github) do |repo_name| repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") "https://github.com/#{repo_name}.git" end # Specify your gem's dependencies in hamlit.gemspec gemspec gem 'benchmark-ips', '2.3.0' gem 'maxitest' gem 'pry' if /java/ === RUBY_PLATFORM # JRuby gem 'pandoc-ruby' else gem 'redcarpet' if RUBY_PLATFORM !~ /mswin|mingw/ && RUBY_ENGINE != 'truffleruby' gem 'faml' gem 'stackprof' end end hamlit-2.15.1/LICENSE.txt000066400000000000000000000043521407657076200147230ustar00rootroot00000000000000Copyright (c) 2006-2019 Hampton Catlin and Natalie Weizenbaum 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. === The above license is applied to lib/hamlit/parser/*.rb and test/haml/*. Everything else is licensed under: The MIT License (MIT) Copyright (c) 2015 Takashi Kokubun 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. hamlit-2.15.1/README.md000066400000000000000000000110411407657076200143500ustar00rootroot00000000000000# Hamlit [![Gem Version](https://badge.fury.io/rb/hamlit.svg)](http://badge.fury.io/rb/hamlit) [![test](https://github.com/k0kubun/hamlit/workflows/test/badge.svg)](https://github.com/k0kubun/hamlit/actions?query=workflow%3Atest) Hamlit is a high performance [Haml](https://github.com/haml/haml) implementation. ## Introduction ### What is Hamlit? Hamlit is another implementation of [Haml](https://github.com/haml/haml). With some [limitations](REFERENCE.md#limitations) by design for performance, Hamlit is **1.94x times faster** than original haml gem in [this benchmark](benchmark/slim/run-benchmarks.rb), which is an HTML-escaped version of [slim-template/slim's one](https://github.com/slim-template/slim/blob/4.1.0/benchmarks/run-benchmarks.rb) for fairness. ([Result on Travis](https://travis-ci.org/github/k0kubun/hamlit/jobs/732178446)) Hamlit Benchmark ``` hamlit v2.13.0: 247404.4 i/s erubi v1.9.0: 244356.4 i/s - 1.01x slower slim v4.1.0: 238254.3 i/s - 1.04x slower faml v0.8.1: 197293.2 i/s - 1.25x slower haml v5.2.0: 127834.4 i/s - 1.94x slower ``` ### Why is Hamlit faster? #### Less string concatenation by design As written in [limitations](REFERENCE.md#limitations), Hamlit drops some not-so-important features which require works on runtime. With the optimized language design, we can reduce the string concatenation to build attributes. #### Static analyzer Hamlit analyzes Ruby expressions with Ripper and render it on compilation if the expression is static. And Hamlit can also compile string literal with string interpolation to reduce string allocation and concatenation on runtime. #### C extension to build attributes While Hamlit has static analyzer and static attributes are rendered on compilation, dynamic attributes must be rendered on runtime. So Hamlit optimizes rendering on runtime with C extension. ## Usage Hamlit currently supports Ruby 2.1 and higher. See [REFERENCE.md](REFERENCE.md) for detail features of Hamlit. ### Rails Add this line to your application's Gemfile or just replace `gem "haml"` with `gem "hamlit"`. It enables rendering by Hamlit for \*.haml automatically. ```rb gem 'hamlit' ``` If you want to use view generator, consider using [hamlit-rails](https://github.com/mfung/hamlit-rails). ### Sinatra Replace `gem "haml"` with `gem "hamlit"` in Gemfile, and require "hamlit". While Haml disables `escape_html` option by default, Hamlit enables it for security. If you want to disable it, please write: ```rb set :haml, { escape_html: false } ``` ## Command line interface You can see compiled code or rendering result with "hamlit" command. ```bash $ gem install hamlit $ hamlit --help Commands: hamlit compile HAML # Show compile result hamlit help [COMMAND] # Describe available commands or one specific command hamlit parse HAML # Show parse result hamlit render HAML # Render haml template hamlit temple HAML # Show temple intermediate expression $ cat in.haml - user_id = 123 %a{ href: "/users/#{user_id}" } # Show compiled code $ hamlit compile in.haml _buf = []; user_id = 123; ; _buf << ("\n".freeze); _buf = _buf.join # Render html $ hamlit render in.haml ``` ## Contributing ### Test latest version ```rb # Gemfile gem 'hamlit', github: 'k0kubun/hamlit', submodules: true ``` ### Development Contributions are welcomed. It'd be good to see [Temple's EXPRESSIONS.md](https://github.com/judofyr/temple/blob/v0.7.6/EXPRESSIONS.md) to learn Temple which is a template engine framework used in Hamlit. ```bash $ git clone --recursive https://github.com/k0kubun/hamlit $ cd hamlit $ bundle install # Run all tests $ bundle exec rake test # Run one test $ bundle exec ruby -Ilib:test -rtest_helper test/hamlit/line_number_test.rb -l 12 # Show compiling/rendering result of some template $ bundle exec exe/hamlit compile in.haml $ bundle exec exe/hamlit render in.haml # Use rails app to debug Hamlit $ cd sample/rails $ bundle install $ bundle exec rails s ``` ### Reporting an issue Please report an issue with following information: - Full error backtrace - Haml template - Ruby version - Hamlit version - Rails/Sinatra version ### Coding styles Please follow the existing coding styles and do not send patches including cosmetic changes. ## License Copyright (c) 2015 Takashi Kokubun hamlit-2.15.1/REFERENCE.md000066400000000000000000000166011407657076200147200ustar00rootroot00000000000000# Hamlit Basically Hamlit is the same as Haml. See [Haml's tutorial](http://haml.info/tutorial.html) if you are not familiar with Haml's syntax. [REFERENCE - Haml Documentation](http://haml.info/docs/yardoc/file.REFERENCE.html) ## Supported features See [Haml's reference](http://haml.info/docs/yardoc/file.REFERENCE.html) for full features in original implementation. - [ ] Using Haml - [x] Rails XSS Protection - [x] Ruby Module - [x] Options - [ ] Encodings - [x] Plain Text - [x] Escaping: \ - [ ] HTML Elements - [x] Element Name: % - [ ] Attributes: ` - [x] :class and :id Attributes - [x] HTML-style Attributes: () - [x] Ruby 1.9-style Hashes - [ ] Attribute Methods - [x] Boolean Attributes - [x] HTML5 Custom Data Attributes - [x] Class and ID: . and # - Implicit Div Elements - [x] Empty (void) Tags: / - [x] Whitespace Removal: > and < - [x] Object Reference: [] - [x] Doctype: !!! - [x] Comments - [x] HTML Comments: / - [x] Conditional Comments: /[] - [x] Haml Comments: -# - [x] Ruby Evaluation - [x] Inserting Ruby: = - [x] Running Ruby: - - [x] Ruby Blocks - [x] Whitespace Preservation: ~ - [x] Ruby Interpolation: #{} - [x] Escaping HTML: &= - [x] Unescaping HTML: != - [ ] Filters - [x] :cdata - [x] :coffee - [x] :css - [x] :erb - [x] :escaped - [x] :javascript - [x] :less - [x] :markdown - [ ] :maruku - [x] :plain - [x] :preserve - [x] :ruby - `haml_io` API is not supported. Use [hamlit-haml\_io.gem](https://github.com/hamlit/hamlit-haml_io) if you need. - [x] :sass - [x] :scss - [ ] :textile - [ ] Custom Filters - [x] Helper Methods - [x] preserve - [x] surround - [x] precede - [x] succeed - [x] Multiline: | - [x] Whitespace Preservation - [ ] Helpers ## Limitations ### No Haml buffer Hamlit uses `Array` as buffer for performance. So you can't touch Haml::Buffer from template when using Hamlit. ### Haml helpers are still in development At the same time, because some methods in `Haml::Helpers` require `Haml::Buffer`, they are not supported now. But some helpers are supported on Rails. Some of not-implemented methods are planned to be supported. ### Limited attributes hyphenation In Haml, `%a{ foo: { bar: 'baz' } }` is rendered as ``, whatever foo is. In Hamlit, this feature is supported only for aria and data attribute. Hamlit renders `%a{ data: { foo: 'bar' } }` as `` because it's data attribute. This design allows us to reduce work on runtime and the idea is originally in [Faml](https://github.com/eagletmt/faml). ### Limited boolean attributes In Haml, `%a{ foo: false }` is rendered as ``, whatever `foo` is. In Hamlit, this feature is supported for only boolean attributes, which are defined by http://www.w3.org/TR/xhtml1/guidelines.html or https://html.spec.whatwg.org/. The list is the same as `ActionView::Helpers::TagHelper::BOOLEAN_ATTRIBUTES`. In addition, aria-\* and data-\* is also regarded as boolean. Since `foo` is not boolean attribute, `%a{ foo: false }` is rendered as `` This is the same behavior as Rails helpers. Also for `%a{ foo: nil }`, Hamlit does not remove non-boolean attributes and render `` (`foo` is not removed). This design allows us to reduce string concatenation and is the only difference between Faml and Hamlit. You may be also interested in [hamlit/hamlit-boolean\_attributes](https://github.com/hamlit/hamlit-boolean_attributes). ## 5 Types of Attributes Haml has 3 types of attributes: id, class and others. In addition, Hamlit treats aria/data and boolean attributes specially. So there are 5 types of attributes in Hamlit. ### id attribute Almost the same behavior as Haml, except no hyphenation and boolean support. Arrays are flattened, falsey values are removed (but attribute itself is not removed) and merging multiple ids results in concatenation by "\_". ```rb # Input #foo{ id: 'bar' } %div{ id: %w[foo bar] } %div{ id: ['foo', false, ['bar', nil]] } %div{ id: false } # Output
``` ### class attribute Almost the same behavior as Haml, except no hyphenation and boolean support. Arrays are flattened, falsey values are removed (but attribute itself is not removed) and merging multiple classes results in unique alphabetical sort. ```rb # Input .d.a(class='b c'){ class: 'c a' } %div{ class: 'd c b a' } %div{ class: ['d', nil, 'c', [false, 'b', 'a']] } %div{ class: false } # Output
``` ### aria / data attribute Completely compatible with Haml, hyphenation and boolean are supported. ```rb # Input %div{ data: { disabled: true } } %div{ data: { foo: 'bar' } } # Output
``` aria attribute works in the same way as data attribute. ### boolean attributes No hyphenation but complete boolean support. ```rb # Input %div{ disabled: 'foo' } %div{ disabled: true } %div{ disabled: false } # Output
``` List of boolean attributes is: ``` disabled readonly multiple checked autobuffer autoplay controls loop selected hidden scoped async defer reversed ismap seamless muted required autofocus novalidate formnovalidate open pubdate itemscope allowfullscreen default inert sortable truespeed typemustmatch ``` If you want to customize the list of boolean attributes, you can use [hamlit/hamlit-boolean\_attributes](https://github.com/hamlit/hamlit-boolean_attributes). "aria-\*" and "data-\*" are also regarded as boolean. ### other attributes No hyphenation and boolean support. `false` is rendered as "false" (like Rails helpers). ```rb # Input %input{ value: true } %input{ value: false } # Output ``` ## Engine options | Option | Default | Feature | |:-------|:--------|:--------| | escape\_html | true | HTML-escape for Ruby script and interpolation. This is false in Haml. | | escape\_attrs | true | HTML-escape for Html attributes. | | format | :html | You can set :xhtml to change boolean attribute's format. | | attr\_quote | `'` | You can change attribute's wrapper to `"` or something. | ### Set options for Rails ```rb # config/initializers/hamlit.rb or somewhere Hamlit::RailsTemplate.set_options attr_quote: '"' ``` ### Set options for Sinatra ```rb set :haml, { attr_quote: '"' } ``` ## Ruby module `Hamlit::Template` is a module registered to `Tilt`. You can use it like: ```rb Hamlit::Template.new { "%strong Yay for HAML!" }.render ``` ## Creating a custom filter Currently it doesn't have filter registering interface compatible with Haml. But you can easily define and register a filter using Tilt like this. ```rb module Hamlit class Filters class Es6 < TiltBase def compile(node) # branch with `@format` here if you want compile_html(node) end private def compile_html(node) temple = [:multi] temple << [:static, ""] temple end end register :es6, Es6 end end ``` After requiring the script, you can do: ```haml :es6 const a = 1; ``` and it's rendered as: ```html ``` hamlit-2.15.1/Rakefile000066400000000000000000000053601407657076200145450ustar00rootroot00000000000000require 'bundler/setup' require 'bundler/gem_tasks' # # Prepend DevKit into compilation phase # if Gem.win_platform? desc 'Activates DevKit' task :devkit do begin require 'devkit' rescue LoadError abort 'Failed to load DevKit required for compilation' end end task compile: :devkit end require 'rake/testtask' if /java/ === RUBY_PLATFORM # require 'rake/javaextensiontask' # Rake::JavaExtensionTask.new(:hamlit) do |ext| # ext.ext_dir = 'ext/java' # ext.lib_dir = 'lib/hamlit' # end task :compile do # dummy for now end else require 'rake/extensiontask' Rake::ExtensionTask.new(:hamlit) do |ext| ext.lib_dir = 'lib/hamlit' end end Dir['benchmark/*.rake'].each { |b| import(b) } namespace :haml do Rake::TestTask.new do |t| t.libs << 'lib' << 'test' files = Dir['test/haml/*_test.rb'] files << 'test/haml/haml-spec/*_test.rb' t.ruby_opts = %w[-rtest_helper] t.test_files = files t.verbose = true end end namespace :hamlit do Rake::TestTask.new do |t| t.libs << 'lib' << 'test' t.ruby_opts = %w[-rtest_helper] t.test_files = Dir['test/hamlit/**/*_test.rb'] t.verbose = true end end namespace :test do Rake::TestTask.new(:all) do |t| t.libs << 'lib' << 'test' files = Dir['test/hamlit/**/*_test.rb'] files += Dir['test/haml/*_test.rb'] files << 'test/haml/haml-spec/*_test.rb' t.ruby_opts = %w[-rtest_helper] t.test_files = files t.verbose = true end Rake::TestTask.new(:spec) do |t| t.libs << 'lib' << 'test' t.ruby_opts = %w[-rtest_helper] t.test_files = %w[test/haml/haml-spec/ugly_test.rb test/haml/haml-spec/pretty_test.rb] t.verbose = true end Rake::TestTask.new(:engine) do |t| t.libs << 'lib' << 'test' t.ruby_opts = %w[-rtest_helper] t.test_files = %w[test/haml/engine_test.rb] t.verbose = true end Rake::TestTask.new(:filters) do |t| t.libs << 'lib' << 'test' t.ruby_opts = %w[-rtest_helper] t.test_files = %w[test/haml/filters_test.rb] t.verbose = true end Rake::TestTask.new(:helper) do |t| t.libs << 'lib' << 'test' t.ruby_opts = %w[-rtest_helper] t.test_files = %w[test/haml/helper_test.rb] t.verbose = true end Rake::TestTask.new(:template) do |t| t.libs << 'lib' << 'test' t.ruby_opts = %w[-rtest_helper] t.test_files = %w[test/haml/template_test.rb] t.verbose = true end end desc 'bench task for CI' task bench: :compile do if ENV['SLIM_BENCH'] == '1' cmd = %w[bundle exec ruby benchmark/slim/run-benchmarks.rb] else cmd = ['bin/bench', 'bench', ('-c' if ENV['COMPILE'] == '1'), *ENV['TEMPLATE'].split(',')].compact end exit system(*cmd) end task default: %w[compile hamlit:test] task test: %w[compile test:all] hamlit-2.15.1/benchmark/000077500000000000000000000000001407657076200150265ustar00rootroot00000000000000hamlit-2.15.1/benchmark/boolean_attribute.haml000066400000000000000000000002221407657076200213670ustar00rootroot00000000000000%input{ disabled: false } %input{ disabled: true } - disabled = false %input{ disabled: disabled } - disabled = true %input{ disabled: disabled } hamlit-2.15.1/benchmark/class_attribute.haml000066400000000000000000000001631407657076200210610ustar00rootroot00000000000000.book{ class: 'content active' } .book(class='content active') - klass = %w[content active] .book{ class: klass } hamlit-2.15.1/benchmark/common_attribute.haml000066400000000000000000000000701407657076200212410ustar00rootroot00000000000000%a{ href: '&"\'<>' } - href = '&"\'<>' %a{ href: href } hamlit-2.15.1/benchmark/data_attribute.haml000066400000000000000000000002371407657076200206670ustar00rootroot00000000000000%div{ data: { disabled: false } } %div{ data: { disabled: true } } - hash = { 'user' => { id: 1234, name: 'k0kubun' }, book_id: 5432 } %div{ data: hash } data hamlit-2.15.1/benchmark/dynamic_attributes/000077500000000000000000000000001407657076200207205ustar00rootroot00000000000000hamlit-2.15.1/benchmark/dynamic_attributes/boolean_attribute.haml000066400000000000000000000001271407657076200252650ustar00rootroot00000000000000- hash = { disabled: false } %input{ hash } - hash = { disabled: true } %input{ hash } hamlit-2.15.1/benchmark/dynamic_attributes/class_attribute.haml000066400000000000000000000001421407657076200247500ustar00rootroot00000000000000- hash = { class: %w[content active] } .book{ hash } - arr = %w[foo bar] .book(class=arr){ hash } hamlit-2.15.1/benchmark/dynamic_attributes/common_attribute.haml000066400000000000000000000000471407657076200251370ustar00rootroot00000000000000- hash = { href: '&"\'<>' } %a{ hash } hamlit-2.15.1/benchmark/dynamic_attributes/data_attribute.haml000066400000000000000000000001401407657076200245520ustar00rootroot00000000000000- hash = { data: { 'user' => { id: 1234, name: 'k0kubun' }, book_id: 5432 } } %div{ hash } data hamlit-2.15.1/benchmark/dynamic_attributes/id_attribute.haml000066400000000000000000000000621407657076200242400ustar00rootroot00000000000000- hash = { id: %w[content active] } #book{ hash } hamlit-2.15.1/benchmark/dynamic_boolean_attribute.haml000066400000000000000000000001371407657076200231000ustar00rootroot00000000000000- disabled = false %input{ disabled: disabled } - disabled = true %input{ disabled: disabled } hamlit-2.15.1/benchmark/dynamic_merger/000077500000000000000000000000001407657076200200135ustar00rootroot00000000000000hamlit-2.15.1/benchmark/dynamic_merger/benchmark.rb000066400000000000000000000016671407657076200223040ustar00rootroot00000000000000# Original: https://github.com/amatsuda/string_template/blob/master/benchmark.rb require 'benchmark_driver' Benchmark.driver(repeat_count: 8) do |x| x.prelude %{ require 'rails' require 'action_view' require 'string_template' StringTemplate::Railtie.run_initializers require 'hamlit' Hamlit::Railtie.run_initializers Hamlit::RailsTemplate.set_options(escape_html: false, generator: Temple::Generators::ArrayBuffer) require 'action_view/base' (view = Class.new(ActionView::Base).new(ActionView::LookupContext.new(''))).instance_variable_set(:@world, 'world!') # compile template hello = 'benchmark/dynamic_merger/hello' view.render(template: hello, handlers: 'string') view.render(template: hello, handlers: 'haml') } x.report 'string', %{ view.render(template: hello, handlers: 'string') } x.report 'hamlit', %{ view.render(template: hello, handlers: 'haml') } x.loop_count 100_000 end hamlit-2.15.1/benchmark/dynamic_merger/hello.haml000066400000000000000000000016661407657076200217720ustar00rootroot00000000000000hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hamlit-2.15.1/benchmark/dynamic_merger/hello.string000066400000000000000000000016661407657076200223570ustar00rootroot00000000000000hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hello, #{ @world } hamlit-2.15.1/benchmark/etc/000077500000000000000000000000001407657076200156015ustar00rootroot00000000000000hamlit-2.15.1/benchmark/etc/attribute_builder.haml000066400000000000000000000002011407657076200221460ustar00rootroot00000000000000- h = { 'user' => { id: 1234, name: 'eagletmt' }, book_id: 5432 } - c = %w[content active] %span.book{data: h, class: c} Book hamlit-2.15.1/benchmark/etc/real_sample.haml000066400000000000000000000557221407657076200207430ustar00rootroot00000000000000#id-1 = render partial: 'test' %ul#id-2.class-1.class-2 %section#id-3 .class-3 string-1 .class-4 .class-5 string-2 %pre.class-6(readonly="readonly" style='width:1px') :preserve .class-7 string-3 .class-8 string-4 %pre.class-9(readonly="readonly" style='width:2px') :preserve .class-10 string-5 %p Hello world .class-12 string-6 %pre.class-13(readonly="readonly" style='width:3px') :preserve .class-14 string-7 %p Hello world %section#id-4 .class-17 string-8 .class-18 .class-19 string-9 %pre.class-20(readonly="readonly" style='width:4px') :preserve .class-21 string-10 .class-22 string-11 %pre.class-23(readonly="readonly" style='width:5px') :preserve .class-24 string-12 .class-25.class-26 Hello world %pre.class-27(readonly="readonly" style='width:6px') :preserve .class-28.class-29 Hello world %section#id-5 .class-30 string-13 .class-31 string-14 .class-32 %pre.class-33(readonly="readonly" style='width:7px') :preserve .class-34 string-15 %section#id-6 .class-35 string-16 %ul.class-36.class-37 %li = link_to 'link', '#' %li = link_to 'link', '#', class: 'klass' %li = link_to 'link', '#', class: 'klass' %li = link_to 'link', '#', class: 'klass' %li = link_to 'link', '#', class: 'klass' .class-38 %p text-17 %p text-18 %pre.class-41(readonly="readonly" style='width:8px') :preserve %ul.class-42.class-43 %li = link_to 'link', '#' %li = link_to 'link', '#', class: 'klass' %li = link_to 'link', '#', class: 'klass' %li = link_to 'link', '#', class: 'klass' %li = link_to 'link', '#', class: 'klass' %section#id-7 .class-44 string-19 %ul.class-45.class-46 %li#id-8 = link_to 'link', '#', class: 'klass1 klass2' .class-47.class-48.class-49 Hello world .class-50 %pre.class-51(readonly="readonly" style='width:9px') :preserve %ul.class-52.class-53 %li#id-10 = link_to 'link', '#id-11', class: 'klass1 klass2' .class-54.class-55.class-56 Hello world %section#id-12 .class-57 string-20 %ul.class-58.class-59 %li = link_to 'link', '#' .class-60 string-21 .class-61 string-22 %li = link_to 'link', '#' .class-62 string-23 .class-63 string-24 .class-64 %pre.class-65(readonly="readonly" style='width:10px') :preserve %ul.class-66.class-67 %li = link_to 'link', '#' .class-68 string-25 .class-69 string-26 %li = link_to 'link', '#' .class-70 string-27 .class-71 string-28 %section#id-13 .class-72 string-29 %ul.class-73.class-74 %li = link_to 'link', '#' .class-75 string-30 .class-76 string-31 %li = link_to 'link', '#' = image_tag 'https://google.com/favicon.ico', class: 'klass1' .class-78 string-32 %li = link_to 'link', '#' = image_tag 'https://google.com/favicon.ico', class: 'klass1' .class-80 .class-81 string-33 .class-82 string-34 %li = link_to 'link', '#' = image_tag 'https://google.com/favicon.ico', class: 'klass1' .class-84 .class-85 string-35 .class-86 string-36 %li = link_to 'link', '#' = image_tag 'https://google.com/favicon.ico', class: 'klass1' .class-88 string-37 .class-89 string-38 .class-90 %pre.class-91(readonly="readonly" style='width:11px') :preserve %ul.class-92.class-93 %li = link_to 'link', '#' .class-94 string-39 .class-95 string-40 %li = link_to 'link', '#' = image_tag class: 'klass1' .class-96 string-41 %li = link_to 'link', '#' = image_tag class: 'klass1' .class-97 .class-98 string-42 .class-99 string-43 %li = link_to 'link', '#' = image_tag class: 'klass1' .class-100 .class-101 string-44 .class-102 string-45 %li = link_to 'link', '#' = image_tag class: 'klass1' .class-103 string-46 .class-104 string-47 %section#id-14 .class-105 string-48 %ul.class-106.class-107.class-108 %li = link_to 'link', '#' %li = link_to 'link', '#' %li = link_to 'link', '#' %li = link_to 'link', '#' .class-109 %pre.class-110(readonly="readonly" style='width:12px') :preserve %ul.class-111.class-112.class-113 %li = link_to 'link', '#' %li = link_to 'link', '#' %section#id-15 .class-114 string-49 %ul.class-115.class-116.class-117 %li = link_to 'link', '#', class: 'klass' = image_tag 'https://github.com/favicon.ico', class: 'klass' .class-119 string-50 %li = link_to 'link', '#', class: 'klass' = image_tag 'https://github.com/favicon.ico', class: 'klass' .class-121 string-51 %li = link_to 'link', '#', class: 'klass' = image_tag 'https://github.com/favicon.ico', class: 'klass' .class-123 string-52 %li = link_to 'link', '#', class: 'klass' = image_tag 'https://github.com/favicon.ico', class: 'klass' .class-125 string-53 .class-126 %pre.class-127(readonly="readonly" style='width:13px') :preserve %ul.class-128.class-129.class-130 %li = link_to 'link', '#' = image_tag clsss: 'klass' .class-131 string-54 %li = link_to 'link', '#' = image_tag clsss: 'klass' .class-132 string-55 %section#id-16 .class-133 string-56 %ul.class-134.class-135 %li= link_to 'link', '#' %li= link_to 'link', '#' %li= link_to 'link', '#' .class-136 %pre.class-137(readonly="readonly" style='width:14px') :preserve %ul.class-138.class-139 %li= link_to 'link', '#' %li= link_to 'link', '#' %li= link_to 'link', '#' %section#id-17 .class-140 string-57 .class-141 %ul.class-142 %li = image_tag 'https://github.com/favicon.ico' %li = image_tag 'https://github.com/favicon.ico' %li = image_tag 'https://github.com/favicon.ico' %pre.class-146(readonly="readonly" style='width:15px') :preserve %ul.class-147 %li = image_tag '' %li = image_tag '' %li = image_tag '' %section#id-18 .class-148 string-58 .class-149 .class-150 .class-151.class-152 = image_tag 'https://github.com/favicon.ico' .class-154.class-155 .class-156-title string-59 Hello world %pre.class-157(readonly="readonly" style='width:16px') :preserve .class-158 .class-159.class-160 Hello world .class-161.class-162 Hello world %p text-60 %section#id-19 .class-164 string-61 .class-165 .class-166 .class-167 = image_tag 'https://github.com/favicon.ico' .class-169 = image_tag 'https://github.com/favicon.ico' .class-171 = image_tag 'https://github.com/favicon.ico' .class-173 .class-174-title string-62 str %pre.class-175(readonly="readonly" style='width:17px') :preserve .class-176 .class-177 = image_tag '' .class-178 = image_tag '' .class-179 = image_tag '' .class-180 content %p text-63 %p text-64 %section#id-20 .class-182 string-65 .class-183 %ul.class-184.class-185 %li.class-186.class-187 %span.class-188 str %li.class-189 = link_to 'link', '#', class: 'klass' .class-190 %pre.class-191(readonly="readonly" style='width:18px') :preserve .class-192 %ul.class-193.class-194 %li.class-195.class-196 %span.class-197 str %li.class-198 = link_to 'link', '#', class: 'klass' %section#id-21 .class-199 string-66 .class-200 %ul.class-201 %li.class-202.class-203 %span.class-204 str %li.class-205 = link_to 'link', '#', class: 'klass' %li.class-206 = link_to 'link', '#', class: 'klass' .class-207 %pre.class-208(readonly="readonly" style='width:19px') :preserve .class-209 %ul.class-210 %li.class-211.class-212 %span.class-213 str %li.class-214 = link_to 'link', '#', class: 'klass' %li.class-215 = link_to 'link', '#', class: 'klass' %section#id-22 .class-216 string-67 %ul.class-217 %li.class-218 = link_to 'link', '#' %li = link_to 'link', '#' %li = link_to 'link', '#' .class-219 %pre.class-220(readonly="readonly" style='width:20px') :preserve %ul.class-221 %li.class-222 = link_to 'link', '#' %li = link_to 'link', '#' %li = link_to 'link', '#' %p text-68 %section#id-23 .class-223 string-69 %ul.class-224 %li = link_to 'link', '#' %li = link_to 'link', '#' %li = link_to 'link', '#' .class-225 %pre.class-226(readonly="readonly" style='width:21px') :preserve %ul.class-227 %li = link_to 'link', '#' %li = link_to 'link', '#' %li = link_to 'link', '#' %section#id-24 .class-228 string-70 .class-229 %a(href="#" class="button") Hello world %p text-71 %pre.class-230(readonly="readonly" style='width:22px') :preserve = link_to 'link', '#', class: 'klass' %a(href="#" class="button min") Hello world %pre.class-231(readonly="readonly" style='width:23px') :preserve = link_to 'link', '#', class: 'klass' %section#id-25 .class-232 string-72 .class-233 %a(href="#" class="klass") Hello world %p text-73 %pre.class-234(readonly="readonly" style='width:24px') :preserve = link_to 'link', '#', class: 'klass' %a(href="#" class="klass") Hello world %pre.class-235(readonly="readonly" style='width:25px') :preserve = link_to 'link', '#', class: 'klass' %a(href="#" class="klass") Hello world %pre.class-236(readonly="readonly" style='width:26px') :preserve = link_to 'link', '#', class: 'klass' %section#id-26 .class-237 string-74 .class-238 %a(href="#" class="klass") Hello world %p text-75 %pre.class-239(readonly="readonly" style='width:27px') :preserve = link_to 'link', '#', class: 'klass' %a(href="#" class="klass") Hello world %pre.class-240(readonly="readonly" style='width:28px') :preserve = link_to 'link', '#', class: 'klass' %a(href="#" class="klass") Hello world %pre.class-241(readonly="readonly" style='width:29px') :preserve = link_to 'link', '#', class: 'klass' %section#id-27 .class-242 string-76 .class-243 %a(href="#" class="klass") Hello world %p text-77 %pre.class-244(readonly="readonly" style='width:30px') :preserve = link_to 'link', '#', class: 'klass' %a(href="#" class="klass") Hello world %pre.class-245(readonly="readonly" style='width:31px') :preserve = link_to 'link', '#', class: 'klass' %a(href="#" class="klass") Hello world %pre.class-246(readonly="readonly" style='width:32px') :preserve = link_to 'link', '#', class: 'klass' %section#id-28 .class-247 string-78 %a(href="#" class="klass") str %span.class-248 str %b text-79 str .class-249 %pre.class-250(readonly="readonly" style='width:33px') :preserve = link_to 'link', '#' %span.class-251 str %b text-80 str %section#id-29 .class-252 string-81 %label.class-253{for: 'f1_c1'} %input{type: 'checkbox', id: 'f1_c1', checked: 'checked'} str %label.class-254{for: 'f1_c2'} %input{type: 'checkbox', id: 'f1_c2'} str .class-255 %pre.class-256(readonly="readonly" style='width:34px') :preserve %label.class-257{for: 'f1_c1'} %input{type: 'checkbox', id: 'f1_c1', checked: 'checked'} str %label.class-258{for: 'f1_c2'} %input{type: 'checkbox', id: 'f1_c2'} str %label.class-259{for: 'f1_r1'} %input{type: 'radio', name: 'form1', id: 'f1_r1', checked: 'checked'} str %label.class-260{for: 'f1_r2'} %input{type: 'radio', name: 'form1', id: 'f1_r2'} str .class-261 %pre.class-262(readonly="readonly" style='width:35px') :preserve %label.class-263{for: 'f1_r1'} %input{type: 'radio', name: 'form1', id: 'f1_r1', checked: 'checked'} str %label.class-264{for: 'f1_r2'} %input{type: 'radio', name: 'form1', id: 'f1_r2'} str %section#id-30 .class-265 string-82 %ul.class-266.class-267 %li %label.class-268{for: 'f2_c1'} %input{type: 'checkbox', id: 'f2_c1', checked: 'checked'} str %li %label.class-269{for: 'f2_c2'} %input{type: 'checkbox', id: 'f2_c2'} str .class-270 %pre.class-271(readonly="readonly" style='width:36px') :preserve %ul.class-272.class-273 %li %label.class-274{for: 'f2_c1'} %input{type: 'checkbox', id: 'f2_c1', checked: 'checked'} str %li %label.class-275{for: 'f2_c2'} %input{type: 'checkbox', id: 'f2_c2'} str %ul.class-276.class-277 %li %label.class-278{for: 'f2_r1'} %input{type: 'radio', name: 'form2', id: 'f2_r1', checked: 'checked'} str %li %label.class-279{for: 'f2_r2'} %input{type: 'radio', name: 'form2', id: 'f2_r2'} str .class-280 %pre.class-281(readonly="readonly" style='width:37px') :preserve %ul.class-282.class-283 %li %label.class-284{for: 'f2_r1'} %input{type: 'radio', name: 'form2', id: 'f2_r1', checked: 'checked'} str %li %label.class-285{for: 'f2_r2'} %input{type: 'radio', name: 'form2', id: 'f2_r2'} str %section#id-31 .class-286 string-83 .class-287 %ul.class-288 %li text-84 %li text-85 %pre.class-289(readonly="readonly" style='width:38px') :preserve %ul.class-290 %li text-86 %li text-87 %ul.class-291.class-292 %li text-88 %li text-89 %pre.class-293(readonly="readonly" style='width:39px') :preserve %ul.class-294.class-295 %li text-90 %li text-91 %ul.class-296.class-297 %li text-92 %li text-93 %pre.class-298(readonly="readonly" style='width:40px') :preserve %ul.class-299.class-300 %li text-94 %li text-95 %ul.class-301.class-302 %li text-96 %li text-97 %pre.class-303(readonly="readonly" style='width:41px') :preserve %ul.class-304.class-305 %li text-98 %li text-99 %section#id-32 .class-306 string-100 .class-307 = image_tag '#' = image_tag '#' %pre.class-312(readonly="readonly" style='width:42px') :preserve = image_tag '#' = image_tag '#' %section#id-33 .class-315 string-101 .class-316 = image_tag '#' %span.class-317 str %pre.class-318(readonly="readonly" style='width:43px') :preserve = image_tag '#' %span.class-319 str %section#id-34 .class-320 string-102 .class-321 %a(href="#" class="klass") %pre.class-322(readonly="readonly" style='width:44px') :preserve = link_to '', '#', class: 'klass' %section#id-35 .class-323 string-103 .class-324 %a(href="#" class="klass") %pre.class-325(readonly="readonly" style='width:45px') :preserve = link_to '', '#', class: 'klass' %section#id-36 .class-326 string-104 .class-327 .class-328 %a(rel="prev" href="#") %a(rel="next" href="#") %pre.class-329(readonly="readonly" style='width:46px') :preserve .class-330 = link_to '', '#', rel: 'klass' = link_to '', '#', rel: 'klass' %section#id-37 .class-331 string-105 .class-332 .class-333 .class-334 %strong text-106 %span text-107 .class-335{ style: "width: 50%;" } %pre.class-336{ readonly: "readonly", style: "height: 120px" } :preserve .class-337 .class-338 %strong text-108 %span text-109 .class-339{ style: "width: 50%;" } .class-340.class-341 .class-342 %strong text-110 %span text-111 .class-343{ style: "width: 50%;" } %pre.class-344{ readonly: "readonly", style: "height: 120px" } :preserve .class-345.class-346 .class-347 %strong text-112 %span text-113 .class-348{ style: "width: 50%;" } %section#id-38 .class-349 string-114 .class-350 = render '#' = render '#' %pre.class-351(readonly="readonly" style='width:47px') :preserve = render '#' = render '#' %p text-115 %p text-116 %section#id-39 .class-353 string-117 .class-354 = link_to 'link', '#', class: 'klass1 klass2', :'data-foo_bar' => 'foo!!' .class-355 .class-356 string-118 %pre.class-357(readonly="readonly" style='width:48px') :preserve = link_to 'link', '#', class: 'klass1 klass2', :'data-foo_bar' => 'foo!!' .class-358 string-119 %pre.class-359(readonly="readonly" style='width:49px') :preserve foo.bar('Hoge') %section#id-40 .class-361 string-120 .class-362 = link_to 'link', '#', class: 'klass1 klass2 klass3' .class-363 .class-364 string-121 %pre.class-365(readonly="readonly" style='width:50px') :preserve = link_to 'link', '#', class: 'klass1 klass2 klass3' .class-366 string-122 %pre.class-367(readonly="readonly" style='width:51px') :preserve #id-43.class-368.class-369 .class-370 .class-371 string-123 %a.class-372{href: "#"} str %p text-124 %p text-125 .class-373 string-126 %pre.class-374(readonly="readonly" style='width:52px') :preserve // hello $(window).bind('click', function(event) { }); // hello $('#id-44').bind('click', function(event) { }); // world $('#id-45').bind('click', function(event) { }); %p text-127 %section#id-46 .class-378 string-128 .class-379 %ul.class-380 %li.class-381 str1 %li.class-382 str2 %li.class-383 str3 :javascript $('.class-384').foo({bar: '.class-386'}); :css .class-387 { min-height: 13px; } .class-388 { height: 1px; background: #000; padding: 1px; text-align: center; } .class-390 { background: #000; } .class-392 { background: #000; } .class-394 %pre.class-395(readonly="readonly" style='width:53px') :preserve .class-396 %ul.class-397 %li.class-398 str1 %li.class-399 str2 %li.class-400 str3 :javascript $('.class-401').bar({foo: '.class-403'}); %ul.class-404.class-405 %li= link_to 'link', '#' %li= link_to 'link', '#' %li= link_to 'link', '#' .class-406 %ul.class-407 %li#id-52A.class-408 str1 %li#id-53B.class-409 str2 %li#id-54C.class-410 str3 :javascript $('.class-411').click({foo: '.class-413 > li > a'}); :css .class-414 { height: 1px; background: #000; padding: 1px; text-align: center; } .class-416 { background: #000; } .class-418 { background: #000; } .class-420 %pre.class-421(readonly="readonly" style='width:54px') :preserve %ul.class-422.class-423 %li= link_to 'link', '#' %li= link_to 'link', '#' %li= link_to 'link', '#' .class-424 %ul.class-425 %li#id-60A.class-426 str1 %li#id-61B.class-427 str2 %li#id-62C.class-428 str3 :javascript $('.class-429').bind({links: '.klass'}); %section#id-63 .class-432 string-136 .class-433 .class-434 string-137 %pre.class-435(readonly="readonly" style='width:55px') :preserve #id-64 -# hello .class-436 -# world %span.class-437 #id-65 -# hey .class-438 string-138 %pre.class-439(readonly="readonly" style='width:56px') :preserve // hello $(document).bind('click', function(event) { }); // world $(document).bind('click', function(event) { }); #id-66XXX.class-442.class-443 .class-444 .class-445 string-139 %a.class-446{href: "#"} str :javascript (function ($) { $(".foo").removeClass("bar"); })(jQuery); hamlit-2.15.1/benchmark/etc/real_sample.rb000066400000000000000000000003141407657076200204100ustar00rootroot00000000000000def render(*) '
' end def link_to(a, b, *c) "'.freeze end def image_tag(*) '' end hamlit-2.15.1/benchmark/etc/static_analyzer.haml000066400000000000000000000001151407657076200216350ustar00rootroot00000000000000#foo.bar{ data: { 'user' => { id: 1234, name: 'k0kubun' }, book_id: 5432 } } hamlit-2.15.1/benchmark/etc/string_interpolation.haml000066400000000000000000000001101407657076200227110ustar00rootroot00000000000000- id = 12347 %a{ href: "https://example.com/users/#{id}" }= "id: #{id}" hamlit-2.15.1/benchmark/etc/tags.haml000066400000000000000000000000311407657076200173740ustar00rootroot00000000000000%span hello %div world hamlit-2.15.1/benchmark/etc/tags_loop.haml000066400000000000000000000000351407657076200204310ustar00rootroot00000000000000- 100.times do %span hello hamlit-2.15.1/benchmark/ext/000077500000000000000000000000001407657076200156265ustar00rootroot00000000000000hamlit-2.15.1/benchmark/ext/build_data.rb000077500000000000000000000007441407657076200202530ustar00rootroot00000000000000#!/usr/bin/env ruby require 'bundler/setup' require 'hamlit' require 'faml' require 'benchmark/ips' require_relative '../utils/benchmark_ips_extension' h = { 'user' => { id: 1234, name: 'k0kubun' }, book_id: 5432 } Benchmark.ips do |x| quote = "'" faml_options = { data: h } x.report("Faml::AB.build") { Faml::AttributeBuilder.build(quote, true, nil, faml_options) } x.report("Hamlit.build_data") { Hamlit::AttributeBuilder.build_data(true, quote, h) } x.compare! end hamlit-2.15.1/benchmark/ext/build_id.rb000077500000000000000000000006451407657076200177360ustar00rootroot00000000000000#!/usr/bin/env ruby require 'bundler/setup' require 'hamlit' require 'faml' require 'benchmark/ips' require_relative '../utils/benchmark_ips_extension' Benchmark.ips do |x| x.report("Faml::AB.build") { Faml::AttributeBuilder.build("'", true, nil, {:id=>"book"}, id: %w[content active]) } x.report("Hamlit::AB.build_id") { Hamlit::AttributeBuilder.build_id(true, "book", %w[content active]) } x.compare! end hamlit-2.15.1/benchmark/graph/000077500000000000000000000000001407657076200161275ustar00rootroot00000000000000hamlit-2.15.1/benchmark/graph/graph.key000066400000000000000000014212561407657076200177550ustar00rootroot00000000000000PK1G }}3Data/mt-C1125456-CB99-40E9-B950-F75BF800AE14-85.jpgJFIFHHLExifMM*i 8Photoshop 3.08BIM8BIM%ُ B~ " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzC C   ?|o9'l0dj0'5?MN?ɮs%3>j65׍q9%E;_Aϡᜆx[[O^i7u#~~x+{? /)0DK}1Swő2<Hϥ~>giH;xٗ^GQȿd2$`0;g/Vq}6 kWwKvzG3 2Xd_Kq#>kuXaBtqɯ1ᧂ0PdP"8k- v$5 %e$U8'eT)r$s^!U77oa.9U&V >UUQ: #;jWpzֽx4];ƞVqF>6qX]cG^%'n=*eܮǨڠ6s\4`ִ&MJvD*K]?k/0\h2):JȁPl~LgHU5]Oo]Hd[\u3?|,!Ԡrlp+فn{(9=o ckf|x};9fqعpz.+|B |k5TڈIز(XO#+ ~+B_zmےW=zkzcX<-Yz|.?^h`$Jn8e?9y>=v&x+PkOZgƍ U"1he^qYI*_E|.9U\]U_)_u OZc~L2&nT%K+şQ<|7|'c۪Ԍqm ng;v21n1=:^cxћ9cE޿̓Ÿ ݯď:}nת꿮h/mHЌ1і ݝ>S<Ou,[S&#(G7w~|>6m>&g 3k?<3kz[\CiWeacǫ{?'V_=jWVq ~* hQ_>+Eequk'ؐ/ڋޡfo&8mwcUGRkW>Qվ7H^v;#%mlK nf'3i~>?$Kq&>{=8#ڿ} `1o )JOvwZv˽CN/ͱws>[ѽt@t`V*U9›u'[ub~cK@m+Wk;pUcߐ8ʓp9| jhZ{h@߻՜ҾÐ#N?Vu{ *VV+ەjߣIEԛxR/뚟U s8^e#ٽF;I' >G #g|q[FL77H-20AxyPevӵۺ7pq8ybcv-+UB"23# $* b_x>lll/-®w A! +1%>\8,U:jWm8]Iu%|uOş? +u\Zn1Alj~n2ZTb+`R}?oZXFw [O@+SSO9]I+}#3&ҋm$۵ש(źT0xK=ᴫGW*y:rzץxslw-2L(=X & X<*pdtnwqch s]8!pUcs\z4x{5Җ2Q|w>1il.)AXZ~+h36G\~Mں/Lx~߂|o W[km9nGo-l˅7lXX`W:,~,?(˸Mʇ6r>_|{RJq_杞4U*q+Ln"2e7=2q[Aq|\M sO 8⦥cX98I]o9-~ e[4 Txj|m;x2u)7mdգ(9#8= o-g*Ԓd`q5ϭx_OedbbhNI1pl1 B+ sV+igu{crJH[w_|<+aK`("9Xx5vBO_HOu #[{m'*+\Iw(9S" Jt|^:bq 25ďٷMԥ[Ki_>>xE(7^o}A2Tq>ot `?q3H$=?^O j..o%6$>OB88e66N~>Y5q!-,Z#AϽUL{^ǫn8#Ey6F,/+Nj+5_ ;o]YCk㺸ũf%ߨj>z<WWet.Oo_oŚ{;WXs!G_f^{ۉ4c+~3y_>yfY>_GˤڮBn3߮kIay:zEȷkPztϷ_ńc.K@A$+iZQI[:߇ 7G  ja);p_N7e~ ҿ%a1<;yI=OyJѿoMyGK/6 GXc&GV$+*ŖǜfEE̖+}IFxNB1^|?Q>qKU]mŕৄ/eIޚ''<7oV4Z]M=U;wg6F23VK+~5iitn2&@N U̟v5]Vw֚VH[ rGC[~e.èeO>]1{E&G!'_Yl}<=Yb׵wگuj-zdxzQ)EF;I][ovݛKiKzc'WΟ>+]6V:lHPGEf'8gj]RfSzo7hNp >eP4sS`u~P> x9.S5j[4ߩ't%uig&&KYU]8|9O 7W5M6<1"X p^ݮ|'%}Zx  #@rd|A瀾i^!͗~gPs)xh)7X}rsƣ/Yi5+Edn?f_4?kψ<=N^ n5 Z^J-,Y$eP_3m x^x@8RC+#2|:)txϋ56a*y )d@/&ŏ|j]Vky~ ZH\;  f9PWWQv^W?kɰіjmC>]lI3``gھv0.'eyGsk᫁o$r2q+G_p~M~(ϋeK\bX. -71qm`#qTr\nym_30'7-5-9$d/6ޤ5a~.*~zecV;c1W~ߴ?ÝS~=BdIшq9rI!KkS~O7Ay Hۜ`>­c=|m~_KOjv=ْDZ#^o~|8nc'JmH\<{$r34x#5~hL?1x& !F?|;'iNj#T\1:^*G.-ޛ*%N Cn+?pg|9f;^g^W{=<m^pAU<; mwe!__~x;E 5U>ۇ5~ 7ry\ y_{\A/.Ӳ/tgϔCpAiXi9X5 Б޽nLQ#%޴E]q"=%f\Ks©=,?`i 4X'^in@:ujsclNK+}Oi~ ҟGCӝĎ7Qn~wH ^ G%,|9Wq\]Ƞ U־5ѭPm=ּĖڗth (@#'KPQ>S"o<ZS5+Nފ^Ӧž# VgM5K/uۤQcƜI?GҼ'AKUK(Yܺab%=3m[h>56NI\ ^|{c1J7>ケE3r3< :rJm]Ϧʸc U: :SwN#tΧ۴%$UKqʲ хA8,^GM@=ÐȾqHXC?1 z`yI|s}[PwCNH|3a$vv8KG`dmigx{nH-Ħ^FT1''ˮ;WFVMkwŠ8z2*ԧMI̤֯K%ӲZQ_+ρ[ZseHbeX0Yy] 3W^# 5otU:Š Q kjߌz1y.u{Np>k>ៈ?t=JLaB2ac k&`88 ;Fm붮͕^3-TR*J^'Ŀ(P5IYdQel"' lbK(.u_~ǖTe_#W!Uxf<پ!sb I&*َoa0Yc5*?4o?< Nh46 c ga]*%a# |/e9Xl֥'k\޽ݭt^ ;kCO] WxOQKseWwN{=zk_#hѭٴ|+_1rz크x[.nmm[ےd=[G@2c χ-lt%\2NI'kȾ8xW!PI!E*AVRo.G5A}ϒ~%mWJաil5[%;4L~c WҥAwO?x>75\\}p3ӊޣFelwsP|W?u R/8O_@k׿g:GO)].5PYK' s㟎|8|Бzq p#=2m6[]zv.6ןj~)}>>vˡXON;7*jyLN3a+ūvu3SQ79t@14x|8+կƋ|\0 K)lW|4]?YX\Px$79~П,m߁]Q]SF$s-KaP3g5b2l~\zG?bbIMb\pOj$3#EtN 0ο#߶OڟŮKFܬ}4s]i$p(~Au3­8R1ȯʳU8k}2>_|WmK-9s8u hxa CЏq~.;Tc9=:,˭%U?#Wazu(%~OKUJGhȞ}AU3N8jo1ռ/)K^ڜes#'.t,ՙ>]xSM>@bh I@$ki?k*i*vж 79q?׽|G6ɢFsh[#sI|EAx_ú4MJdUK 87dd e~3Owo0xYмg}~E`37v {#=kgQFpק񿏭!]m5Ǔ  B 䀠~]D:VZG`lmHuvM^簯ϰTOWiuONݷ/Y6~_'ߚ1hIM$:REn (p5φ[[*LbX28Gך\iڬoQ *M9@@ ϧ?dڇZZ5QgJfx9VHLjzp9w6UXjxoi65v}RV/gyM*j:OJWѦVFc?]оZܬr^4OunϽWI.$N+AREpD ۜpNk~/hYmA?5ac31:p~ɿ i61lꖫha)8A )9=mr2+;Ϛo~+y-Ym,Y3_$VN\t3+ 0ж_^ Ĭ5}F 45d4qsGzoX\^kuمZCg4ȁm%F>RA9 -.lʬkGrHM9[x E%ُuÚʵZejj_|r7]z}^ U> x&9>\w#%tWgc;1qNCmxQ>&j:u 6M7Y^#hC.)3 C &꾡uaSźLjO8n5>_K#嘍nd100ýM uK ugֵ!PRkUJIHf'+ y%I]V䏽%N{嬣םݓŸ Oi\Jd Sx^x~dQ@,Oֿ  OoF~6Z&kW[Af-,7rMt׋3KYY(g5S)9._lV%E'ɿCM_3M[N}>)~R1לϊƃͤ-1$'-$IFj rx8Հ\oSb@Rlz =ƾ;|[Iq37 : (E뱏 ڴ0mq<})/>-mU*~=bNîI/NW 8Hp4C/\3הjC2,]N٢v #Î힟~|gzr^]On%!ExW=׈,|3 3q*wHG\Gr0;}؋ y,aD@j;8'}E朝cg|ִ{<7Y|TI\2Cv9oA_+$PQJ=kևihdDN?zRW^/Eӽ]Y μjr,U|iPҡh_ E W?#X^iTWٓy~.WX9jIw,o“~Kb^Xj~Suҿ`}MWGԣKj&[2w).zq:4-yӾ0C,TgߖC_7QO@(Ӣ=e#J9_ΏYn7ode^CqkJY߁_s*U'zCg)Bp>x_\oWq~l@m(pX0\47xUoDU#314v-_I_~-tπSťO3aF ((£P9ɮOS,t+]C)7N)d<5gZ8ˤ2Rq[Z[<7@4\\Jp!AvkžsۍS3Ci"0a,O9۾k{}ujMyewL sy}寉 :b&;`bN*@_5.|=%%:$x*n eWK;\Hְʻǀq:gv&Y9sm )+܆|?q^'L$IejbTid>dCp>_lAm+kD,}OOq^Gb]mIV&S%ᜡ.ri5ywh_>~ANºvlͿY?thdnC3JT<`ڇWwZ[Nq Aܰo0d1zm>+M6d{s ` iFx5o~9ǿ .tnyݶezG<6m&p<;Te]U[o˲c^1#E)&]U?gThGu(6 ?#!H_&xEcx XE%r.Cn < -5 ix6R2 d?/μUy.<{7`m7W tppqYʪu$ӷmoۯʜ؎Zo[=_`ڣZNjZs۸FB+y]7ln@ѐ;(rH88^ kv~;ȳ\DC4ۂfRN:!p_ AzMOB|kyL-T hI8\>Vvۜ_}_pdk^3~Z.s'++{Tjoor9Hk/[!~ZeJ' `;^&Sہ⟉<0VZaq=';^:g4~ۤ]:&NFxˑ }Sbk+%b79j39Z~&~|)&zNdn,e `W'Ԃ!~KrAV9=GMƚٜ3ֿ;,Szyd\ @[[I'$^(5K].# F[ G _6"Jvgõ~]\:-' yWZO,Fj/j=8&%R;݂Ȝ^ ߍty՜,%d|pKvn>9uH/𫞫$cӌ\EuiwŻg)kLƏ,wJ`zG߄Zo|Q xLHnOTp7B\̑&r G) ?Jm~Ն5݅Lj4F5SK}]0fԑW'˼# :ϭ{HEsO\gmٝC[QGQưr N5n\O~w뺏%9u- exq'Aǁ k+,qȅw?ޯ6\xםWƬUOe}ͮc2^o>IZ .]bi| H|2/Vnʋ"P0ݏu6? 5ȇ"a6rb\k%66{IE$gɗ!?RK3h_h[[;* ;ă@5'LEܮum-gO$Yd)Uޒ[[kJdէ P˧i_xtyq!<ӠϏ# /^):˺J = w!\h<asa}vnvђ]p]35hJGϏ?>Z$m͒Fg7đ#;LNNIz㧇#Rܷ/Cj᧘Оhj{yC~?U_`4: Y|=w%K|]^H?:Hۦιkσ/ĿXDT5!$!Jzw3A*+_>oFӑgJ c_Vg|]$9@7)8rG =7WqX,ŭcdr[_ٞg)c/E7u;]G?{³TӖ@\SFZ97q#n8oV&qZIo1KMN/# NJKg3|3{z5e>G`dy|?'DP'v4?B]GޣyB#rK1ZU3ʔ7GmE?FۗY~8uj5=iFٻWk_5/oZ_iYfIq̫H$O$g~"/KL6X<[&x.y+O|xִ#es!e3Ac0=3Q{7DA,F2I+c%IwwV>z]romV ύ3OnR# F4 `ukSj|T𦯨N`.gFgP: 8<?ҵKc@K> H~=x'u&=6곤A?"qVfhՍgi[V>lnSz({('x׻O'nƏO㇃~,F\%7&D턎"|˸aHExdA;[t#׎eT~쬷Ѯ=ݐ߀_LS_e]:o&6 ,`'~*gl~FUJe%VY~*m]gnwyG?Z|"+)/=x"x: YJþ0OC{ߛk->'m 8T @ '~ K)H-)UO269~UJ\TV[ Gҵ?:<]Rߊ`#srAhzs^GGxJQkU8m`xH}O|1/4Z!ܒ(.U#+Sεh_A+ 77goTg,R87Ν)If/*_Ce/']? zmY%TA7K^՝m>Aײ)Jx]mA̫1FPQ2@B)PuԡKo#U2{a,*(3e9Xv?iሠHaәRT@Zf&]Ӷ+w ty]>4q>^g/7T;`:X9=3_;_Yw w#d*2̹FKݕΝi[F]&~P=rO^ZxKn0K):GnpzQ9%Op>yѬ=goڷ ˨d|R->@k7~pFGÍbU?4{<wiz4 9Mߒc-R:Ef-a>^ nl|&0 O2mDeqA_hOj_t뿅輪M) ŎrGɧQwi]m~y\H,m_ᯇďObenϝ <+k+x8ӥ<"ђ2$C ^.Ær-~^űf.y)unߍ/٧l`-cC" ۆ#܀ #~x~Po^,yk5IoP~A+_} 8:cciTLB_qc/e2ck~ |=y%ͪLБqJ>iapQ~qeS< uIøa'<_JMj ?^.x(ncEfݐ+eN= /wǿwK/m_C yS٦nV, 2sC;ao]kF&dGr8g$v,+,= 8l7#SkiS>c1Y bصm􌕤{й??!|Ai{5t/Co,'ȋ,~6~~1$U pOZe"$crG|^y+kk$֣٦ 堸*& +n#'c);Elӿ~\2DJ O/ȏv{جɎDѰWjOfog -$w@fLŀb~? |&;XT?H5:е=5kݶE1H=O*}sJIOc\+>;ğ< > ghа N2=U Zkp{jT.P?:t|7 n/zN+~-XxO%_f\_8+fTբk\y5ʟWg Mȹ 73188$_sץ{c9)Gk0J J?+G2:+/ ]{h/3Upqp:|WkW&ᛋem@ѱy%*"=6^_^#*^R~YH8Cע~Vma+"r6ӊGH2m $Wlzz&d1ca=9>w!Ƨt#ǰ ~UIL\zDwvw쭅UtGlwhT#;^1X#4v2QgJExO lk.kmM?_D|\25X4 z7o#9(Jusck~qy8v`&E`N75D]{6B6EכÖyuSVidw]]C)bA#:ou /zwZi".Pt|u<{g ONu}jI>o^{Sb õ+Z^Qni_hxA7^mn )>ET_FTp _ZׇZ'+^/][/ٿ¾1{hgV! ~3ƫJ܀kߴm2ҭ-m5X*W;/VwW5Gvkr8;8J _-SY~%ԵZy OC_|f:u~i?{ͷoQRiي9ϥ,tX[ɫ~Wi6ZyԖ+^VIhcǿf}v|1"oU<*d~ӎ?/'S3=X{P^*x9Xm?4h~cuOZĊ4H_+v1-k/< #I8d9ci%Z )Bݝ9h9kݧx80b#}Zyu?ȼ;⟌%M}+Hu#<1?y]O;dn7 |(8$>nqdv)r>_?? -G ͦ$3̑dpx}Іo C^wgEeOFyz_>˂r< I0|_nO/N OZ@E}cc1eoC:U[uo∟uzF&jv Ǩ2ޔpJ:3&,[KT~6@?g_7#mumˮMD0GQHǘy5x(Y~톟]4Y<dXZH\L̬$)OpIrI4Wp}W_|cyUSD]{Liahwː~#~oqjb&K_4?K`(rKԕ{N:%$_Z9JE_duOj(kQ6X셣u#rG RC0r=_'BxS~{˳͊41ʂHYfx> >|/Ҵoj+ S,I!Ҿ95'ki*rGKghk]D,vOI|CQڋVS,aX ۃ8IVoܧ:cpm&|_ׇ9'KL'& n> ,MMvFl>Z{xɒR~E2wn~p9=zW_{ǫѬ|@]*Zt{P6hL$?ta2Oُ_ <7eZ.ke(+4*8d"BzsG'k~y)PPX}[_>Ƨυ[A A xBH/^9 Mijڇrv9MK[my RCvV$s2yN,o|FE sӯCΎul4 ao3nhYI9>[+]i،E?1>t=sPC}\,VS* ~<ֶ]9J̅v/: c`w5a~ϧDt:m͡Z`*0~'<w}fy?2D8]Hf6k!;{`J&"|?jA_S~뷾"hl+7r1ߜO?cxW|/ڋUtg,H_WXeE-25qjIiwR(^UI*$ s_ o hWr'W'$-qf#0Gჽn޾GE,>GNXnjM8mj'ӆ?k4vH"yN^g?.fh|%gb ̜/vA+G_ #^As$H'ˠumUʁ_?!8&NV'1nҼ|׌h尓I'-ߕg>Yv`_nв/1y;I>ًߏ^&QK~']|Iq 2V0ˍ܀r5cu)}RV嗶=ݧNZR%'k:zIpī[kh}s~$xS:`s蚀sǾX07 3skC¿|7_i]fť\:Ha P; K?fOZ}gWա.X7Dhp&ѹ^~={Kʑ䝧˰8cꟖO~œ#SRx|TT_386ܔ96,5I;3i'KU[iEWn珎Uq=Z1VcքZGtf6Q+t8+AGm;K=2r@; asV{Hiw(O?#q,ռ|]-M `Tmb/k`s kwJ{Ph-. r5QotS9_:$FkZU%yhH: &G>1M.忽ZLy1>9Qw8BhR|5TyMގ܉zՎe7.i~mxwU>=ՔaK LTN@CG/~y$GĺNrHRg|.Oδv575i5QU'ԚKf9B9ڡy'/^9(Ow]t C5oCu/zO6C`2mV>}9Yo&D) +흫Ԟai6~:)d8cAY~8?|5-?8.Gw 1ml4\*8&LWŸwǽ{g}P ku) !FZFbs^7*׏5NE5%ŵ{JN$Yq kZ+n~~? oMaxC6mp8l:O ѵ].n`^U[|g!,sU65m<*_GRjSٷ(7k?sR+rt~}LM_np &t˶8B~!=O!? |E7~$Z[$\erGCI֭l3iXB~eG#׿~5uOCq"-@W|6x3˱ױzrgJ&]\_z=cVЮ< /x*̰Q50 ]烆xW,\yo{Bv̼FಷVQA WD;M!1ɍYM F~=t1ִ=B5a-ťX1z }nYN⚎>Z7WK{;sx~>y8烽7x]|YouzN{kK40Pvz }-w 0TcؒxQ"| |`_nrn.൬dퟦpxuYkROzfw6v9cO7{W~`tfBi?atVQӽH{TAiyG&vO jwWMmqlŤPv}Q^=x~ԭῶHanG" #@5oigzF:'lԈ%'I{/! vxF1)[ FEgts<WϱThRTegpixt䜥xgk.|3v3m[>cYGʹq%G5*==cPKr6x={<7?[&"4LdՔ~m*{Y{\5C[I0סĹX-^H%ϿA^&sƪ.\iJtg=:Z%x`˵b8󏘌}p3{wD!_AOE=pzgӧPlLQ[`8 PA-sֻ6-r'-_8Y9nf! 1Pw'y]Ǩtl9:M٦̱,F8y?(2W#ڝs-Ŀ)d Xn>g*cbmg;snqg/qH/,ۊond2;R1 $漣CAovqػw<_oFz&(2^jSp"t~osm>ٮjڂyOeAč,A8O^Le(J{`eʅC1{3{<.VK/&"8*' YMQi(fC/'U@'&:,dEHS\}(]~3"6{oT+x;Mis-ěBGMفWa ezvm׈n|ouAȣ9 cRs<<׾~ʟ~ |;XxUh+OP UVeqsWGW^K{F IF+ϻc\eP\m_Fm W [ i.rX̌7 Vb0 8(bq0β)E^oDoF?Ho`]+}3wߌ?gzIU_:J[3?ĒOy+Xяď5 l_x9/ts׃&>2xV᧎[}nDzFAǮ;)?ϯi(C⽌^Ye<W QcqkZgVnϒ;r߬M~bzr?.Do_ȎB-$ֱ>&wCoj1UǮ:{unD1`ŚyrcfG;#^/ŸiZޝ'¯ar]Z7B QОqwU ԔvsJ~-%Nr?ՙ?t>>TVk_F0QY?|U5W]Z]sgrN7"'"|Ew~6NJ~ͧWx >Dv2@w?M0Hl+FVA?>rz'\9j] 4)aK긺7EIu+E>8dݽ"sk"yW,Axۍ )|NkVn$nӎ!sLv1mECLgn}'dk36''c^- Ŗ%j6n9~Ǐ'U=k1rONS<,ѿhee)mrTEui='xf?0!?s3H90z~ۿ vcw^WLoRHEp὆a <#]vo _y=5RZӄ6n9Z}}=  mN3Ǹ*ؚeVzMsJA4$J-FI^FWOgoϧE,W` @@ Nrݏ$ת[S<+ }'yѯ'6ѬZʄ#8;:d`r8k״{ ڧ@ΰrvc#ft&C!Q7@ s>΄mj`=TdWc=:JsuC*`<ǡkIg% .0C`o ]_{'}=I%I#6*\z`uԭ%)0͐O:E˫s8\te2I2Cd20L}=zJzْcϖgwHF9鸞}v \_U+،jr$h·pz ݁?M ," 'gZIisH/ kQ[Cy}rO8@ =s7exlA6~\):lg_?/&]5o8WkC?%sRwȚOcgi?zJ$xkt}Σi}hIX#H8Og4{+9lp1r?iտLo"֍]#Ы 53Ϛ?޾*eRz9K>72lTyN{Q֜,Q5+j[L#kxC]3Ɵ$o(=Ɨou֡+m+s^Y F|;"gkO?^7K N:*:xZ1䕛7Dy澍JWk?7*%5c^0ލ񂋉c6HHib=m.xH)\z37vׯG!%zo?EUUXܿ Ǖ&J]%;ū[$cS䖖ۦy>|(Ŝ>hAMr^=Q3^w&jogf_vxFEe I6 {m;zNtUז_i<3 ŷ r6=Jo3 ξ\ѩ^OW/+֕8N*iϯ4_M+s$ΚJU"i;| Wk0\ Ԋ|Mc9bz?>+ډ &$֒1' ,dckcab= ]so $sc<}o5Ũ@HW88>8ZF{OM}#Q׻5l?F̖;HA l.\q@%ySqV5;ÇA:o~^u![Xg} ?GǃR:|w &Ͳu$!#+*[:h[#%p~ #-'v:޳=5?VѨgmdr3.k얀I&wc1Ҫj1|Wl=s*Ɖ!?ޓW+:?k_q<]8'c0"\઒{e} oy*gDPK1GtO^^=Data/110809_familychineseoahu_en_02390_2880x1921-small-10.jpgJFIFHHLExifMM*i8Photoshop 3.08BIM8BIM%ُ B~" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzC  C  ?ݓ>zu*0۰s=OziISxnq3pfsO$ߧ^>$(OClwc@{sk}6Ѯlgl}ս Pmng-y3לz_'x iwv5+rɽ@?|բA|N񥟃4ve[.@!W8ʂy1QSܛ+n_VzGV~"2 ɼPKp~cׁtvZ1IPK 3nsRr{o h:w[OR4Hqv#nY8{q[n *q~rӅ,u7z/BT(/Ax`8xAqɵ `v;;O~'pzWZgOU4br!|׌uQ g?wב۩~VkC<rYR@Z?k^" 'WPV(2H7Ȋ:&ܮjg',#k^[SF*l;Fqۇw-Mțc7Sm@y{.=2deEzu y\Bjw2T.ɳ#v6x<8U$CL`fL<ӥ;P; =CIr[|Pyw6t֦пmϊ> _^C}j@#%YqǐI?D6,^h]b1<䃹z=(%mtצy=wSg۩^XȒ|ߏFpQpNw .Er #zѭ q_?RWǯ {%'f޹ g\>I6v<ׯet@cӃ<~q`#j;eOaxIV<"K(FfĆTt}y5׺ 4 q1x]i>C}zz.Q]o|G>%[NYbXO>i:X7-#wG'<Ua@ܘ'y˹v.oa 9cϹ}+mAUNq:j)u qK}:Ԇ?y4L,F0kl lcdCG_"$i% z?֩͢z'kŪ6'0kA'9 ߇=ÿDx!A}HڑNy8>ּ1by_|}x7ۃR4 $y=rO־ߊn]mMGP`̐BG ʢv y =:TU(zGp[j{IlC4f@Y.}^c5x:t$$Gdq.dn瑂=GT}K{ JyVE ,`204o61pͺchFpxR6.ln$C8^eyr&O_3=VKN= ?Rശ In3d9ٝgF0CɣX;@wlq|gNss cDRN kn𶋦ݾm s\!kePw|mjeZ^m; p訲2Nzg=14ߋ>յ/T[mdh•Pcf%FqGnkV)r?CɆcF%Bۧ}#6[.WcyFDY3S>X9mv'8xqkm?^""yŷ,.3!p9[ZI> ƍE;]'ϫ| iucs߷|A0vrzӞ'oOG08<\tnCŻ!A{Wԩ)-fKmU^A00Izv~kx zO2i'" 2 Oa8_pL\Q6 pv$c3qZ`HTyߍw`OQ__US>)¸WY3yƯX:?\E.KG"w=M{ֹ'Ķ&7^$BG%[ȃ#&Nfe[Q e3\qNF8P3 *~U#q8NEuFTc?ɺ0@󓂹v9#ةJ2:xz~U2$ )ϮAZ|65%{ >u^|k[ n/=}k}qʦkV8NH?Iʲ@qףk:."# nP0+BՉ-^q {_WZ]S7pqs\֙ • ^^r?vrZtpm%nЧBsZ=k ϴ/`yS牾0" 3S񎡤}4&HlN|$@ H$_xw6̂cglDky匬'םx;ľ`DAfMC.cIh$g KR컒-y/1*Y)o,zlڃ*( "[#9F#ycUhK07Pn |ao?Xhvz5Av!xT9eeVYwzֽs5G-S%3b8G6| S7:_^7M]Mz_߆5]dj6UJ QĆ[aa0~[tXWWQfxC<:VĿWthgf}) qA` $8R~_.Miiz^=1m:+#kPTI >ɮVrc_dtR*Ѣ#ܚ]MƑ/<!v7HbLp$H*'TO/OƭKҟ1#& lLg;K,U!:wOyͥ:JUҗ2h\2Ē R#I<$#R$++ ~\`ج++*<=eN8h(J]G~5o>_VryWR/t,?^t[+&t^(ɗ)@ 2@=A,lxS@uOL"/F&oxȲpy(~&=w[藐ĄdS8@̀m|#٦趹mǷZKuTm&us P|Y'c{޽5(bN JҞPJ0}7d G5",R+H\lu ][ʃ8 3`sҾ#J}Oe9V8?e?ahN&X"vDp܉Xfܓ鎇뿎_ir2ܤ̣,I# 1:šJM y3*(X: 7{o2F ё7G%O?kVG͟1T Z枨` ~YXjp \ǜp1ЃakYmc`wѬX`c쐸tV\sgr׿_Zih1Jܽڔ&`zd0^F?Ɖ4dl˂1^z澞4 /[@m (D dr:dž&IIY8+؜j+d.w3١*l "W 8?TYJ/@H==[EUt?*b1;vE<:[Jz# &7u8tb۽zc:fh3Hunߧgm Td۱|*:2<~_>6#z~p.`EJrd;0~P1J, L*pz{z.mjaaR$p1$A=o)᮪ck*|n'g5Ox7s\`2.I;p<zWzfgq]y\bAO_3u{X3mKhQ\UO:J@ X bxʆMzؼ-$XmFrWo:}^Egxɹ%ܫ#BߊkO۩[$Ɋ|h2w(+m;!1+yP -viںufYه, mΑxTOUjrv;)> \^^Ji^ԯ绎=M,oE$l`H#?EҼ16o%C l62ZLn)C(7VژM(`XezeW#xM,56m/*N@!Hf,g F[~i{۱8<=xƒwWN=4}-~jz L[<>rpqО:W1_|5C_4R{ \γYٛ6U(̘9h8xU4ZͿ J[A.3>Z Նr!𞅣iMC b4vTDUpC[J2PImgm|17&ѽ=iߋ~/|\5[JzգY<b@+$͇VtfREuosƉed@a3 `"QLL^EÞԧYNT&X\)R>R l|:;~&F_\7y2(p?^Oǟ%MO/2;C l|`d{FNZC`b}~;WdJ!sN ^,fvX,W}2zW՞m,2Ni湝 3:ywß [$v09;H'Olq3~sx:ݓ[Y # )d v}d8QGs[cBVt5kVowc,a6A!zG9T :dt?Jʎ%4yӤh 3Ұqs}ߠ\=i+MYSn8zvqӧ89j k[ZO'\S rIi-O{lxiGJj{(Ջ\eO.A}Pk 8x=BRWG%s-c1QxPDm܈ 2!~^jTΛyi2WYb8$\A~uo--\Y"} $Bބh:s|;*S|4nЯ7 k/=>rd1Ǒ_q޼4.y 8LhK1T^6BN WZ_5;Jhs 8InpI'Gc0ug9(;-zQt'̚ѷm|Q<NlRJh5|~v5)` k[@nG4C3GMBMwZD !2N76`R|ZL^jX&`YIMX)RV4=:x,MD$ӵmV`5O^o{o~mgLN݅^22T`ψ)Ckt{ b!gOʙm 0uETT4>֚=; k\]_6)Q;F}'8:5ÿVX쥊SŴ;J0# W?fu(H uWVS-ZR!MEs/X3<|-Fݣ~KT{~d;+bs0$ɏO|a#jа*~Qo#8qs0xa"d"A <18ۜl-v`eHG]S|>&~XaiR@'r8 B.{5 E7M{eWͿyl9 +1`p e\c#ypq= *FdSӒyϧz*o*^[q3qc'Mm]qk5YbQ_U:I;~cS~1\*gz']q"Sqw臎=[,rX xˡ*|'$vOZìÞ"Y>H:mBt]M, ~o_(n6vP-o޵aiwOCj>O5ʹ+qdq澇?eЊ^ZvPTjY;o+}o\4F0r98#4m4(G[ĸ Pt=I;Ovht+K[7 ~1r 0= ~5IҢB^]H,Jċy*Il|5SteY|NjS}xߵ mcCyBw! n \+%}C?ĴIm"9(| W뺿6%%ܶRmWrIy 08 [H[ { D4oApq׷WAƵKI=WK}aq xziٽ]m%9-'g `!J+8I9FGZnE^_u{u>gH|BFur:| ـ)t JakdU;kočmG$\0ɨpG y[(آ U2.@cG< rlh 0BF#Q` SOែ*xP͍m0D bS dRpD;r?h]k档'7 a"mBIX;e?jZwx[W#ʊc2ۣܠrrĒI? ޳a7[2Rg\ r_k1X*dתioԥ,NQ_{fYܲ6[Zۀ _~џp5j`,mBH[8ϭ~OLo8~_'"]`u7F A-OK# 23_/[n@%7,t0x؎o0)8s5A64Byc#=8 UdN"T8a)X_Ӛ3]uզS.AA߷ڟNdڑݰsIozx|CY񆪶{BLcFг`PWֵ Cnj7Ԩ/!ag F$*^5ҴiWög ޕ?'*I$~kΥK[տ2Jr}Sv 0@;s߭|KĞ1$|oa?uş|5^MWW,25l&voERFۓO*njAx i%71N@s\cy)I]3ۅ~g(->{ *(d=q9|su9=1I8^'Br~R28y]t'O9Qg>РWv~y{w[~? 7w O7l̡H*N,;͔$I;J Փ~0[GB{t8qq2v[cM" |s1vU 1X$)8۞2tV g 9=;*2giƧ s5T1H*AAI&,)vzv= 鑖 P1=zZ%J ''} zbIJHs͕gq9ϩt%^-lsn3ΈC8;A;;z`W zDEûy 㓌s^m\hH g=?<^ f+-$D`l%H# f~/ ,uE K-jEm2#Dy*8s* ^ƛ.nWDg9BbqA|rC b71z*sv ۦ+{]NVVhX*ye[pc,C=_=)g 6ptե#7u|6ԬML2dL&#9k䜀qnWQO*ѧHX\r?M>o4Nh+!.UfNy;8=g_u -ILmyX!N ۜs_5=Dž/`lPiUB32>c;K0Mxeo,=rFUb98ɷs_G07E5y` ?=‚c={:J tkXF&GNvߣ_E=?]iCGwYnb챮#DK8|#6ĩ1R0!UfN b]Ofl# 2w85nt?Uqeam # IlG\KvqrG_qNx}gGvv9:Wz4x A,Uƕ ?[.Ĺ^~/S"_O4QҶ3A 8$}5B;K?tIGj'u-vԝeqB1|O18܋:.yb$_>;0#MQծ۩|>HM;a.|X YH^sVt8zϋZT-_ ڗ=x04-`ʧ qF{7S%dmhh#87Gb+7x&(~*h nw;Y[]eg@6r95k6?-u_"Q-Ɣ !2K6M1E*ϥYtG1mq5x)HPQcc4=|My%VXr8 $UyPxᶰk<]΋(QCd}prz|Ϟ2B #u|V/OXPTwS6GsS\Be$AzJ;AvvGYH;`,2N?0)#%i8$O8Wʟ+,%eR:bqzk(Is"i&;;k[X|1-@[Larr:vIg8s5ʷɀQH=sNsk0mo_#ʚԾc¹E\'d9LoIuT;0F9898TJ̍#1UNz';2$.Jh{0~Q>uoos #뿎ű[pLgݒ[ ;jB6>b7#g',JI\y;ψ-ѯiKn;%N}ǷOj=#rpr#+nLll즬&.޾gT}? IP՞;|FC ; AfpMrcw6dK# ƃv|mIx_N=Iȹ4_Ly]Q\o_?PC:N ~k_1Xrq_io?|KgZu[mrQsO@c>l[ .{5ONuY,mW)-8bSMv?,+[U9<t jmHUNyP/DF3܎Gb3ý%6ގѳ\ʇ*koxW@tGu"(cڠoݶ21!d$v}8x~"Q[&WUW922[lcjyσ-^ޙukbC!¼aYT ``[o?<3KA@Eڒ} dQ*2Y`%ZNN1^VWi4 7&WQJ=~hmn_sӭ~}|gCGu${arsHӎmnL$I}+{ֿ&-\zGq~-+QOSx-?^[li(pX1ewױiӞk7(ZiFKKõH%ZR]$/>}7©"?AoěXdxyu$5|)3_4E9iq@ܒspMziO潛Bc9`xʫ7\d26>,?uh`#8z(bj\&ٮ˺燩Mhgz}LgP8'99kmR`"+qŋ}p7=q?>1[xOR5+]|ʖUs ss=Ͻ*T*q۽;ힹg=GT ^\e][&d(0 oӴ g랤יO%Nmc!~\tV' xR+ "ɖ-7 B uN=x:Nj"(,ˌ28OB a&OKxi5KK`ovDmB(1{(AEz-pdm8%uHHDpv,cn[w^1Eo!ݒ2OzJ>B^gv6-A.Ւ2G O'cU"1  sv(31iӦ.~O*Ӭvխmv<޽.<?En#PH@]c#,O~j9nr #<Ř;BVGsgݳ}_š-#$nb<}s^ikp,0G|Ҹ-&jhM{8=gmv4h' ##AI܃rܻ$W/iW莊Tm6o7_Vqcvy.Ǎ =~|>Xt_BgpFjP.+ٗC=ӧuw7;07ΠǙ_Vm5fs܇|01|uxv&/--un|汔{!E Jb%?ÑA>ֻ;C^IUy<̠ 77U1\\NP)I8%}B?c 8 l#h^&zKaĻ0}ߘc[))[j:D}ْO tt`@9ȯfϤt)Gپ)NZ7^4&j z cx5tmJ<ފZhTݐrKxS"o-L;BdL(N67c35>81uO k0^ˑ_G֜qݖմqkMwWs903kI}O͐BA*wqZ_M_y~|1LT둕cc_WJ}/pNŖ!bD#Anռ={mYxћynCgvp!@ +. M/m!=U%0Issk揖uOՖ[̉8>{WsD3 /wt+I69^XapֿB& jE b3x 9rZܡ ;#kp[ـ*N`uvHWze822NFOQps0k%gSH]`%aEK>p8א ~CĺSgIAG5lv\FAF0I0cH$:&+>T$Wq栳>~6(zNۮzB4 r 1c:.IdqZR<ړ-›@sp;3rł2>px8ZyCKu'S+)̘=I$8O'5A Q!xxZFvarA--{p?=g߁rF 0I#81ƩUUK _9%H'qϦN+C7pݒQ@ 08W;̞N>| Ҽ)fCNwbI>J)--(1N!1r0F_o'_}Om"7ۀ#=7:bnzF+6yx^xVм=Χ8k`8,{GȌu|>Z+1^L<CŔų?)Ų@!Ӄ<o52kأާ#0sdOo$&+yxo6]W!HMf4<1!b"vF ePֵǚN'򟸑lqVş. )Y'rBI<|/u 5WTA`sI˲)I%'v{{j~1 iG- d-$,2 iCsk&˹@ ʒ;<).vwI rYxyֆmJq  * ;}־ʛq2ONTvm7?"wnc2XC#źϹ[5=׌Ӻ8q|Gu 9v0u*r-ָo-T՞sw/؞9~k3X|iW+("3܌r:e%!X g',BMO/k +k:<?wu18kq)%Sx骺viXbGV~_nSjb7> ZU/p_X\gX`m=r8/XExҴV?Kr{n|+wA2g+'9x'ZFՠ4IbShevWFF=:ԧ)J2\b]*neHԦ?'W*1Kl݆a1mJ3]q9¾@+_VVYښxfQg~xA<FIvcl3.0^Ǯ9?KRerwKӁJS0sMAԂ 3N@cQ8wb!6 x<&і{m%bO g'kDai!]) L|&ȑD '9 *E C+>Q<3 ɮ^c)bAu?zZj+r-O۞\tc89H]+? 8Z}%*;Yw n_ =k4$Ue]PNnOx9e״:g-l sOv1wxNmw[W[?M9|Qht` kZ XBI_x+nS]:E,Rq^N0~|,oVV:/ 8\y}(FG}ݡ=~aC?TTWq魣k^eoz4%̚/5 aIp7g]}{%܃J#xr8#,~> "*pA@f6e$Ufҽ\B9kn?5yIΐw]۱21kڼvo8瞝}x=+[.b-Q6x/,OW3L괹?S3<Ěg,[מC*![DQB ;1ҽWųv{q+=Ս2ۛ[@_c1qu*m gKv30|T+H 3%@@c˂0NL]vKL-@=>bGϟ$KV40ti _MxN~mdt+&7ŤutX\^gtZ;_'Zx.ݰ!зPx0韮=5k. u$<2Z6{z%6q˨hC 1kwX okw$P&NBXF:=yɹ_fj-ۣ꯲n.1.zCbڝVʭ~2&\tO$`:8񮒾%`9'xq^/]oW6$wy"BWl0%ykӼ`#\gqIǧYttu)I:ud8>^wGfnukxo!]s I>A銠#]m焯$U%݆W8h0 q9ڎDVWMP>\0yN#9Qom;]:#,9cD쮓:{*t_F}T%6pqC"&r P0Bֆy .Y 2 @'p$r1e3JO)&=sZQ]^f 7Ef^:pyLjl!bB䏚Y:񂭞{qEU!ژ$c%ڋϾx9H椝R/F ǎIE53"4#$/eE=$,;?ŏF1q!֭_2'yrOoW7|D_e)?ӥxG&M${ظQLgv5'kJ9 F1F145H퐥!G=r:V`Wq j7WZTfE=Q`b[ǡFwE>;7'JSqJm5ZF©˪Yy5\Da H^Q 3QI=h'Nӷ|WnbuRhvfEzr=E2P/.F? ?e[;+k&6챋pp"|U=%vH PEvƟuOĺ%Ϋr3XuQWfУǙkulKi(/=3Vh4Hx{K; Ts }pvj*9jdd QoFA@tǍ1U?9O(㏎ OCo>kmkahฺ9T2IF# u73"G~t^Dk2|i~T?x%ybmI[m<Š(O(q?qVbE1Ұ.&n*m٣,Wz H_N@+_e;hHSN+iSۥƹs[IVyC2|?|Uv-t{nG qNsA lxrLmNV#6جn# ?S\Uj7Y%*|ShUk[[YI{MYT3oּR~"4H}K1n@~xwmcHPr^z3?k(,&n |\څ8I\:1U)? <7J)A24xU\?gߴoí>MwᯈmoZ%l ЗP94--lc^uo؊NJT~Tfqz|_7YVnK+4oHepA+ Ԏia\|YH.Nd~zO?Gu~/Wቅņ O tnS#u6+G -~̟{ѭf/wχ\0qϡ##G{7PkL7*2գ\'=-EhUz?[U.?];z CBz&xYZ3sBh= | Gg> hj2#Mge$hALe U|RHZ+XIMջ5em#̆)R[WMv_&:0Me1h+Fʽ6>SK]4&@?Wsj>x]ۭi)!m$E+hvVGrg%|SxĖ׍|Kԭe x'˅e`@HN=X'38LnnW[/徎K/ 8mW[ܵg{h!db>m|uMoHcp$\+xp s_ӹOPPl,~jQVW 񴺣|.~g_LKU<,Iz|*yb|?ޫ?ٯ$' v[l7-TFO Km]-v>jÄg78_JfBt$֫8E,g?|>>4b6<#9Llִc薿yŪ;_3C<7__QE1a(_mkO Oy}?Xm$oƱ7x,HVݎ?~rk#Fk2L*Tٶ2:1^xK9?Jd:_Ce8FvHLz=SIlu$I&aू/~ i^CoakZ(cs)IH*!67~x.C{G,6 Ql\ӞI_֧JފOG,V'Sm]Sp@+F{ KhW8xNxX_UƗs_>ߟVL<z+c<9r u6 =Avk9]%N;RMItr [xSCAn5?wKZC~"~cKkki";.F>So㷎iZ,G-Փ@mB2Xm 3:_1a2RÒ+4{V|e TtY[f>|A S,݃#88#ЌV"3\WW.$[ `%Ǚo+>Yw>Y0N ׿"xGEx#?5?ozg5BwIcHFڗMs~+R(9?v/]kf<5e\__Me^֨xHWz\y\xOЮt-'g̡pYOJ=Cmx?ZW'c *:J|`Q+鮗m|\*|ʜ#xhrtv-cRǿ + &{#jZǪ!NLש.!kdkW 哟J7#Pnz׵H ƥc;[ 3Ji{ 늵3qwpRM.oṶfߔk'< ֟a˹mA)3 9?C_u'Xo^~Z*E]((Np&"A0q$1mq_b\3xo<+xWK}Fmz Z<30x0Om}YG_ \Lkf1_YRƒ6^昜p4}O>%'č9Ѷٔi7yp/"<'jne6@ [x|~+S#Yrs2MH|sK13^Eڐg[>OYN/ݦ~GׇuO¾, s4?20K?^:f?_~ bja%#P>pZ_|#4m$BG+ɯc[J岮XSלQqӔ<f(ɦ;ݿCo@x/=aK=L-!mf%"a䄢-TN叇Y$l.t23e"f sqo t}y0ABb4<[8U\ϠuN<џ`rRk}O.ڌ  :?~?uj1ړK6?w\oĻOϫzׁ 晁@Yb@daXX\Ro)^Aox F ]Au9K.3WfeV/$d%_~KZ-^ Q<5~'|xIէR-6:mfaH&c/%H]4][>}b8y\ק<şw,<5_oB.&LoX7 X 1l_Aiq0ٮaO '?hXxMh:60i-$ $r&pv|)`CxHd~SιzTr7+oߦwmm(9h)e^/ϓ2H\~Q2^Z+hcb$1b2qC6 k)jyELM HǕ (U@+?~'L~#1VմGJPU[ i  ^wq5O<) F.U{ṯ }=ßK ItO|ƗK!@pr2Gqt5g[ R%̒i[ݗ|$N7zTN[}!&"HQf7SBхc}ྟzռAeokO8[BLQSF3Ny 51Bx8ᔹdz馫M3ug&{ɦx7WYnbHN2q8=Zm~'xcZмCaa5)hbX v~=?ok/|UxolpHMռ2E0^鏽'7K7+m3-qmݸ2ノ+8jV)>{ߗUgaRy/GwۇYO/R\[̷bRb;ftF3ACc?>? |CЛHJ3[k&mCBQ|6yVײd^)|0 Җ8=kKд՛zr(m+'*AZ;sL :[rM6ݿ9k]M$\r/ZA< OH([M!O+RU1ס=uKjGTRA'܁\%y!_qrc:f|I="kpKF XëD_'ncIwI k+QӮbI}r>írZu:ی=3^ ҳW",|8_?fƄJ铵NIx_ZIDUw!OkkM4gXh+~W`]_]mqvZL-Ұ<}}G]U$-\)l Z1|N}um]~ר1ύ?+8##8?W>'M_"b^;l)X'ӋhQgqʾ*>a/k vc%2sQiƠ3Ew?ٳ.?jM:4Bۆc(p57 %YE Y?ν?G-$jXu=ixw߃5F۝Ji, ?)?; )V9.Y[)*TƝ9h3^lULEXjݒ}?3ණOH02Kp?2sWǚn:Wi3OR1Lcҿ?%]NH8+_>k BIE}NGFKTzq_J7PZ3d?s?_\y&},U$&+φaO[ y8)xx^ 6[{eOmr$#h1F`YF0LޤCo M:2v>8ZōZ_]ܛ{ۧy!X^ebw]Ywt$=H+_~gmykj˴^X(U$ss^_{|EY׾7t#S$MNşt&!''r9 x^]"H[9" 8}${)+Ɠz.5WKGxDbH >ŷt möN%}wU_O׆qsJX$gcqW'<]5Y̨trG^q;u_.>C:q<@絏^j.,ŎNӻxWp$;g$p~ק/9#\xQlUe6;9r~֕s\ʹ8ܧ Z#;zO?zׂG+q$Z'?kxnn4ۢ)L WS`U3n&h7?7l)9$z>r2|I8Ur3Ӯ$D}{￳瀐}FvG1ǕW+ٞ#uȦ8~c'zkd!dl1c۱k'vY~\3fK]*"C=A\ ꧙B3yeoeLnW ,>ïJ?~ U?7J\B2Y`w2G1 H[iSV[~AEW˟(㨱k;v02~9W2Tc ڶ㢏O{? b CiNсࠟP߳V~+ML8n% XPzt^JUz+lQ\[$|E^Z~k]&z+y;Fw|_ZWƟZDžAc=Z|:ۂ2<~_oZѥPx;(P#βH DF#޻m{cMV$kn* yk(o*ʫ'$wk?2T)i⒴ZN?x_ ^]c@L SMB?ƽ⇅bEI,t']R9x+C˖hN?:~|4Vvlc.Iq חP\U՟+eӷ7w~=Ԯ| ui<ˍ2rfPUdpr;V_ 9D,|ɤ ,۹ J^V?MVCs`28y5ῂ|/p j py[nIrV FW7Mm ¶wz_ʶ--Ek}Y2Ns,߆+?/~#_|Lo5˜1xsË{_-t_$6&h#'=M~=(q3Wo^F5mNV/]Ośxu j 0CeA6:Vx\`s^x3ĺ ڥVެĴhFAeSa21^xHY![Xfl(OA]JmJm^Ꚗ${{ɂP| {[cG2)Ò_½4o,^'yd$wOL(n)ȣ(8Q$}9)-7_:X9/ZZqio0C. D6fؕ&XoWᦉw E͛t೐v$IV>m<+am/cY$F/t)r.t=wzYU*IGF[v_9ލoí)[CEPഗ'OLlPHP3]5+U$Y6N? v#kS~PG}$W_xJ@s%19qL:%nOVۻo~ّ# I%V銾j`R>^xqa6HZ9#}c^Ow)rIyV>)tቼX0ȹFފw on>/~ٟ BַÌl]}NO5Go-VZو`љ :.X-92w⫯ ]>Vu)"He?%_b>ˍGҼea^<9acR&#Þ:V;q0A@n< z_]&~ȫ9g#cԯ5RoZzf N%G|;:'ӯ ?E{"^^ȟ f B:m>ko[U) UOW,~^:6ƛ9?|.Ueh712o;GxF 9hDT:޻ehUssp-;r*Okv[ڻJ\Fo԰-sY>֊i;࿁5oYnl8?rC1'xd@ЮWS?v{[En,ѢB2<`$c?_xR,|1evejr|7O&f,I`I3>~̿:4s+8>SQ3rG< gʩJxc{C]9M̃6UVVRoh;j~_>V)ش0jEy\ۼTI2E.m-^S=CggM~4oB]|c8~1'4x*nZE&o({ҚGyON c9II5. jI.6@$D)D1p2AOƥ,$$ܺj{^>g|E~5kѴx"9H!USh$k/><;&jwjo68HǪIg5LN'o7kOy= PELj~!~_/\h![8"`apsW|?4߈ 4sfcTbFdӌs"?ZƯzki8o'Ơ6F:ď957/?K߇mCE"X"A P$ dmہM)ӧNg8lF"Kmo_~IF5 wozj0+ (?ouR2^|zmGX2FyGʿ1u©+UH? >Γ 7v[5q"^8 xzYv96|fU8;(Տ?(-Բx~yԸ͡#>H_Ed~~F +5b\t!;_jԸ[ φgqle~4Xg.~2YI 갤jL6LR }9WGooʽ2c M SfMm `OS8\= _t$;mgh>\;+t?%?m؋Ak'4O|1K0Jm|HAirC)xu6Ѿ O(Nw=H^߇?E-|a+#en]_zls_Oß񿄧o1J0R9WWecM>*=ZKE zLo?~(7int9d)q\Ps:8siOGo'$ejۻ]@4>ݢgW:l=rS;k K+J(}:?Ǩ.Zwu1^_bF>1~?cc'k^v>yrI_ M39'?/jhPxR{F&p <Ũ~wl-a=f;7tgn+xVY%nVv%$8qrTq!W:򍝯no+ؾ *$HkQ5)B@ʌqtxgU杫\h%ͣn_yR ~/> OtM5k-o@o +XHOqO:Ɵ W}l8䀭rɨTh+%+]N{GUQkRs5ndʺOĻo*R?kڼI*]_R:fF8( 'G'#P<zX`Fs'xGߴ/m"K{IJ=Ɩ-xЍ۱nq0O_ymh3]Py=,7 WHa(}o_ Vq*swJ+'E#:'rr&{Њ?yɵǟ .4 7BdNh79؏uo ~7-눋[E$r\D!!!A;Q[Ҿ![##(yB26*NrI9$ WjR=׮Ijr:_?,wz5v;A V,Nab)/{NfvMB)v9h**RjΤO/Z=2|O_Imz{s\{`pk0a,2WWo|5˜%b_Mώ>x~M>4xX4AcN2:3_aP,W'r:Mw6crlމ9ʜ]m |Gi.#`p u_}FVIE-$lC]aHm*A6F+^$ΔOTf5ѮMO*uXg w8Oe9ZT7ݍkw@1.Nuu/f?Yù8_cWQ_fy(cYcLG漲bʿJ?࣡X41J/,0⊭bd?$~T94߯6FO\s {W; ϞKhNGlkc_1_jbMxB`xUn\O2ySOWY (u($`w̫gƘ6 V9n+>+IR/[ E9 '= zi"1?Zm2~亐p}GҖ"}KfCҦ|SyKwt;^ t"HrUۏJt[UC M}1^?jk^)nfy&ĜgA: fUJ[c'9tN:6עo/O]jWvsאNH^ݣ|k= O5cr^+.MHLwf+R= ƾ?*I6iE^O&3HB[ȹdq3'1{%$=0{n~b.c\ LJe$CןOC^d3R\t{߰g~E~5Oؿς p?Ӡo__> Ĉ,a1;.O5v|OG/!VU7[F!I%As(p~I5Fޓ^i`ⳬU*1签y^Z]7ٳ篏? H<=2 0V`BO~2|#uwj/)*d8I"L6r[9=Zioh\oy>rAPblˁ=A co\#Z&St#HG 3&|D=ZWW*/O7{i{}~QV𳩇aҗ.%8>Wգ?ؗUiOz+n-okg ?%@0ĿLc6X$RG cMV[3R3>ꏼ>7^>&K88XIEi/hh6(/DV&ʑ=w$$#Tj)&euwǓKN5jT*2nܭ-=t:t | WZb ?Y4$61 JJC 䅎5<'o|>2xjZyR;YDW.."R_ "\0$(Iv[ew*!9E,Hǘ w *xl'Nnmlעݟ4e;'έ澒m~?f|5gĹ;x;ŖH$eti1 D6 g:\_7sH!7i]iwlU@ $rM!_OM~,7sGE&W T ?g |>V/⸰} 0oap)~ĕ,5Ei5m"WM:ui4bz|ܕqmH_+O֊xM[ Gs@8i~7xCImI)_ UX!.r1~/:[ m2#{ne* e^|a s4Zhm9r]'T;Lx0ýw~IaV$8]UxvpxwĞeK6/ 6$2RQnF?Iߵ7wTKK3V6r7`3ߊSS |>h^ m8<"C6@FIl$gχW|c QܳXYM|?<>~Ke^ CK?v Mo϶v7J#֦"8PT*ӷz Km 5`} ?}_xc.~G7G2QE~|i(n|YWۿZx!7N=zz3WJ$0t >^V.>3ksliϦkNJ|s=kl{.GAo\^bUGX<&eVPu7KeϊtlvM(w>=ZD d5MIRTg:Wj_+j_[X"]GUE-ܚ;Ŀw,]_Sߌe/ |Su 9߂íj)-/T'.L^ (:W}6 kCMGu27}_O߃%]23Bиzt_փ~xGM~.2E֧vtL9)8+D 1}^o+:tJ[irDaxbwH cWm4N}4ӲQZ3׎w4ZkD"e%^;xf~m`^zNj8nJ'O{8=+_O|J"m8Z 4*:dy5xqa ;#NQ|\IZ=PomqZdo!hw[]&(ƽX ;?vivVK}.{~lx#5-/+Y+gm17ahVv3:M=m;=4c?w;=Hj[ܠ+) ʨ;@'x\f?~͟R^;oƿ:ƕ<-l B.cT蜓|)?.GiA?@9$u&o [ė7֚g-+A&E24Ys-_Uͱ?]N\>{i˭k[w2g V$^"^Ԇw(a${&ú~%{WvjOۇ fXr6+?:|-]ï2xs;BK406-}DJo6Lܼ9;)Ǡ82H`ڹl{kY7Nb4xLZ+?૟)˲3\t5ko$w:NxZYarX4džUL0r0qzxk_4g5hP!1U~na`G_W-.6?3i?/m1#:_[^ἒY} S\ Ip- l j[*Sª3诪jw彵OƲl'o_|U,uZGzȱ, ky2B f=}qt'x-AWI?A<g5/3N`<_9@d0ة*v9zdUo4feo10@{5+:8u$wmi_Sj)f' )&V믩|"AiZ vP z}O\9mtԳbO,==+3HŸ":]R' `~C_B:|~;:r;OG4`.UzҾn񆑜^b~WN:_?aQ_(~̟2пd-:K-dM_ l#n,}W9"?j+[z ^x:}`圀yH}J+r/hF*+7w}d'b2z5fN/D9_ ߎzlj -4((yyxW{-.LOG1WWϱc(:F[kV::4+߱ _wqKU%y] E6> gFE~eWSwn_z#l?8\.YRa\J)ڱk?_M? C^,fCx F״lt Xdn:#>͊h+ax:T֥>ӷ9ѩdtރ +_9}zNNf#8sexⰑkQJZE{H9NpJzz:O#ľl/q<̃m2 ~QYe}wm7ǟH#)E4R^8~~7mM2`y6)j ~~7Z}:* ddF_ # w[ ᣅڌZjֽkkc 1yv*xriv굺?Oٷ 17ᶻ'~ Rks<f~b];r~_#k6 j:ԶdOZ팂T/Q=zϗpV (Μ]WJ?V]6cxSKYo&}mY+ k+g p #o![ $x\~Q^o.mkalֵ? >>Go-k aPut  >>x2M-#ߺ<@8J'`~WgY# CյM_O˸mӵF_#0@vu86O"'ھ㢼xYND|un$i)u;5XaY[ΌD1vOZZ+&KJtMI4$ 6*$U-;ð+$(((((((((((((((((PK1Gm?OpXpX3Data/mt-1D92F908-FFE8-436B-8459-224D94590240-76.jpgJFIFHHLExifMM*i 8Photoshop 3.08BIM8BIM%ُ B~ " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzC C   ?(((rv})k5jȇcC}$1b˔W->x1MT]?4?ސW{˫o&s\%[vlH#g8^BlUS}ip;of{}ErWP4<%E FczPђ84hQTM1^/#ۻ֋Mnum9 ϵO0._+V?e&?t 8''S;БE~paO>\i.ŗ85xCDw4G!ۛX<} jn ےHO*_G37eEh=7 1yZ7kf駂b׺gdE޿y>|=i{,4~r:-⿕O&|{:^Zt .^($RF2 D 77ְÁeIZO )G=8OQ7k^ TQ0KpxUz3I'^e7`inBW s2~пmgsoY fſmx]$r3kSs6뷩 8PzsN3G*5Wwu7ޑz?|Y0h/L$}N=z+u'BP1+#-mA5o LIW s`U *@2bX匷+!ˡNjnQgY*r%GM5VhoC^wE49),ǘ#R+Tbk5Rax4BU 4,tc G?Z_Ý RO)\]l| 6ӝIu5) mc {4+tm!`|@>j+6r׭Gnϛn I$/BW7Da җ򴊿 m,b+zC0Q;>дvG襌[W~CiKI>=^(c`((( 2F>bMU$_297Man_MF!C=3M&-D+OQv|5}.}E,k(_|`ZtMi6$lp'`2U_qSԵOV(_ "晈…8k7 >vwZzt[°̷Yk_# ii 6O?`qL/X\3Q[=mj_.>x{] fm:"yY"wکmfl`9>6ҭ-o @v[{d`.A,}?|E/GNj~?x^ygI0N{¿^%<XQa@P`B Cִ!|Ѫ>yz⾋40/Voyl"[ΧBVpmugZ心υbIeMCIӵ{YE՞-rU *]e3X=gPcY =W'ۚ)g߁ ?k?GhI.3EM2vsIs4&I$d\Hہ_o[}Pmq$zT d ҿ3 \~^v^׿}9ab">K>~={ Q3 F7F#3O ZD֒D[yᣔӺ#)I=x:|A}!z}K۽cx<:ύPף[f>dQ"L|32eY-旧= | *PS&V4xG11KOᖡO#Y7$\|I+HKiң9ڥyO!uZJ ,z$;(X&yf`}`{{VI֎ wZt?1[ I(?KV~>Tmm2>2$}yR@/~?]WoS24B.;eA6`t!$_P[Z𽿇F!Ѭf"i0̮TWEzc,+S*r?x^)E7>#|#PUA?c_xo~O${&8`נ~R_4wí^)nl([iw,nlskv2C:$SWR9<`׋pY?iOuUUϱ{U4{?ßwEܧ;ftb6|Wf2V|NՉvJ6COm A^~k J֝֩]N+Q 4@|8}E@_8)ݧӢ $$\"*Zj:mrz_Aj_muSOΊ(O(((g,&e\+翈7=EqnBnu pWjR,ˤZ互Px'#(ilRSI M+OV$ּ=ϚJI=mwҕj4kE~7DZP^J6xU{krUFy#3|(2φ{f,w5v!Iګ P .žҮ5#u)Le8iYNҡ~n_>SFX|=gA$g{6F3']ԼJ7$yQ.wC$H8mF%T+5+~M(vcWeͮb8aKOH m[xnKh}Đli\N2&;eIS ctMoO_&,Ê8JS{:S;DsCj׿G| ~_#]x6^oĊ鲼?:{wļ K~>K=[ jmC.F]KxG5dF~GB_BQ;/eXkbMHd؛c&:ԷH?<_A%o"d! 1*w4:~U\K gx,Nui_}şV}Y=|"W|'nvr(X.Uߟ?dUlt+MQn\b8y'0?A_ݯ; 9hW~=F.# !O; Ҥ*+C13+yʦ*>8}߄.Sp-J?|_"ɩ^h4HNdl #Y־|18meػH|5m&?pĸ^Q3i0TWY`q ú=zUxc>[llA\F.5Ɵn{&?-p*zUɅ!Vg00lh 5] 6dSyf"U2ܽ+nNj3uRA/C}ƼĿqZK eqvݹ`:}GQS./n7iڷ|4pLw|I1ᲀ~Q|K]Ra18=Uպg'> 9[赯s֚k[C>jqis+ϓ (?(([·xF/&,2?vqc<>1Vqjo dt,l>a89şj~?[Ѵ-_TјMԩ=e?"p}vMF_ImnؔD ϐucl'.Xfl:7U!utV'{[T`fi)I%I=]?k:x{ڽ:=>|"2>Gnp3Yƾ(<3oa/ /mdT$dRAw@_7~\> u+=xWu|E>ij%XQ+D_Iq,~.cy67F5p0ך^e^nv3 oxzQL2YF$g@#!鞵I~ّ%Ɠkom-r:[Ac{b w$>( x>ß 몞;z=ۣpA1"T*e)Y_M4>/aS9w&ֻk璘O~v-J;g9g TAy߈/A47 NY"Y1ǖ_K]J+WXv;[>6UpcNQ-om?\iغ5KkqFT+&u_#xKgnI$gd~$G~?S?{|Vn-{ٖ(Ui9B&~UV\ Fn Ǘ#FDJGc~i9`PT+j6W5,dg*_*Em5ȽG qiw׈,Ekg+e|0d ݁ebV7jgӵ5"{$:sio?8.j71Kqh ,0=A:r;N>;||?t}N$3 >l򫃜=zOFJ0rvӵyR feϚJ~?k/ٖI]3}1ڟYχxh-mYe]c ,O<{c5[5֎c6\I|,=Wuc~!MZ[ <0v8唨 w5q߈{FW徊Ϸ۰\ g!GkYx'K]QO F9ngC EeϕFr?$~O.tGS~BgLDumGq?-&lJ<Y'Flٛ6|/(l3v dFs^'勭ܖgl:WW\$(G8a:ӼYa0Fc/~7X_|Dpݹ{nw K>8#րH$'a/P֧ibhwtzmZA8''j'^qSO'$(IQ} Y˽#еEWٞXQE((5>/_~(~97k/m|_j f73&8%">ۛ աKWpwyE s=*t ϸ?33Jxg=Gsf:f͉Z(t>_׵̫hXsW-Wﮭ*Uk`!ɇ_um6IZbះeޏqB 1(hx[m ,w3JEJ@:=k~Zk.NAdgvs1S,l~¼B&@d;|+Y<7KY 52$U*I9W9!_W_[i*iN0ѹ*TG8s/ _xii(I.cld ?< ைmCZ TK6r _@8\Y[Vo]<#|ϖ]:;']_uk_ ̅?9]oKLۑ.{(M#O Č~(yHFہ_ YQ>-ĐjB_Ǟ_h]jKmJ '&H.* *?O.5)_G-]ŗѡG9N.V䕔ǫIj.?h>':OosjWLncEtCB47Nk}JҬ>-R1 w>tOx.UF{8n@tL}kO{g|[e[&!"(s?|wqUWiZVKI~e\90V򔜥k-mnG7kwEm'O0;p >,|qoc bp7oRVtH |~7K*xZG*̻'[є rWv^-e@LWe?C3U.dv]?nv,}_w>To[Kk̮{[ :q7RGZEDϞNh>¿MpJZDe$r>D7Sx}ku;}!?ysWpgC ʲ(-뭽V~gCG 5߲z,L *;Obhl4X 〭H=0bٗ_πoOKbny y_Z UGEYG@~M)b֑//?<̰ʝOxجnH䎿<b]`K@OּO3[O8~ ̠\rT7=gF[?_v"VM``Q{Ó^פ8Ig z򣯽|g3ށ;|>9>_qG~{3YEWg̅Q@((l/񷊵}NVS`VgUqJMgsCյm-ygXXp@שɿ ?_ k >7C\F*{ֽ'd%%ޠrvMlIWC[#^1ø|\# nkg3X`2˪{Jci,Z}?C[](A炭8=`Эn|F&"P~`zDW9&ecqqb;€> g5(?㾅6᯲x~Zɜb(ie#ҿB~ :<7u|VVF{@b&h!¨q_ P}ڊmd޺#`%*yqm}ݴJZJK)]Qmy] H$vǒ}:|9M{5mN;0*$̌|&@Jz^"ZMZ$mUafG޵*xZ^/6Y{bx$LVV Q 9Urғn{JrI8ڽ3Ǚߢ_zOu<28c Q nk0M60_jse]o|t6#Rt u6I'ȄqOye^4얯\珨|nW-%r紌Z%g+ f׿Ŀ_ .qcjM3ejO*+HmV'\-KqSr;Wg?ڏ@ٍo pA^㺜nod̤4m;q48l<^^o{kdi';y-[ʺnFqB0epTA+ixL=n.ƛ:!.n چʻ|2!6XjM.msݦOCA]_ l,`i aYjҕeuc iapTJ/%fﭤLS'P] )4ad:AW[eki* U%ps|Nk9cӥD?hIXv' %唷<{/~oâj;8<2zzzkkM(# 0l$9!Gt? t̳iiGjqwV,Z8Pm/#t hE<|yOŴdS1.?*/#b $q:gwنY@F7(Q޹QͱSr:{KmF u˻H[,:p\wAq8)`0@8=\9}]աuJU@sԠ<]%Osׯ5$rwOlkh b >Hh;!z 8;YzdLo$Pj7BʡJh⾔{CNS%绻s,12xtW\_|:x^g&v#"N"uSZdU| _,6~ e |59M;_ >hj8-=—V>?fIO[hx w?*a0:5Mn% nQq_^!5MNSSNLD&D=+̯,6j14-ݵWZ-f?jޯuu=_ lY6N1 3~8<`)~ϾΥ,J'o󝤎s N9A>W|K9oyEZPxN^~YR}ۣ~Cx ~ l,,CP= xE񍎯kZE/٭<Ѐ<' Jǚ=M 1Ť0 6D1a㧒ᦋ HY5=́6.C'$s&<5J¯ivgtk]O0\OR8j؉rϭ3?g?<; úF]HO*2r$~xSjG;G 08~+~wfF\ye~{BTF#iFG(TO@}.g9]}g:-NIۍKq"@v ޘaibzeU3c#Out8UOB#5i$6ʲ'vo2M#{vQh{3) ?ştjP;(B(((h$6h~=<z yw,^X0g x?:}Qi+^-XW|VU9ݶ_t~5ʜi(B%iۧ#o)ZT$[FkMCN,Y/0 }q I5 /C?e/ ym棨h_%Kp>US` hO _BZte%"t﫻d_40NY[_\Oj>f~xAalfmť;;ww>+XO3a7vNMЧoEx\GlY=;5} q+*VӃMRGw uZ7A%:/v Ԏp9Fw|h'@XNg:Ah{W;5(g.[8׺ѥtlż1x%?z-'u·_MPgcrGؙf2s i,Cb+EGa`vg诩pna)5vִTڲjɷeSM!d$^X!>vbAB?i= #q_k& ~hd3Y$c&{Is;Gw絥_ϯ^_a/h~Fh]2K@6!q\ >)h ]h55p&Fh*IU_iQ7A(?$:vx$ZOKŧqŕM?x&JʭO?~gS#:6ԙbFg׵TĉmTrfp2s_tQZ/rtj} ^1q[ℍ妒>X=_?g?w/쥝t>G*qoj"^e@$~Fn9ҿU>iڦBu]:dT8`FA 5Q_sRwVߢG llcJݯl( (?((+ *AϠ:Ŀh3ۄ/%]wafIo/hn+;+??'8?Y# fb$ⱪ:_sJkUm%OV?jks+Q'ş -S4xSu{JXi`HPdVvW >Աd]V +K R!\y%VBI$ɯo"-1| g7txg]'{-r+kk˥o + իD\ȫm\.mu"vܒߺ$@~:X?`h9FOWMb$tFK E#e e# )-Ŀlti/7X`vG-㟆^u; Y^^]ZS\>[Xdee't# 5ލk\2Z{촲JM84c̷yW2Wwew+G/[Ɵ"<+vm[k:ҺFmKEe; AcΫi==ºޛ+x4k_I"s Q$ą]A t? xO\j'| kO,? c~mm }mm2y6Vg5O~Ǻ>Ys 2DFG䄢4eBҝRjqntU(64EFNMIߪҷ2}i-߲p)i xH#@񖁨xwPe]B B{o7dLfPno-ƿSǿk>6yu=tKw[NW_]Tǽq_/n_mrs{i(ī(?aä$ĬiXƤKyץg%6 .Z[e<}sWJd?أz/v^'U׺a_jwڧq {@P#Ga,Me> :}o|t|. C߅ |us4(㽑4Z8*yѶ 8>I7:uU~׭psyKKuqzE|MGo!g_ZxCzz. 6EԶlDdfX_?i>>xfxŶwڽ:rd;_1!"6baq_̿WhMi_|kg 1Fvs] =GKDPY\,RELjA>Dy wOi57×2'sHncOU11Mo.RܻӧOnR]ZٵnyA{Dնo1{k=/5Lc_&^V?_'p|DwO|%igDAK5PG!0 1_|g)e|>%|7OGO5bq5ogy=6vCer2F (W?~,ڽOk<&TV1xOTJ6n1ёOP+ R$q^97ݖ+=3Z7*/]]N_P߀??M6$׋!ZHm/̂m)x`.ϿZ~~<[#Xu}(A,f71OCѰPFA4J8sWca,qx|Stg8=?/hn+;+??'8?Y# fb$ʞrU7|֢))\ ⠪/>5doǺקi~[ܽS'>ht$Ƙd'_ݕܶ}g58SU%~mlXy?(7ޏ~['߳?e[ Cд)-P4\ėZ0gƒ}w/$ڋH,`he5sW!渝€89Gg=Z]oxV[GsjZ|VG0X|cxdwʉD9ƿ ~ i_M/iMRx;~uBDNO |@t.'-P4ķZjcI pT>_,_P_x/Mu&dwکе;M*X$k)/^d[.cg-Z]oxVSGsjZ|6G0X|cxdwʉD9xx[ÞBՔV1h_N"\y7W4ܼʼn?Atߏ5Hu4i$+AEPEP((+>-;S|6=ƾ9fҵ }JI!mG$LrSK{I|9i?6-Jt,l%Aqmq"cWHC# ]//yO)Z8UK8&=SMg|9{j:uy[b]6Y {WK[[DTݐAߏ?Rz_|=2xMԢC,+s7*JL׺QJ~Rv 7>_<5xm*-%&,Kf2!% .77/k)|ŪZ[K$ʊe–랙P|Oi'_5=?Ƒe h\P0\y!4J4.". DyR&얿rNj1WoX~86ߍtOᥟÍw·Rt -cs;W)NI_~_쯠^x[hj3 itw$mA#C6H+v>Om@k:ޙ򲛉&WIwkh]nƗyĒ+_^'=ijWp]YcG$Ьe65HFpy)M)=KUMRot[-U/mčy_A lJC(uy?~GZΑ᫭V "nz͵B 3‘DeC?|+?k1ce/O\t1^;_~iúg9K/Xu0:oShR,Aeٛ[o95|=,59Dx{LcFy8Č-տg^9 ~Ժem1 o 潞*.uijá?eٛ\/75=,5IDteQ^e1#Al8Wxe;6Ѭ|=iQ,6+KKhH`R8~UP+ɽJ ) ((((((((G1?ƚuP)qmq k,RGF #/h~m+SOʴ*:Cl21FHmvw@yo4)1O wmK$p w+e*ZKY-*\2O<5;žEzu嵅SYĬ" hDwTE!UY1ϪQE7}ϞM(~/u]Z5Moy PM x v*|-h2,2cMY HXD"<}EvV_նw{%}S.eŸ,b_>eȿ2ṯ?}/i5kEcK U64/ /晧뺪5kHbEe;0?cbRAERQEQEQEQEQE(((((((((((((((((PK1GMJSJS3Data/mt-DA150A6E-6AB1-416D-A055-09ACD9E13F6F-81.jpgJFIFHHLExifMM*i 8Photoshop 3.08BIM8BIM%ُ B~ " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzC C   ?(((((((((((((((((((+/W_ z  $cC$4 *&+ ߲w ïH%;JiF?o[kQ_E?k+O}|֣Ks,H% 71MϙJNϳ%dFqKuOz+?ƺvƾ(MCZotoM]Au+"n$eL@(W.*o)#š<1AT|RmZۧIkVÞj6&i6?j|Ax[K\=e Q%ԫ J]rnbdHkflY?lvn_޹J^j|7Y^Y\WPchVm5q 1OMd4ƷGTm+imEnu%ϹaE~EPߏ?kG/-zޭa6=I6(hY$g^WE FZ]˛O O7 4ko|CNY]%jVhVwpڬIl$F'y\=v^_/[;^Pwn_}?a[_c +>xE<-_k^8үn_I[iks$A15 T_>+~?c˭+_o5Ui$fGĢ mHdΌ\ڵtkk;M7R$ͨwխ7WM>袿j+gOG/ |2__|uiD:[ˮI4yUËY|_-# .–`y_/)wGog Ʃ.4Z[œ\-%xN8L1nʈ۲BjTE^m%ԣinƚq(~IkEsOÞҤ|W[i1qw*C!TWa~-c ׆]yR{M/i"^_z^Lsυ/F?:DO! qCOB%Ə5{uҼI6Ck[ĐJ@J1\:_ W *ͬjiM /RHRg i%n87,M^NJnZH'[|Iîxv +Ŵ,R.qt%Xdc OۧeÿPOzGm Y!ϪzGOeHx匱 0ߝoٓ s!~ο7zUտY?tk-6WRu;*c HF#5hI[n查ﲻm%rbmv'oFQ_?nڧ¿Ɠ@/Ko!qZi[[Qom,99c,C)L7%RCx=:]Zܬ , *n Q\k^7kV붢{9>/W_tQEdEPEP((+ ?|<[FVsgMյ'k^I E7R5EgRqi/J_IYE%(Iw5~O儺]j?u{K8 īUX=ۥT@X+ ;_{%+Ś5nǂ|3y+ҵmNCwdyMcn8hWtӺumMY6vOM}j0yS|'E7~(~+|A+=7l:)5ۈmo6~|iwGb[;Q^S1\'}_>zN=z>W&5a ƍ#@ΪNXE_JsqkjZwkn%Ƣn3OZއ?-_~}3gb;YZRd[$TF6`ΨA qS O?& Cdti.KmOcH\QI+ʊ M/.ov)߄TK_1dU'ýsF/[xVV4Af l$ҘFUbþ,xG[^ }¾'iW &-Co],7m 3\:&*j'5Bo(,բjwwJc2K( Vl$}gB P[w^*zkM$KJJ'K_q}vI"3_?gVZnynniĺ ]vvx!,>c5ω$~U-|sǞ)wƯxTk _ k>6)n-.aݤqH_&ԓ[Y^%]' ~?| >*|G5k~;xJx`Gxl%FXl׍;i#942mڿ?/_Z_g ^Y ºRJRDB:%{E*-M| f0So'r?",~Ij?[ڀ(MkAGI ܕC%bʄ3 u@վxO^ׇ~#x+^3jړizݵil$"wtS_Sv6%:jI|q*4($v:bC.Htckq ׷~2wVg۳t{oLxGM j~h'Ļ? [x{mRXm5vׅH'2pW];vRVf$iu"'Zkt~qirZ5'I?)'Ǐ|8w>Ϛw/%|gxz}o\iiuᶁ[moKr|cX~_Qc$5 x?𖟦'Moi$]}s)iiצ Ine)1. h߅K߂~(hau;y-nmA2RPG~QU KwvJRwedޗ(AEPEP((S>nUM4jr r2wZ[^<0 0$]ܘ V8B+|;~Ӟ}.K y:@E /l 6&m%Q;y 2~02ȢEr̆P+0R ?*,Hk்)AEH 8 +?O:ڷwjr=/0drI%Vl+WBIks_-^IWxs$X\ef/~w4&1]#RT*H#!^(햛U'~8| :آA 00{Dw(Ԥ%x\9xu3 &.U͏(Has(+GhO|c־~~UgLJ!b4`'xAR]+<JW'Q~~^L~!m-0e׎x/]Οnڐ\4jeL n_^tpcln3O?bھP`{E# EYJ-nhŠ((+cMnbLj.$2h  ڹ-u'~ޯIƑKU ;{/9.]ْ@!c#4( j=FVk?= 0ضiuV8 D]|çY@|iW^5yM4+hr\Z&iIR^t^cxC<9:i ߗmm&y:ڬV^ef%cB骚PWg$_iĖϩ&ҟ*S|;}q% hlHtV%xe8՗rD0Tcj?hFx`}'Tk-ZDNg%xSt#Pk}N->g]wəf4ʈt"'rޅ絿RHZ8 :κimGfΎʖ?hb]"?tϏZl o^@bEy貭8r@Yǿ'O;m]]#7e/:9"&GlD\E'u0]Z]2AWʶHRgi ,mR"#↻F3W? tG$76.|ĸ=+A&K%/&ix[5mn)=RQ=֚kAkIi >XEޥס45+? wyuIc k%)VK ܺ`{v2R4uxU 촋P,kq u$alڷ? hkލpj.'m$_Yj{Z6B(x?Zrn?24>T%uṣ576 Y DOҵo ߉,bL n@VVO@u&+a-0޾ 줺7r]xcⷉD @R@xs~-ho^/"MI@L-(N+gGߍ(|Qss$~_nkO|𷊾=xc> vPJ0v< u?JSJj:/[)U)I??>Xg.֗%||SC=Mj: b|v/OoyrHew" .8Ԗ9<pzWwv ǀʚE#j7h"mhDLȸSo7Tе;m>eeV5+a!72]:~C?;aig릉n5IT}SQ̀T_~>+ZFַ7Cϻqzx"`H~m6~Q_ ZYXkZG4 ksèXh%F8?=¬X:/h?Ǎ#4];['9n-Ғ̍>E +3U BH34=;wsXRj/D68%vKk]]ŋ!xQrY>^h^k+o#Smeo\cLe'*q ++Ayh uZ\>w_4 3Il#[V%#d, W>1xwzy!ODa!ɉR:#er[^Igy QeeaO_ ?3iWF+Kˈ_\8vL[6S/mj.n?]ัuIySXSmcgRBXn+Ⱦ |MԾ/x.__i Dڎgmo4 V7Ry]baMrh 7>4o |3Ƙ$hXv!- /88=N$o<(y^A4n3ߵ?4~i?nCK8`I❦dI 'qbkbK m쬤ԀH\JXlAZe'"K;~Lx*Ælc}<]_|z,_HamSGS)T,:|z^--a2,dlɴ'57?wEw^6AX+[ g~kѼv[1bͶR!M~{ƹRpNK]-xcX׎"q^^/#jJ%/x")+һe2~^]o /W[ 9-rnU;DdRWRȋS ksoeoʃ?6GM/}Z?{8EQ+/_ xŴ2f#xX)BIǁfa)_ǚ:VIh#p|R3O9}Y_$SÙ&3D8>՝㝮GyY m'w߲{ʽ޷j?9?i/'.AX۽蕈#vt8x"xPKs,]r1W ?k_ "09=I}J~N?/#=/ƾ hrl놧rߕyt/ߚw^/ᕷFWWaǻ H=[ Ok0V io*8Hzdy~{0Kg1(m?D(J$n8RCg 5{-Vl|,.E>|bh ! G> u,-2?* (#х )W`8c|kZƝwZѥKJaa4D%KDfv/gn!9U+>.䶑rTe1HcKgfN<9[)t;#U3ݜa?g{y⹇~Y ,l4\|c-}{-mSF5+eH$),13[,!rm9!sي3xF0A\7*φ_E3vH~ԅë6@Nsqћ=4"+P<AUn>o`h$xC#F HVЊE7j@<cS(==hSM |( 1 }~I~i-Kw!'"6 ,{Wɪݿ'E_|-Z K- 49U8q^oCğkF0!H$jzONkOt-=/m[ IA1ZxV;Z.yYN#`Bcܘާ,*HS(rӋtZ?C0j{I%mko|KI6vWݟä쌜=H8Ӛd>/T\'<@dk.x`2@Tqiqڿn)wA!QXud.׽|kj'ŝzksnmcDD䁞> 5uw?^Hӕi[94 GKďRR8cr=Ԑx&7Y3|Jz-&k\X\PZFTҨIlҾׄK-7hmK=g*T]GNӦ޽_ ? -sOmW~;ou]Qbz0ZY[)H ^-+M ټO9"=| pInp3^yCk\b;ћ5>–MmZnrjv_Ib%Ϝj?ϮĉF62$|+?C7A8z|/L'moC_?/Oz>RGCt?z̪SqOF[<\7{yď '$kd? _%-|@ +}zZƿ¿VĂ((O~%ޗ3:ϋh-;ٖ&ԧIb1tʨs>"|Nռ]#f׵Zaxm ILn"yOZ&Ik6i .mh3* c, ̡ FpMp=I௉7wzdsmq7l9|vW#(npǦHu Ւ5?2E<͵٦.\XYeEhlm h5=BKu. RIlnx/ |4+ht^/c+ DPTfe- 5[(Y !#YDR@%G@D1n›o E%ZfY z4Es>$Y+QQ^{4j٘6xFFA_IxvّAOLb xaj7Nz}l8N5bO힓ㆊ}8*Gzi rLit[w-[ dZhŽ X9*u u95m27_n%զ23[ ,\"c:f<2|+3Sz$}| S=LF /dj}8íE$w K~_k,Wh.川e[|؍Bvܫ ֐v t Lrv0ᶜ_:hl/nLb RX3J.:gxc/_hwilqsEgl`s<)̔ʓ@75;+?ihEq} QI3[]$ήWp3ekvg6y&pswKn9ѣ<_U,ʚ=Zu.F2Z[4., ],;G#G2[zgD|S[MZhOmx؋pto5#I7%}OLqMJ] t-P a-# ^0B9iOUK [3  lDnDLq+c85t5]rP5+k@j:t?d0M#ٽki'G0VQQXLgW|Ix#eA$2-|'f}T |A[᷄uNj &d(o=8bGRHMaijqլ]}cby xim攇e"4w# \W~1>%Եo|+/oHq `Vg9;YLuC^t߰)=[Ú"׉5O؛#s[T dVBnQ5.*x2$_kM;Mmj[=`]_$O<V@|=Egt㇩VW^n~o#ȩxtⷽvg;h@F Q1Zy>n* YɼqԮܨSʱv_9F5fXYϨ?R?ʽ'W㸅0O^ji{Kp ?GOCߍ0ђ9HlaNɯik-ʏߍ{*2As&su>?xv}=Rў#ii37e+_YTPAYQϖ'kGDyiq͝&ԔC0l<?Qm^*$W#Z0Oǟ>xJT8 v\9G˹{J躩eahP+Ҡ ذ ~GPr\:*w8bq@m<X^6:zh`q$l|#97xzPiuI<}CW+{]7K- Iv)Y zWx_h?|]k]SK$>KI+26l:[|QKmq}t{ō!_4d@T;WI|~(WjVٴttqN2mrk|2a]USO{KKu]9}4|2^møjZRr:֟3폂~9-w3z0j$Py{/AҿqᗋAxI:;+<,)M* g ޿PgjU#MA._՟ ҩRu*9jAEWX(+_}8^h7nIM1Ml19:̭I6GU/3~<ִ%Hted]NLȖ3Iv:C<`t7g5-[_Q0æA/ϩMdr u "oBE~7yo4eKdvĿ`C}i5EA6Roh a?h$Hw+krUf[*ú KxҴwPz\=4Ne#/Eo샫x7~8 hU@KoZt,Kߵ^_Я>a%ƹ};{;i`ki"{{]#$3D9/گ=V6_HMI ’ nY"95}WD՛Ɛ$KBL$hF>RP C𥏃#m+U 9Vt6Rܠ4׳.Y-_-J _H&`ˤmկWޞ Egh푭XǨi7aeF$?g+Nlu1so6YHu=]E 4HdJ 2_ ]xYlu]^W܋V{4ѽ6i7g;J(TU%w%K=^£TgK`m|-i.^En./AMllfx5h"B'UK# VdqM}1Y#? |/E|%B]Ս[ia-%"e+>J>ᧂ,i0̶SHy]3Hce8 {EFiW7 xV'=st.y"A;vD3ؒ?:c?xK'˝9R"g Tl-3K*[ /vPތZ|wNZ7k$޷f z2rW\Ѩ굶in={[_xj;;đMVTO,ns־Ƌ}F|d<k-c!#i! 3' @WC|N/&]RѼ/l~%_HNP}q_q9 nxxZoTQ ?wrZK/eSfv)դxstrҼwJ>|Qd9w(/Oq%T5QbT$k}M?oaql5GNWNj&IO>7O |fuN;yn,R2m#Sʼl6"dC^kŸ GUhW$*8H<wDu4ʆVIƤot]$#TԩOWVMuQE|((((((((+~5U⯄e,O /Z<[aaÈ#xe<\d0'OW](+i Ao#2zXj]}IusAy&3VzQq$CkϿ?uëje~&^m7i쨯|[_W]IJ\W+?II# ?JQnޟI?3 _ocow*|{OEtm0V 8|=Lڟ,ԁTJ]#6;E bRhyº$udQm޿㿙|%EI^|𶢶zżqK a4nѱdeUeax&Mͤ#h?_dP1_?CNlNSChE=> 'pB>Ww0&/8( @4G\̯~H}?ό_I/+}>etb0A _Z|:hA O RhbP_GS"4WáœiٯRqI ӥiwݟu5x?<NxݨTp f*0*k3jٗeƓJ"ݻE͕ .Dm$eNEzK̾0!u˵M~gbr EJT{s5}NZuYkCًľ('>_S.mSii(r0yvs 09 WW¤5evHaشWwd{aET(((((((((((((((((PK1GK.M.M=Data/110809_familychineseoahu_en_00317_2040x1360-small-14.jpgJFIFHHExifMM*>F(iNHH8Photoshop 3.08BIM8BIM%ُ B~" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzC  C  ?:w(;V=zr}r;wRNAGA߂?ۭ0[㿧vž2AMC;Ϯ> }l}&)lw'q1Lz>>Z#`3E0xצ:c>ܜSB#IŸ0F}iZ3?P6_T䌂vT-۱gvQ=Y܀Teu#׊o|9Cx]^rb-\d 8(/G)_j$ٙ:}-j$3V0smod~T|-xʶiwLHP3W $8ItKY4%^-n۴f=wrG7?<)=vCgkQdϑ{uV$$^ tn"k_IF!|De! >fUZ9=O ~NniHys(6\E#J .pp{躌Hg]1_7m.d|At jO; H:0ݎ==95k?A⭤Iusdt=y55R_#Ƕ=þsV6Z<FG @SK(HEEsOpFwz4#m;?\1q޷$'==>\Ҥlɋ-L;#8IǷJ GYMwu MiLl`dۺzPhל1Mku9*$2=?!Y7,yy'hlqxTOJKH繠lz}ϧ_ҡ s_è$qGny9quHs:ը7Hߎ59ٻ7_|JծH9+dF"K`n' 8'5x8۟S_ C;06gsj.f ,licd) N*PQO~>-C&Uw٬l_0C Q/2JܳB+6c}_B񸷎kp6qfpUO<^Grx^oj,V(̰’GԳu'>¾fYE,:q놵OenmY,7\Kc':Msug"&As9R|,L 14f/ʆdGfRnpAT-<ń#z.1?ۚ}K\"'[Y@kʑϦmX'!'\fH?+v0]AG\&3'J1 1HС]Og4w`!F 898lc_ŷ>%>)OeiPtvrModA3:`lwRU֧װXױ&ጯUl-+zgkoLgp־Mӽ \F9=1rO@zíM圌4x<{Xm=:wu?Ržbqzz\v'289x08yzzQy?2?z#;\SCxT`bFR?sVצ8HRmH + AGϧ\WSmu}_2u3tk;Zޓ{ LmGs<ӥtcעX[bp1qWu*SIhaZQl{>iPZ/tgUOҝ:#*`ܪ<:moė+-*zc<}=)4xj(.,.KeeVaܜ?R徦wWx2H=_OΩh#D܁u=:wFmnRY- gw]'׸ZBHsW>KI=ix` m#=J+w${-/ ̛ TP zAlcg0ɆyzSq__o(~pxJд(ˬ'BcIvnۜ5AUp_ǒip97!FY|妻~>էPxY%{(f y`p_=O7)WJsWuy?\0@G$uGz⻽kM_$ 2zӊ}/Nz>$odXhlvG?+uyWSrrzQ c*O~Zmifr2sԜ1̀N 8~VɌl;Jts f;K8~9<kX Ae]ey1мā>a_f|)Fޣ$vg#ԧ ߂-o5H/'o9ˊGI"hqtc~ |\Դx΅żѦ+y ecAWO5NkJ4-wt_jJI=XҺa\қZ7ؼTcOf#cxv1y,b3\E3qԎ{~uudR6P~_w'~m${^''"@qQV>ʼMlR\"=OV#Ղgt'lm,n2\>MUY^0'zׅ}(*o_rivq=?*n~Wc%S?0oU?:uv%aE9,뚵o&(}~R4ͿqCُǨ@x; G[w׬+-^n+#"Ճۙܒ28~__"y-wr"6q>Z/[])cl*pAa8GW"AKFGR=s>z*:ݜt& fdH~0pzq^3+wKg0. ~ ^zc: 4-Fփ?Ak:X<~Yrk e`d {šZ&z%zz+⏉aڥ~B\)̚rӮF}sV-Kev%Mnޫ|q~16۴'~5ߌ61' WR**sJͦ}7kUt"b6γ19E|weZӺdԩݱzU`ֵ$Vs>v4*J֎6.ب`LHMn,\Ax^1N.a#\Kߩ}6NjJMBۓWc8qR+?}F rKi6!͔nW{M/:~ek3:c=jQDx^.PS ]|_$Eidy*,9*4: 37H$G#;cv9ۃ_ujZz< ?y2n.;(_,MN:?IYcRâ<0$( U^:1Ci5[u,qݏ9޽'KӴ- (p89<!@(hS`]<|)bY[Ғu%m?Lάx]hDT~؎.j ?+QcVq(RFG ?|?iM"ALv˘,!e`W]\_[Tponx'nFn >QrqQ'?L{ߝYQX,곱Fq'A5|Bek F &7_0:yW귇!h0ks B2 q=} EegeU͒{c*rQNzR.Pm> ⶯Gn|bs&6GZ]|PL[n Fw ǁ4bH1AVؐHŽp@y&ku+=oV~N@?Qԝ+J\Hq+>hز <@FI?LֿW `l gIS-ݟ/hoAg)I'EJ=":_X-K8eROqUgZͷQI :rs%<6 uz~#]€P ޕ #\8i»i|{=B@wnT>WW 7a|-w)##OOQ_Cǩb$* {vJWYGͳa{Z-|9OoO/g9m`ÃokZc37\t⽎Hn*W yߓoΩ[jI* p<i*rwGtZD sO[֟0#Lc t GPMВ9Q(-!nXg sN2*$O}ȭC$e(sKdB-Eqƃ^1Wֿ`Tyno؎Ua+)<4V Id$<vg߂xɩNў,iRZxcSꚟ) #ǡ8'+XlU"# =y4Mt/&ʛ'* sP2yv.RmA`u~pR:{7+ؒB񞕵km72?RR~] dgd5co<2kb{gD@:ǩjjֺîk\hm-"خ@9ǡ=?_uG)A31 *{G|t>#xʹE2^\ b?@1{I⼳֤unܳ^0'D-1$RI͝QN/%Mφm'=cҼ^~VE}8JI𽅌TrE07.4X(N3FA~8.a0fpd(TEsqyѓLzhFdP-#=đIɑ8b|8f987%X')\Q2?y21+b$LN&ԫ|U~nFF+ ~s>>%#+<#(J;(94Us)IE9̷ ٥Vv3pIj6v5 '$񜏧jVPע`FHԱNkjpG0}iy7/.TtԆ=}ꦥb<えO]>CCBFlOz4߆ZZfgTT=?54Eɟ+:MhZa,VGNm։e2ư $?JֺNnw H c'kk̶6J2FFϧұFЇ&n!]4 ?ǑRiu,Dq[MFZZPUA$z{ʨ?D G}zgz4fźnbԍ :ucǡJQ0׭r_]]^};II8<R cRQ=2HBVv2Bngj唬R\%UcӽZ4;⎷kEYDw oks*"%Gp@^ 5x tH6ݱr0!wdu9 \$;/ "IJdg͞6,i4cJQ|^߅ T]xQF:!$\L)wLp;Wk,>/Rtu2fX^1%+$4H"njs>:~yZGZ73^$ܥ!> sA9ﴰ.Z<|tg*JZu= V1F$|99㧯Ne=yԒKeY:c5~#_E{ B|#8%-lݞy=Үd a[3׷cԎ}t]՝oد},v^'rH\r)ݥmMeVXujjd& )'# ,?x6ݤ7쎧+Ϥuzw=+| L̫(t)d#;V#?_`x){lRI \m}B;}-=$ /Yy/y\1w%(3'#/ \ˡ ;w"OGӭu?<1{[2[GX6[@,Ny_PZYC4yR_<㟧n";q1uS5= sG-Ee%]>4X/bx^s64[ƾ&[k {|qPI9#jmV֒hȫ7VM:cOm[#̜Y5H_ !/T2'uo)}hG{#JXЛVN̴[sNi/.KH}OѠqFd|RSROgf]bu m1S{Vm9d9#=2HxL|rO{jԮ.cޢ4T^TW5#Ve@(8_OOJûl.b1^}3Zi'4HNs9&l9#4\d|wө&3qOT05 o j7qqp3^yzoiW7z{FռΜE̯u|K=+ϵ%2,M|xA`e],XsÚގU.A.ea`r99Ww{hAc5c5UU uҼOtt'rʰy^VSbxwMͷvHtqĜ~>ī$`m=lסh>.kC x?Nr1LQmg)/-Oּ9V=p=ş4B#,=x,#_z\󧘎Jx*A?ƿ#xW?5y4r;i]J~WF8 *NrҢ7ݎc*Nu=['y"m8.9½viJ}e>Ȍ1~s;x>vuxl+HAu+{EΓJ*8s1׭rb:6S^ \ d&`Cn8#¼?Ŀ#of{H71nfu8s >mA[5lAB؎3*'MbK:bE Cjbi:>O:^%8=Z?Nopxi>hK*0v?0;ښvzu۬20bv$JcKhuc(OӷU7:2sf)-,#IstԴyv28$'JA g1}W8|G -``>c++#&Ͼ?umszĸwkPT6`gvڅ۵b19e |3CAcF"vFfY6FI:m[~1od/+SPVCVt魋]7q) O֭(RuF A\8O x*ɖx`Yz5(rhQxg*~Fqw>808˚5053.m8cXjqhV Vvxտfq_1MsKwTm-#m)Y0ަm l$QvLoI,i%vgvYֹ iVe ΐIk8lmBg ,$--㶈Eg?:5E$?Ҳlawmֆt!9OC: ֨%!վjq ]Ar +W?fcIQ$qIMp'ߍ}_-K42֍d 8_u^$K1; '=z7iVn=1>|q[[4, }FO}A#9cOEZ"7fM;0Ie׎xkcӼMB4$ԇ#=WCHx'\u- Zܷ=*j3ZeXLrɂp:?c2ސ8zjH>,^KS8#.8a[j~Я$'x>XEp/%q'H_H y 7<دK.NT[٫^T%Umm~_> ·zc٣%C XME5a|݌CLT}rK1=3^Q/ mC\\ H<ۙA琀WMxHKi/;k|XXU3=øǍq%]߫Een^!76:|t(|39|*Y2}NO=^nk_w'ʆ0:p:i8}2,ñ9U>*qׯOK!Vr`@roi:vܢ2O_k1ỻXYWa>fz=WFk2fff sqDrI{lscuI4՚(;O|9Ҵ,$Ҿm❝:4nŷ vftW9+CwmUe,M=Oqeh3ZUA{HyI?ָKwly*>xrQF:s7RE)ؐ[⾮;I|el 8ڤKKeEZ&0P8sx.sG^ 9DtB\K $70ظU皧b"gdaU *Eameiosş_=7Wעk TOm &;dV(a&\ m{syV u/t v #.0_|??VVV.Y,R2$8>kV%xSO_6n#,*tJWj;:]+k߮[H qp"_q?c5s{j; }?=+*Ծ贩$ǻ`Kn+=U' u9w+{̒w NּVE $c8 O&bZ'$)E\X/W;NŸv:*)UGejWE;iOީ][EXjFr"]8=0}zKix^==:_AZ\l=s^\~i1.mn TcGn/n`??Lvҹy'Z.nݵ@ =sW=C֥Ob]2m}zdqة@Vn$};%bu_5ORN' uŧt{V*$msu`z5r,db]m_{_ $۞wd|9#ֺw|{Ⱦ8$NVăr7OzH4&8ԅ{oW#O{k4f B׎{ w^m\u> Fmy5 eHL9]3\B^+c>x~-^;t0eb<5D9HH'nu=?(χmm%LJخxL *POb9 ߅^*<1nlLҫ7mN*8x5Qzu>'M_ *\ҵFOkFTHnxVfw`[MŐz\Ρ ;^ pNNܒp+']{!ἽI!gӠ9ީTғq}ugZ)ASJK[hu5f=o֙3ٕPG5<=~W6_-R[3`9ev;^g)0=Qnм{{w$\A}O'63G)$,a}{{sҼ+>Uh"m3ΏY|6 Wk/=smFa^ӡ88lz#|xak/?}Ë}GQ9;FYrlxÿ4>ӄG|^l8y,m )KW ,=Wuitt+zW;\t=3df{Nmoo&~&mV[$$q3gn+ӞAԭ[cudpn.. IkT 9 wRzx&u}%;s` X`F1؎2HL:5y?t 0;~ES|zuUZM3IJ z=GJ\`H#$}Tof{_Տxѥ'ɹ&dݭR٦ϨV]߃/V-6uwىO2B H,= 펅f-H/2!|\[2K韻|oajm|ZZܽ+$s ҿ\&+C}U?q -;6~vE4ʜs޵X@&Vgnxۭ|?^%CA.1e{noһ&UM>滐\CV5rꐛFGTJO=NCOb+cgӑKj<9n.eG yזkZ /l`8"H<  m"w{ 8ũHU}%֢8K?.x;k3tH --`CdJൻn!%}Պ~zWYvq+^ zU5%TreF:araUw3sGUo #Vhm-F҄ݫ{U[8K2m5&"ӌ]g٭"^0I#<ȯINW>LT9`> )?XJw2D̠lZgd}m2ZS!ea܌1V D+lU}H ҷwW,r*ն|i|)r'=vo]ù'o|]u:cg9@#_5 6 ,dp+̭oui/$D0 U#%+wm#3,\hIaIݔg3ΨgIe(93X<%kÍ;LѠ.#T[$v.ۨ8as04 o:x c#Ǹ,E< ?bZĉ'u:yacdrAդRWi&飘4cJ䖍Zi;6ľ%>&_Ѽ̏jcH<*ca|~ua+iI/G#^ΐ\1R틗Ұe//W"\O݃Bzw5};I_i~0?.tc&3y 2R _5#4_ܿ ΓgFcĚVh3 Vr1Fn+Ѵrxvƞ0NE- TK0泿e;8~8x%xFXFW M cv0k%^oqX1@X|b7\刕+]viy%U_o,G'{Os+0O}a@t+2`v 𸶽)4rnhgF+ ta]NAA~|rYY|+֝* Y5 OFUNvQc-gVڍDpm1{~V ygN$eV8@_3_\Ip@໖<s^UEiT ="RQ[^Zˌq՟o }g*1EPK1GI˛MM;Data/110809_familychineseoahu_en_02016_981x654-small-12.jpgJFIFHHExifMM*>F(iNHH8Photoshop 3.08BIM8BIM%ُ B~" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzC  C  ?'I?|7{SƱ/24>&W5 @$ʱm/>!;P,t+e\oKp%,İ$8-i 3c-*L縿72$GwGo$}# 3F%[]"ixVAZV`K}ݲ-[~r/N aV ?PRr4w:!fRa@0e9|"SJvӪOv-Mhޜֿvxavw,o1^8acZ2 랽r;^I_jTؑ#g.)U8ok6+K"]K#*6GSwCe$pXu"^ƼR릗Zb V>h}zzlūDS955䩴1@GۯЎF:=N#b'͘F3vXZgݠg:WF`1oNIlޟ5Ύ6tc?™PF<WEv n13pcӭ509n^r{֙Q=;@x9H˜~~UJbG>m\GQ£1'?޺#018ڣ80ȧ?u9?Z6pG<NzB`#1p{}?:;O3 ܎#WA$zcM01c׏NF 998?*?qӠ;pqc~g x?NΎqL9L0ǿN\ێtz}?Z|s?8'u5J6t=q߹TwB랟N pq8w: =}qNX>zuqsӟҘmz_ʷ|GLcL>:t_OO9ǧ)n>EoyDr{c߭7\=.Χ[",?^-M1yw K4k:3y=;<ªv: H񦩩>/IMktb$y_LyL9@VYa|L[DZjfhvm܍9* nݪG;/SgSj%xtY G- FC}1R p}Z*2[s'w󾏿V([rzgbIbH]Tq\ᯁF5rH ԟF-G^ɮig0:s1tNOQ\rݽ}+pǦ{wx9y`c骄f'Q}N88w½^^Ozoٔ*jdg6-2y=j8zuyǨ][cO|f=: tS';@zr>SM jM9=xz~Q}ip:sɧndq#F6yN+> ` c'ٱn?}? V`y9ݟ^ps}3k}1=`oĞ?j?zpou۹'9'u*#j`z`1܏S  shڳwryz{~Y])#zsHg^ޓ('9=M:mӨ=x1M3) ӭе0M l8oIc\ =1z⛨W)CZt{9./-F 'ys7]?ROm;<\JPah1+v [\ z[ȶu%pFqʩ|r"~WyXu!=@0oҼSio4& ض6#IL"c GqG3_' #>MI3 ,ԯx)> ʢmw:o_VT{*i [0mmR3 %}q,2bEn]/>-犄++o>$vs~Uڝe[|cJ]u8%CXgчB3V?LhSEN2}>.]jq Q}9JQ$?¯ 7tf$`Il |F9?پl_$u<39#6yu>*`?9{ҋ^x'O?lIlxzxSon܌Fm\wj~J.׹+;ig8ƫڡ{sN#r~Go] n109M8uCس01?n)oN ctj\瞞֏j5D H$sN}u<SzGQӯn^|~ jھ.{HqqtF~BȑkaleqfF'y4H"s;#g۹4Q)(b˺W|1>$xz[Bh?VX)'2I{8kǯEӯNa,YZ^--ʄE\ 2P@ގ M:_ !GѢ",;C;K= pMI q<+0}_~ x-XZUHfXh{(aD?WM2m>0cOY.=ۥM  Ɂ&}BL9:Ue{6Zjzz&> KI7 Ip{ytUP*XT+a+¼q/!kNs$ZZݬx”eH`{k#Zx_ƾ mWLXp:Utvm#aR734aKƷ]a:)MpT n8fd43 C ]աy^mgeg,p]h~z?T|ʐ^RIb#&2Bn];*Nӊg.{8w|5@<+u{;1lwpBG0P߫&MimO>zE%;y=מS \mE'_eUSKkTZkdqb%}OvojH#=O>9߳t~zūc ߜh=3u?Oۉ>Ű0Z3{~ћS4ϲ(c_9p۞pFvQ~}voĞ?j3o2@?Z-ʺ|׷:C7/w-9b9Kd0 l 2J;@oaP?_=,L-Fb[b|Rf}2}o,-2X~v*AޞgJ{Re6=y'-`-[kGf*3Ɉq|Ʃc:$Zuf.W˩x+šv N)b6/ݪTnUe|i[:NbWKyX >FM\fkş^~: 54dhp܏%!mD[{JC!cY{k&D3$8UԸ"XٖT:)K; &oV6->{ֿj?мWcݼ݃n, mFUnj7 k;mA{Y`Y +&Mc^oRwRvrjj}lM蓲>p$U}fD'쑭~- 7Ic{s~R|ȑ;(ڭ>x^Y.oxj-VSw=CtK}*1eHhDd-uIm{ȵ˷صhqՇWea8nd,bѼ):O] =~q1]-Ru߁8v4MJMrht[{ibq05j8ǛU ~%}O⟋|#yj^hZc"GwFVڞc`US!Gf-v>"hچK9ТY3@I$pI4o -jmy%(8T8\ek o5 o6?Χ/Kخ[Rf62M!$Rv* ]U2}4h`(B)M-'⼢xғOv?Zz9sQAO^*š>yj+qc2 >c {x]0^V˶Y_ mL=E4,%JNc6́>3G8ȪJI-S)ȣs6r9'S {ӊUld#QT:X aG1vˋau:S=TJʾTݤoӑ#MĐ:׵tOc3c:_VbYjseoӹ ہw"C1}? m ?N :҆-gQIM$oO_ Z( تA=?/շ0 ?0{s_Ea.Osxfck0+{w5~Sev ~S㲹r}03z׎7O^N-T:ݿ9m:d;N=qWOUũ##4Z}L]ޥ+,Pꠜh\(G[mAɬ^kW*rI4 lV>%T#srEHKy[v?0chUT?Ox~!5)4Khqd1%vF R[\6r*j׵*-+ѦѵO+iPT6i}m^}[]Rj+ԭ?rLiPU-,ld+?KA݇:'u3kxA 4YYLEYYPBA^39}:&T-Ŝ%el)%FqWKsR٩.׵?&q~x Z+k2ic81,JP""V۷.xrԾ(5u M:QmIMا}EL3XThۨO^#hvH3#vN8*z.ݤ4|mbGѰpbxV\ݸ -}{cNTB.'oo4޼' l"l De|Lηů^_$|cv1~3+xnI“ f# >c&gk.?,uDp<׏lZǗ"=r-Kz^=JH+{[xYU,Wz 8#Ҭ q#ص%=QY|?'5n3It2hfyN6li^y śުQ| tOTY7n o7e 7EUyHD /< 7/ _VMK?/ZKx,5IN {/q<7euPGV񎣩Φ #] uWrd(X_SZ=V__= c?^$vb!#Iyw@#i"߈Oa Z~-nntY% i<eGs#l{Ua#s^2oG⏇%Sikon5maM=\ًp$r[ "݆CӦ}VumOǶnЬ|lckIlpU`8`q}3Oce7ֵ3IyhZ!\[*]@~hO _k^0!U,wrYm m?ΙGZ]XzPhn;;X I"Gdv;K+`[]Ɵ}ma%CTB}`6c6_ۍWžWnVmZF&X%s@r_ x[͏#\cMWF/fx $~X?'~ k-,)B_˫I;+\M-]k˼˸cALym,c Ӆf3,"&dl40~P>B9)υ,81,#\9- ?)?\еK Tx rW| y^As_c<趝ϰkG} q{OKXڬ77 .Czפ"[mzʔ#?f>gwe#&y/i<TqO?|Dwq_%u+)2Cw̑<"\opDuOGSAAx"p@ "4eDH2}˷hVuJ^Kiw1c!i 9'=Ti b*r6&z[̸Úik-C+|6anޯW Iζcl"ː…Մk_ |@kxTDMܶ+k)O.C!Fi!b2ׅ5m_^o )|?3&~[7Y $XVB F ~"ϩ{N4 TK:Iw(;9~M2OF!kޡ#F4oV[V"9-cψzOk+m_Vwr5ړj mjS ͔6^|Q ҈m,y|.3U̬c W pO"Hӵ~}6zn\1| k}Q`k,!c=|_t~MM&;`M M5đ22yusd+5ĎdѨ`&%,-c.w\|oN3#N_iS3tR\ȃ?6O$q|@"ybX7lv1ϦXmkfa/<^sAoǁmfSzG&uJ8?x9Ӯ,o=`2F?.xߚV㻛GxXFg;30=A5c\\^[^vuTN8^~}neK}of-y qۧtz +"q9$t'7MfP K w\qzǏdL-SR;8?S-GJ?]X.Mޙ-K,}-G>e6R7torTfYӠKxl.e/1o0`9K7w*2n #HC.a.7+\.0-R,2Twf,pvK^-(nZkS| kmki|a^9 pl`DSn2apQU|7C4_ izeψcf1E$@D9WYr g"/4h$|`Kt'vhMyLL,5H%ܫso$"ljβo/fӤבn;yŜ,mpr}nUkOO,5s_-ZTYE 3OI`*6U_|uܯiw>iܓ4p/@*CpkZU~p{nInU09S~ SbdʗЏ\yC4<+sSҖEȏ V ^CFxiV?1F6bpé/5;)צxC*\eOۅVcfw4hyA-IUM`~nV[IvXp<S!V`I(f* I>&IG|×2Ts\GsC/4 +V"s;M.e" s BV4o*u@&r~*qJ~ -u }CRk9&vP*Hq![`Fi~A",~tscikqCzr5ؼ (IK:!<>aٵ]nwI{gKMϏ @E*̊8F'a iz|ųKbasD4 p+ĖQsvʪ[[t8Q@HO8&Y4/6WkI^gj_hIf޿ֻb<ԓ ڲ6c*TQ힙cG[tX[S~2[FOLX&"v:3UJ,QF@FOLFzzv2RMjaew^ss˯h{+,R@v@w/jVR ryzutg5hM97]٭Ӓ0cM=gU+l|?_һ 6ޠc'oR? ymj@vSvcr6qP:Dށgh$gq9^xG%͟7I5mX+7fwjs5ΟQ\B*,~itܹ7{= '"#smAgX/hnxDpY& 1HYO6|U˸ z ?܏B7pl:!!w6C $p5zzM,U80k5)ץ8X1c\#jgN"&^ݶF[@܌49⶧Ҭm^ ¼ ø\)[eT'h,r9ϥfcR3m>ƻ8hN/37yG%Ӯ#sr![G9\XV K/k-Ն2gb2SЎGTo2ሄy1'~Iè'EH`I9z\¨FeFxqzЊk[ b#$?_Ӛ[ H#*s> D_,m۞PĊyv=;3YD&%}N|"R#鎼nq ۼ?=wȑĄy!Hb3}nc6)ރq`W.* @8ݏ|I+K `A;}OArvE%/#o@8jGv_1dxUv؀Y_-`Ue,8RO<w*$[6mUA}YrFnhBdr$ݶԊeKPlN?sT@@,LAxp17<*vE`1!.n r%\:`9ٚF!>r0@8~g@АvHfRX?c@eu ׹驘vtQ~t^[.8P3^9l$qv`] OIY: 1f zxg-s>Aj-t?/7ѱqX9[YeY2Y+IhvvxXѾhxF74KwAafpe=v|U|F.eQw?<79<;;UNi4G<1-%9M'09aͻ d ˽[ͩ{^ x#ӡӴ[]Uk5ͿTq'> -Q0+<',J|0埊/yՍi}I#Ƞx3J$v HZIO V18!LHfL< B671*wů C,\ &dăb%'Q3Ӄc#ء60IX%U < #8bӣYLs=ӏ1I!f;N>ld`=851ұUg`wNp$4OWhɭm5 !۱9Ǿ+t]<-nNߛdl\ n;99Zup#ȨX`(q_DKq' Lg烂;cSyi ُx?x`gXY(;#?=kӧVEZ +V烁{dd1*,g'ZR}-.9S iliMb9my=NkUAẹa%rs36* O\;qh_$d[8| / @rxϮ k 3T{xm%ێY<ǧӤ3HQ^=GyO2f5q_NNO=T%bG*,H׎*cT6L?&~lӂwx-Z;aIC r1rUTp\t]pqӷh./%I۸OcұEU97)# tGֺ̘# 2p=sg2|q9#T¥)nIx3\?1G(Pv$r n*y#Qiy\29GZhswe u߽[ EKCtqȧ*g-*[';a W#ʑ  އ-A=R;ګE(;Ttmc^Ef]V]"+*]^Gl[.PƪK+nW"Ev+ AyW!m,TX[i]ybڬ׵N]68;VnT1(b<'PMqXp1qo`,A3g\:N"Wmi gY2Eue&A8 dN@WClC 9UxQ$fpTYch۵]YLŎVG%׌?Ҵ/UcaI8^}:㿥AC]3)\ۑS Pt ~Qnd[3#dg],CqlpО3M2?dsm |rcz$";GsadF|cju6ȔR4 5#g:zsG0uF^ss[ev~U =E #8\>wZPK1G(x GG3Data/mt-5392479C-4C8A-48A5-BCB1-F280A815587C-82.jpgJFIFHHLExifMM*i 8Photoshop 3.08BIM8BIM%ُ B~ " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzC C   ?(((((((((((((((((((((((((((((((((((~?5ߏĚ5MCHxnn_T/XCQq@;ď|"|Wᵵ4NQ2 GfTNb"O/s Nqҽ{kksNC =5~ 4 <;= ѲA| mHуBoTH`黥+X$?2gs4:K,Fodcy-̷ВXe1-; i8]I}pk{GQ~ߨ]\\CsJq嘔GK eL%MZ{]u[}ڦGvu/0/^0d 49g}K7a䷏HԮ~ eRJU_m-3kjv65JIsZ}[+7ueo37uhM5 Bsn̯nVԂ[pN,D}P!27 :y̿Yn.fFmZiGxn% m_ >&{`.Q4.gI$򬂽yRcliLx;m au5~x~ѧZ:gA4i_!M??mYO{WF؋UXmzxS1iz/ص+;=Qsq&}~<-귺usZZPK? en#) @#;XDnd_O(#(cM3peXGS# b{udgfد^oZ}ykڍ[Z^g{ark[+Y*IhC;Sj6Mcxv5:?y (+@'(o#)M>/[Qhll@׀hyUXO$lE~{XGuiyM).nk @R%*jdao O{| Ф.v^-r%Pw\ݔ q ;cٗUྺMu9!!ke UU2|e` /> Xi=__8%ŔiZlo;W;\FFo6?v;~!mt鴹K{ɴg)xm]0wxe:n4 :Mo% ~nOۼ~qY[X^ 9V].;JO osjYp!1 h(D`Ymw|"͎k/kc;X$MvfElXLR=*?y3,_ߍh||-Cm浰b$aXHIayx2!z [G45owe=>uBMB`,.RAoa7Ww쿳uO J@Q!vU "Xym 3HFs^#j&mjN4TGl.v}wQnD=kv[OWӣHA4Yx{PbRM{Q O|f<GE{vpd6i\{3=m#\ o-2.!e*~oikg5gwpeZ[{+-v%MݸX0p jԼ5 q5ḚmwW@᭟t7I |Gmc&;M"DfNKFZ&}6IRX$A]5o`O69Abg/!m7@YaJW8'0,}7Lӭ4쎉cuťեVk Syq8}+<7Y|:CGև^kvz. A>\YrݬMe-6Ϝpέ=š͂hwzvt36QQ [!xw_Wv|OZjFPͽ)|4 Xg:M_=߶(&1,mI ogҗRWq[j}}tuv+HSmEԼd/~YMaiba\-X+^Lc2J#EOxi:xM2D*xkWJm`X xG,.r[?_u_xUƗVMfxt6$]>XzKAg(c>~ i t:$Z2ZBN&kRkUHF%tjB|syK_xOGo&$PfբUy18<+|D٬|?X!㿅,RC$Wqρ\#iUKr>1kgZ_o5,A1tzxP^>OVHVVolړڦ ԣVKYP>l|ˋ8A1kWrc&y KG4]hm&k{%y1yXj)35^EI<e-JK#×K!b"Xm>[utܓDg| 4߈7%սVM[[]ܭW1\><2,:|5/WX{FM=j3*ȳDV:.-2.3_@S9 ˭Ѻ qj :P]|Uŵ.pܼŝs~wC,midcrp,Grw~&ZxoUb:v;Kg#aK`=]=by-D)weX~ͦun^TKӴ[]mn[8pGO f]3jq&wd(`i 8eX].%pW/rGi_>waj_jI-G%ɉcԥv:,N$q|(ׇ|!x2j]ٵ-Z6 XoL]D >j6"O~x⿎?guO˹KMr}&do<4I#cG5<\|@NJaZgkHHcX# bRJBڧoi>%j^,Ԋk-U&-V/46}I64A4d>60u߅4mgT{I_\v Kn@3Zg\qA&ԢfkFQȡ&bv9@xOdh|˭Ae69&/9Dٛß|;s2V}{+RL+hWP<ƱG$*G|*)u0T^>ֶ ЋK Ļ6KmC-0Bz_ƿ_ ~0w᷃q% ձGi2"\ $mral?i"~0i⸷[ylΛ,mC-ܵu3#JeQ,g]3Pi32itm:OcIHnb$-徧'@f]y|?t|MdwO|kt[_c[ c)kGUpYѿoKS־Xmm I׵o<s,Iq\J^K&0#koQ|%౺ּ[̖gSm&(m ’hl.WKԾ|!$-Xui(Wk&e9%_/Kguoig/K'/Q||nun6W]6$H;$FDV2ҿn ~"K?_bR+KSЭ|dt0ݖ-=Ļڀ9߅|=/ǟ"<ZP:4 ;J[$eQƒ|=Pk֝wO:]\ɦ_tncɚմZ/`p oG~fƥf-m! H 3s7g>">d_V&K).̭swqX㳑1%*`wo#>v zZeƙEivjYS[DhF$5XRd^??ix[aĒ_j7ڼSi7|^&d׎-%or#]+ EӼKxGuM+G\O-ΡO3Moi aY#&^V83C o<9jm}3M3ǨC]h+&Du"Ldž> Zw|'(_٫u?Y\ʢ726R%UQ)e_mkF4Mo@kem6}'ȝ(08v S~>92ηOf4ALuX 8HO,tbXuXjrvʢV借t]Zzu?jn}j[-Bk wxaFBG$H!XP|I>xx/Gҭ|+C5ãNf8%(6~E}Ex&,~zޏmxZkin-#K>DZv-'+ `b㹛/۟ j^ FpwF#oqpKݍ!tW.F6w סQ@?/\[<1% -٘K [Ahћ%T?b??5ݢw:isgefY%O&)VO,Ggy_$}ExT?o 8ܵ]\24QIE#uCWu>Q@٣U-M>K_ܥŵc6ʈv?|Nw^%ƺC>ؖ '΁0 3^Ey?g6#^ ukMV^ikmD(#Oݨ /*3ভxTqiwwgu%Mė v!Mr9`A3&wtPxu|# *9[/uWi^A݁ݘ%^w1[|:Zݴ 7,hUg€aOB/ *t+o6"xD*) Y(+Bд_ 趞V})omm(*""*ZQ@Q@Q@(Oo?xM>%]_~s?i?*_W?d9N7HTck#Tc3_iPxW\崻 - ]*l]-E2BW =̆03j@xŞhz΄cƕy}uO۳,Sɗ٫O>'UGt:Qt4uc>B& i ʉaܭ̊%x@wj{xiR!Ԭ6\Z J=]U%$F }|W.[xŖz{KnC[id:o Fα 4&c1FE~'|E|05M/Eմi\i^.z; wq[[h}@g?5[E3Jm/#LK#Eh7Dr@E~@|Ba_&C֣]:dE!X)+C>l/վ28O|>EĚ*A1.fm5HLkRDYa!A(@H_V-5dַ$61)#6i ls#}@73EQEQEQEQE(+/kp֚V \]JK;,klP*+1<MxC3EN|4+g˨8ϾmXO񸪝mt_/|f#^<> iv9_L3ZGh-“o*ف0'_'|6>/:H-.5o \-nn$tMJo-moK M /O ?웭7ú}qlsNhמL:N=܉>@2Gpf?|bҿ49nt)T-|7Y[A2i_h++aۿ|u?z5=6PMņۘ浂'̞b2I<`VV~5X|=$ ګ}q-YF?/a2L&XfSӦ.ˈ#ػU)7xs3pݫ3 u^yt[yme10`B$ёuk˯ًɥ{T}5Gv/hS8ZL|*=i{⿇~ kg ݷnyft(mmg#46  M2~>"6{$q3MU:m5]R{mk{g9\m¼ 0?+oYv"V]#W\ xn/&SyuK}Ad<俺M 7~?5U凂HkMc%ջ,,b3dOFB$o@~ωnE[Z 1k㶁0Ң@ɨ5sV־!')dG$ X3mYf8f!c[k7'Km.zԒxeh9.K+ {s3 u=o}B]¶:JTSI&j>bq{4mR{bMJ@?YhKC}BæAk{b2,y HGy򘔕]۟؃:Bu1&u)Itt>K]Z [GF r*n~D~7Ői_\~5ЬP,o &D# -Df}Q>((((+h>!.$*"<\L^HWȶW3ͺXfD8(S~*Z׎4t4RYmRMBH_#ϒTǘy#*wv_khlaf7v5RoPk F܉K4>z&+G@Ǧ:bUTP0 ^o MaǪǢ[JC k(ue(Q_0m*x+WV޹vz}h7':ai%O\.?[Z8FPYsG#=qJl0Fy o㿎#W otO<Qiz-B sG&n̏JA^Ѭ|OivX;}ap\[[j/3MrȒXKX0~ ߡ@JXcrOԞp?4_12Z^k8ﶴPC&QSPeh߳W-[SxDLj5-VQQF-n-gE#c#h(.6< ݝǮyϯ5Y-8E$G)ȡQ/?o~KiroķZN-4gMTt<75v,MHD).0775] \O%]>]*L;8X+Pg! ,"?<9>m/ Pŧ䟞y|gj!@P5F@@?_'Ǟ2/Cnh$7ZJ\xzNMFBu&tfpL8s9c?7?-;ĺW-Ruizl;)T-ֱ x1;HU$@<~1>BN93׈ࢾ9Ӽso >H t=@wl4ypwfUJO> aXo\?FEiN ~5ϨڻEm䷃Q`&&D1=681gwϮ@( E܀ q= h((((((((*z51ZΨYX GTEFIP+>+%+n.ojޓAtـc]=cgx3sa,Lvu;qM 7Q =@ďze楯Iis$Pq &H,$26ct[S\JE溦\wcG'~4~ j^Tׅ2A}lKe\6VA[g#R h'_HWI\b]e1[~bXuMwH! 2I;>+x|&u_[S ŧxu|,#ڶql ($ l,UkA>6!փAp>iY%udP=>KћP~I^æw ܖXb2(y .rP8)JP&n#y\"&bb$eDYQ@=?/L>qZkm2}H;il\@I q:}(tjV2_w F Kޥ5[H!.%T/1h+ÿ*M[O:uΘՍ,+K Io%b#,g˃`xo5{~YVSatcSd)#%{{N.%O6ωz/+.m 5vePɯjjIg"]J3 l=c%;kO[_x隴Qc6f\a fiW1]G@1Ȅ8du*yVY2xn.f11)xV݉ZE!%#"9Ou }jZًADӘ+bIm1+@!%?o?e">`oo>bʹ=F[tee*pc.hʊeuM(o.wutA<%,\cٌB?io[i֍}fŽ#iA[NJd9FoU K(v$pA_> ~~ƋZiPjk5y\h]֞=+4M>=`#]xFn!*O ( (?(+~>|O/gğ"]z}KHyuP2"9$}z_/ßƗZewHC2pD"6H N}cUknJKqq{o @lF;F Z?ookU\XZA$ZswyiYv'PCE_BI BɺDId~ k2kic}#=V MB[XZ9$9dA6H4 W j,ug$7_iYujP[ySkt*G̷ZWVͽ|B5 ywKѭl᧺+zbdxRKdM&d'~&G{FtVmyE/η#i 5˟5="K9g֚]KU;kK9$&KfHŶT@яZ f 5Uv\+K{,#"fi%dM=(%?ۯ;S]A.4-bLkjg:ԭ63KG9U= }/aia6~Q[<P;mأ\ wMq5.>oiksJ <; Ai?%}ώ^ťizMu3.zcZ4Zlp%d@w-ʰGޗuL͒8Z$v #/,ƃ, >%?[~&LWZr\o)Jţd!Ux|2/t}KX9nWz2i #@aIf]oMMbMּNUgusr/tJ!IpK `<qm#Bie0hڤY vEݼѣ\j (.ꤩZƿG{a%o#6˛dm8ioݏ7;eĝ[2n5=2m[Ha][NIjvZ2RC=A6+e,>a.~̺ς8ڥ⮳ `%77p±ΊDTX\Ei ?obVM=g3C6, v'}? _"=wSD䲴MJݮVYnG7^[yDD?kP@4;W?* p"C<ͿU&Ꮅh<#-ŭs[Kgyukuo^M<]C*OHS S_)PCi lHlU.l-tms1fqH03)]:Sl%=M=g}ĚxQDʊ\W7?ۘme]Mֽ._F&R+BҢ:~?K Ii3%0Xt `aSIl< $l~ o`4=gU$5=˫}2K,~L#A+-\>)Jߵ,3Ѡ|;54MaZX蒥edTXq ~b ^k iޏsaw~$L&o.ns$jpȁQ xch?QPln`}FKq&}-j҉rN}PD>oagxgNu]C5Do?&q.Q_kbOoz|m_h?"n'Q|Ky!$Ki5ż GWVR5zlIaݽs6-QKlzTl JO<#DOM [{ۋu1yIRؐBO/%~|5LӮ7imF{k2KpDd91B dqy׉|K=VPYRm1}2i-k8i5hC4یqSU|~9s-̐PNZiu},d4RpJ#joGkCpVa0뚴kj/>ʉv}3~.6䮿P> m;6_̰IwtdiuHI:I'[B {wo֏>wRg+-T[ J\B2Yc(`ud`ȸ{G6˿|Kϙt1*T=k((+̾2?Z>wyoOcg eR9w(6)'|Tu-6PeFWNXu#֑qs5Eg^H- Is*Y cMİi:??i]}twgCk4-p./ϽLP~M/֮n|5i6cŖ7kV.,V@b\XBqO#s,>ѯ(mu+˴LVy$k ~T,"Rp\m?PO؇ǭSǞ.xn$D[˛/=/öZ}=&9H bHb{?d=6g?>{"t+ [[Fugq6ѕ@CJ(F~3|SKq\kM<"koJlum&)ZYZk]b8]~=jwbq"Œd<,NۅE͘>q8?4~,~ú c欺=tnW}?Q}%-f3Eb%LY%ꟴ~8x[[irk9^3iڿ^F'02eR(j}>0ޡ_[xoY ί s.5^&=*fŕ%//.ce w&?>! ~ǡkV MJc;KauCiC-G,V۳E~]x[ZOiǣk{xa$˧.CYhm%{SȂa!U'-ܞZisjjv'Qy7卣i/']B̶Eyi{˫{u^EY}SD siUg8Xar|MK1KX4mAT|RmZۧIkVÞj6&i6?j|Ax[K\=e Q%ԫ J]rnbdHkflY?lvn_޹J^j|7Y^Y\WPchVm5q 1OMd4ƷGTm+imEnu%ϹaE~EPߏ?kG/-zޭa6=I6(hY$g^WE FZ]˛O O7 4ko|CNY]%jVhVwpڬIl$F'y\=v^_/[;^Pwn_}?a[_c +>xE<-_k^8үn_I[iks$A15 T_>+~?c˭+_o5Ui$fGĢ mHdΌ\ڵtkk;M7R$ͨwխ7WM>袿j+gOG/ |2__|uiD:[ˮI4yUËY|_-# .–`y_/)wGog Ʃ.4Z[œ\-%xN8L1nʈ۲BjTE^m%ԣinƚq(~IkEsOÞҤ|W[i1qw*C!TWa~-c ׆]yR{M/i"^_z^Lsυ/F?:DO! qCOB%Ə5{uҼI6Ck[ĐJ@J1\:_ W *ͬjiM /RHRg i%n87,M^NJnZH'[|Iîxv +Ŵ,R.qt%Xdc OۧeÿPOzGm Y!ϪzGOeHx匱 0ߝoٓ s!~ο7zUտY?tk-6WRu;*c HF#5hI[n查ﲻm%rbmv'oFQ_?nڧ¿Ɠ@/Ko!qZi[[Qom,99c,C)L7%RCx=:]Zܬ , *n Q\k^7kV붢{9>/W_tQEdEPEP((+ ?|<[FVsgMյ'k^I E7R5EgRqi/J_IYE%(Iw5~O儺]j?u{K8 īUX=ۥT@X+ ;_{%+Ś5nǂ|3y+ҵmNCwdyMcn8hWtӺumMY6vOM}j0yS|'E7~(~+|A+=7l:)5ۈmo6~|iwGb[;Q^S1\'}_>zN=z>W&5a ƍ#@ΪNXE_JsqkjZwkn%Ƣn3OZއ?-_~}3gb;YZRd[$TF6`ΨA qS O?& Cdti.KmOcH\QI+ʊ M/.ov)߄TK_1dU'ýsF/[xVV4Af l$ҘFUbþ,xG[^ }¾'iW &-Co],7m 3\:&*j'5Bo(,բjwwJc2K( Vl$}gB P[w^*zkM$KJJ'K_q}vI"3_?gVZnynniĺ ]vvx!,>c5ω$~U-|sǞ)wƯxTk _ k>6)n-.aݤqH_&ԓ[Y^%]' ~?| >*|G5k~;xJx`Gxl%FXl׍;i#942mڿ?/_Z_g ^Y ºRJRDB:%{E*-M| f0So'r?",~Ij?[ڀ(MkAGI ܕC%bʄ3 u@վxO^ׇ~#x+^3jړizݵil$"wtS_Sv6%:jI|q*4($v:bC.Htckq ׷~2wVg۳t{oLxGM j~h'Ļ? [x{mRXm5vׅH'2pW];vRVf$iu"'Zkt~qirZ5'I?)'Ǐ|8w>Ϛw/%|gxz}o\iiuᶁ[moKr|cX~_Qc$5 x?𖟦'Moi$]}s)iiצ Ine)1. h߅K߂~(hau;y-nmA2RPG~QU KwvJRwedޗ(AEPEP(((((((((((((((((((N|k_Qgk_k~e,UkTحFsa), ď|"|Wᵵ4NQ2 GfTNb"O/s NqҀ=ⶉah!7|SJ̋}gXt[r{A 3ƂBz]? O9~~%#x\FzVlⱼf[I,2 @?@hu[| /hzŇg=#R6KHVB*kOU}ۗᮽxsD5+%Υi lY.;UEr"7ltW2D @|M7/\\i8)\kIY{vQ{I(<^woZkNt76ri-lBC9 (+VV[yY} K\j ygᙬ-q<>!HDgr̞ki-Kklu]CUեX=>aM Ee*N̥y?F>ˤzޜ8deΫca |mv1 (zړEjx[]- ؈}-3QMneP̢9Z'u($% s#)%j--:;ʷk1 䍃`u(k!5/4 E%֔ }qjDXC#mdk|EԬ4zqx4u 67+f.Uc##7xS c ]Í;Rp6t\E%c[G36. ;}E|Smw|"͎k/kc;X$MvfElXLR=*?y3,_ߍh||-Cm浰b$aXHIayx2!@>Ң!i(ntkqx6-WQ-Pi~}{fJW ϳv-ȇc#NS¶K:tb&K/j JI2}P2~U㧏heMQKmm4Wp_kHle(iox|E#SiZ! +i͉Ri*`\>$#xXyj4QEQE(M+8_ʝ0J4<Sk_u >=UdtzmV[*-:X}* 0[v,K5RA_ڧe+u-:Qh=oc5&KP [f S8z_:dZ$W6wNՠux.񦕺+b5bPGi_ ӧei[IfլIwY >7?k]㧃r jK%PY5$ύR2J=ICʰ1˧]"))!gOQj&B!텰D;{KT/6=CISh6͔v}ں5%6^~8w:Ǵm짯׿gv_=OB_MSEq̆q#K#g̋߇Q{ ]vZANk?d9Ն-tDIL@ҋ ֿM_o xwO}jG}BL%}56Dy6+@Q54CAt,!a|CAE92F$n3y.ŗ֣j4z֦.+RnғI[UUPhM_[jxR˸Wо̶&4n,cN" eG/9/ujMk-2M"lO59 ir- nn#fTXD}i'?oAksqij?g:ơ$6ܬ,`OZEtW ^QZ &g^RAVv\sr>@DZ Soď s[f sMMREgq OjPΨ1hm/ kZڭƙx[j^l_KޞN,Wַp:G#Io&bM~/4KuŎHhnyy ^uM<:\çj[֫87ȶ;#h `ٔtşͧ|&ӼCN}b8[iZ/Z^&VfR'*V*?j]>@~"'Dޫi騲_-κ-2߽i)dFXe:n4 :Mo% ~nOۼ~qYSZޝMeФs_[iʶ6;;yxVE,aJ/n ^;EV[NA>|Rc[b4*K|Ƹ{iKGae+m#w-ii{p_`yR9!-n,Љ$FhUY'-%^>my-5,ZZk]̉t-UP7<_(f~_|keyyx7Tԯ., l.eP)]%S~?dVNup@t9t6tV&ė+7u_yNsğ k}7KouܝgT]yVGvڮnr ڒFy%V`c xsw?_F~]J[$mblq;Fp]HvD#yDۧ3\Oͪj irZ5١3vyqR~6 /:kc\X^yr\:WXk_%uxETƥ]jWWY_5ΟoiN5!KHeK3$_ f_>M25!Or[EıG%GPH߲t:K:n\Z_Z[fE:̍W,rJ]+_߶F5Ķֶ);bĖz<65(..!!͢Ex"9Gh9x/|%>!-}ZXoNь^ph|hEFidi}26tXDR;Gy{Wݮ S]<73,2M!}ꌻ2$Ѭd! : ཇM@Q,y.GwH]$kj=Q굍i\`k@A̯F E2I"_]-m}jW7 ɭj|K.$Z!n!=>|?̟?4mC]_Otmol1FUW_y?|uo[e-.YUxaE~j_KMu]ݎ}adDa#j}эx)9eO^/_>!o5ZiqOѵ]>kM`^֚D'Ciɣ>eF&/x5&O x3CwrO}/ #I-us6(pP~ǟUj 4[)ŭɻWDKr9'a 3@~iO#ԓKS{$k-Ƶw[I5VPJsfZmigkoa^&>[̱l Ru#T Z 2HtX ^`->/(i /!1C`GzcBŢx@&X`@5/OƖt wC uiaqjsJmls([; 19̻hbhKw <1L> Oh!+_xr-aoXkl3CJ gOWT6q֨m,%a|c h"q(W>[~\h^v >α&vp6,@vu0x9lxsxOCQKpe5 {u &X܄+B#B:? |a;,ޙ:ASc}ui 6$+t .0 1>A>v}nuq-!yTGhb˂s@7:>o_xmR{; mtm8ķY6n|uB- t93dO:k)ieɒ.IE6T@xĞլfӬses}^hV\Pa$\Dr0}/ol%};[.Ny6qߜ.-%CN [ @m=cG<&yn7/}bF4bmź{^")o-F ?š|7~x({kɂ)O^YO+ 쌝} s>fz~!VMNg$q;&@l۳ U"&Hә4.fwgUeO/ iwk.I;LU\ªKf ]ۥճʡєdFAt"_X4i~v֌E>`}UQB @(QEQEQEQE((jF1Y/NJ4_Jوo/,~>gw8ѭCZz]شS.n//| HUKnxĈʄ(ŭ_I_m>Wo!utҾ5 {ӭry,\ H+z_ҼIxz_$Cs[{Om5L[ڮ<*/! TW^wu_xuY,RosK}SձZT7sm%^F 7-t5Gx7ZtkrVkaϨܶ>;,'b(_!+O٧ş^!<5?WLk"SC ~~nkU}cF𞡮^OEmq\jmz%վKcu-s;FK?࿊_7~+>|M6'VF٬52G ZtwQO%z{]G失4$(Q>|hM7vԲ״M6}F}KC]^oӕ4L˨3iZ+woBmn?^#KkQ{49&3NS]ojht`lѣ6kgΥ: xtxe}AZf5˴V81|?Zd;/|9>(;\r+]l>E,i y%yDѕyM/_wY׈%nϮMeiO 5ݻMEm }!帗uWLE~t~hυ^1hzMc}w[ oC̹ye !0o*վ1~zYpjVIuGb,Vv :um8i&7nQy/ W'۞xmcDn=UM%q ;*i4h~qy(y.h9# Ghʚ,݄z顯& ䷆w|9PUoy;2W5 z>Σis 6ڦisI [$wȍw_X=#JYIdQ-42ʋ"7Uu  _ӣռIr-m溴G`- ̓ʈ@[$3! x;<3p,P]G,2zȎmar((u;[Km:a!츌R: uRy]ǁE6[$n bK$6M"R+.,zF.K}W#rQEVVsˢEvk)$m0è5@74{++8Y&`Ɗ2p5Vo)T!uKYe(pq '?088sWڥR6:+I6ew/ 285X%N1u܋[g0b דmaA9yD'$Pk1|CsO2$RȎ!2I<Ff嬲qqFBbMEPEPEr$׃<U[iMަhcec#A?E޹#"RVIcX͊H`HJS* 4(((to>Oo?\g6'xUNᶺ/ڋᗈ3~Ϟ,]5=n֑y[B1F{x79k^-{÷RY^E4,QЙ  |H)Ӭ+[0j%MR}"X\ȑ4a*T05}rڰ{:[o 25#!XFho /PEyoho-QOwi.AuhygaD3pONm|_tZ][xjW7~OZIhZE-ܖ1#[;țNDèxnϻ}GGMo-杨hPjOy1}Q$ XJ#-^}kľ ss4JOu{^{$dy0ǧ]c'ARM֛OMYṊk 'Xk&'O`nD H#O~߳y_V:\Ijw ˙ 4l5ߊn3W~^[zƯek y=qkjv1-%F9g[H,sV;vLF>k.u_ kZkKuK.tz{s5ù`xDe#,t"Z{uuF䳽%ˁeM2d ]o[cǀ>:Ot-6MmK SRI L|62s?뗿 M4ݬE&{DOO0^\iڂ\GUK/3s3pݫ3 /_k4&+}Xh֖C\@ĺqjm̩"/ A=fljkKᎋk0vxӬ.,Rip:hIb/ՌI_ 3ᇇK=vYk_O^;Zp$7>U~{~?'|gMGoE 6XͤP;Fhl7E+r@e^-'nZj%WkkRTM sqwd'މc?xO!nM1.$Cˤj+ ޝJo?Nt,B5/O@Vi y}Ide_f{LhSxOPxy|,=kbtߴ@Zvn\O䅆E#əXmRwN/!RI[X@%,dS=ϗ,-8~ZcǾ" t? +R±M$eGZ[MDҕUI7I)e?/?a _`1!(@ANiQ@ 8E U =3nw,C~>5QEQEQEQEQEQEQE((((((((((((((((((((((((((((((((((PK1GFY8Y83Data/mt-D4D90C95-2A35-4D4F-ACBD-6EE33763DB0C-78.jpgJFIFHHLExifMM*i 8Photoshop 3.08BIM8BIM%ُ B~ " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzC C   ?(((((((((KyNc`r=)pn/>CVQF@Uf4$;_l2Oқ&cA`HN4/YXwPiֺv<JvFhtnA8 EFdQ@=h QL)O(((((((((*#T&[$ʜU6Z Po]q;ndc*]N|ֵ/HӮuj;KKHYqYݛ dmj6"V&c E[*όO{0<3NbկQ-GԮCE d3:sf[SW٧eG98:V!"J#rʌ(^&_)=HCG`V)s$ !*.4TC`/xG>jk??q.RV\^Xa-E#ʢ5;G)55Zmom˫wxņHƿ/ؿ kM IԼFEgmov\JN89 ھ.i`y3ÙV6 Њh#bŷCy,Kb@#w=r_kczocsv=?zn뫫!a㹅^V.dO߱4]8iK(B;E&.  I\qE<_QYqi c_>}M`$nM`%N I+l[r܊߬ HW5\z`* ?((((((((+$U^Ǥk:l#)9ƴUQgq[P|o$`]Z_^$k-s8l|PI-&ilA>C 3)q_ x෼{-&&{ȗ{Hby98Ֆ?/X ӣ2pށ$# c8_<?< is9nlUG ?J1T\c*6Z/03Ė׶];Iu?e߈^HL>b0ݱQ;U^+3_ ]RAuqNkj-h>Wg&4> ;G?i%Eet9Ìc ~5{XK(E{Dn3r$<bi[P]e Ũ#E2TO\>?,xP#XnYT$vG>hՍϜpv+?i-nhS_/&A3\iDz66nI$Q,sG@4R/gֵ~ؚ/9-<#,yAq}cRF ď?ރswķWRj,U@%̲F!_?g3mgg/5 tOfϙ&C(;1[v9bbI<+Y8JX½;_V&.:yԧ?:tZ"0a9\G#G=t( !~Uu&Y4)?yӧB\cozO|CAW*'? poc"t5b[_^Nl~&g<=(((((((((+_~cbG&f_++k]7㿉|AA ox'zj5?>w*qQg7tLד23Pu9>ΑoFoxpy2[g5f|t ÞSN7OG<*rc$ŸuhS"RoK+- j8~1xK^s:UVh  ;`g~|g |7{w\}:HpQUI=Z9NKhJpI,=fM dHe(FA/+özޑwZ|/BڤZcUCġu w6g94-oD%vEPEPE7>h1x}a$nzV6p\Ks9nQ@Q@Q@~~<YWKx⟈;Z" {8 _/9<\渏gMK^Z?(< }i%ƅC2 hz'iMBB$B|@kO%k):T~hu, {b>Wӭ ,maf):Njַ7%Fx:}=o~}3xmΚ̬R|,_o\3Iw%3w = ,t~?uS?*C"ΜMR$9<7l0:6KmpI N;mS| u'Ԭf ̶#Ggkn1\u_:H[? ΋HdѧHiӚ:[i0pfO|Ě[ާa԰\z+D?4>!U.㯈SxbM9ʣ@%s$W||!tj~'ϫXG9R;4eNs~';;ˍB!%QrJ8}kt! u CvrI22FWFJ)5/M+O'[Bn} ~|h^x;PK»B0 \|',HY$z%nnaZuR/4 z}GZZ4H#5rNQȯ߿ +b<&XQ413HA'b#q8 _i5fo*G8 yzo|;j~b2S+_z:WfKN i!r70Zz#ƭ6֞(߈GKc&RҨ<ʵzX IQ^(+S 9!QҺ {N43SlO 8.7@퍒 rOR~Od]׳% C#⇃x_/:<7!H$Ine18 KM:6 Yo:_zĒj^֬{M/ΎZ_ 'tf %"#ƿ:o7?~k:Gg-Wڍm3Gg ګGk(xw~Gwx3U𮝯_k$uT7:ީy]?mfYY0~5?l t/Z_xW"_k~D:&-֗(v!ٿ#ji&ڥ{)moÚO>In&wP ]7 I=q+xk]QK]v_ ѥHt[e9WV_lC2g+񨣵#m"T~p]wJNj&~jϞ"@_y3Y\B5cxu5j5D"C,^EU}kK oQc?&/E5#h,8le &)6pYOErEyEN3oۻej5}ZZߌV#><_I|!|;mM'Óih_ :ӳ5Ol͔i<-go蚭t8=މ|C~U/o% nbe6yvfC_?i++Xn!{Ěo=ٺ:m͌7 [H&s6eJS;ͪi:ιC@t(-u 4(I0wW?hy0M"XMɧSaK6oG{{Yc{Ҝ:v[4Kie#أڎ=|w DŽ/~xX2Q/8̶vГo#P ~ x>8ab>=_/6ŭ'OIXhb!^6*vMU>$6cVP t}oW lƗ?5l̍y?cٟz G|?qmGqu"iWQh,ΥZxcp(U`-tMӞ"&m~eWk/u.WmOQR}T8.oFzkkW|q㿎^/˻ @z&+ɞ87CG˯閾yRë/xywW .|@.cF7;dIG ~]ҽE{QKwc|]㩼RK{lU~p37^İR:aEXTrTw;kmZR7]Byh1p࢞)?C*_^Q)RW@WgWSiz_c ysN׶?s|[+jMC7^lC$O \[Ҿ>iEu^Q{I(`pH.Nq^!w,O.쩃7Z[ݐkoh~/KE徏YIk o#C#ƹ ?r>c9`]LKU6WN mdoDM૫h8_3˩qm,nV$vWb8dkf/c>&u:~` 2Uȯo6~ּoWe{s opWJd+*55uz߅SnE#q?ZѼ1"$Toƾ{aR7-tfRq{q\FAHKMigis0:'簯:18h#ԣKZ^,Ⱖ_q翹+fO^ku|2|:_ڧ]FĞI`|b_~iы E$"Q^#.k?3acrRhK1¾?6ZMĖϕ';#]M>3mm4G]ϧ]&Μ%X=!w#\y-[ө-ukO B폇Q6PG6s2L(iBpE?[mw R5Vz_EPHWZX7ER28]iހ~W_xbIM]Q9%WU^vk)DQG n#5į,EaKkHUq8'5ne]sd|Y#9 ۖ9lG۪_KT%xo?|L<% t~+yAx"]{'m;!U=3^n6m\3MW w(k7rYam'6z`;u~+xMh3VRr#m,FF 9+ /|k"b~s~G5s wj6N\3-jmd| OQOR:}u4/(Dx^^E:əs3hA/nh$ Ğ3t':v>AB8H{Џ}#Ӯ.x~[gQ \fm.kkuR>bP> _7ڢtꎹ8#kѫ/7k`FHæMrԥ8Ju=.6Zw%>t:4),S3c8ͮq_y_C,Hg .l6Uq.JG`C (x((((((((+4w񮹣i~vG@q{n+sė{AA\G>_G煾%YyW5b-g$#Ic׫|TqsJ|Smb'D0}m)Ѯ.}"~\&"AQ3|.\v?m֤ {T奔f7(oٳ׺4㎬#!T~S^L~.к2 !W;߱uXtR^j68`V]ZYԉ^G$}w\Fk$p7R./Mj9f|,Z?$4}տԜ3_^1I!t4oh [{Ko,c?,[^#kRXVQd3-oM_1!%'VMGS߃(B2>_KwK0:?'5|0ozy!鶿:-9#Ks^d4d8^}?7kws zWwsUx.n .W>a3jzjѹxd89+Z‹AkvK= ϒX+tcNkc%pxra@;.\6^.^6Erk˅YSo!Fl3lEo$Fͳ3y x_W:D#Ρm<*e s~:?M[ wGw=~sT -sh FNN~q!4-lu?5 ״ Bb(_Z!pq_G>)I$Zz#i-k Ԑ[R=WW;es4ycT=6}CQAc/$ RxO?^V}'[K nC>[0C  Ƶ~"b?jQ6ل=0O_ as\~rq*srzbbE<_]糏1u*U]E^_D/o_3ZZf TՄV#$ThD,Bq c~xA ]KL)&xLJp|+K%&_l!UUuӲj?#qAv,ݴ(?((((((((+sкҾ#Cg':zo H~^%MNpWp_?Cҗ>>KZNHsUaka}\Ʃ[jp1pߏ_c_' ^-߆'po)5oOy9Ϟ=Ed빂VFa>|rb&y&>2 %ܕ?1u\ǟ½*஁KGDI Ђ~ fyw|%꿉}j݉ʛ$r=A8` F~;dZ2)x<U~&xֳax'7KG!:oOJOKf,?hev FJIvda"g +C]PKn?o&>#k?d|Pmj]n[}fJgp|In8*W~>?0>TJu5yd`UV## {ڿ|;*9So-ﯝ3`g"5~鿱+itp+O((((((((+;]?2>6_Ƿ B|}xzuA4x?zqԭ?Wf HL 9̀0RԜs^^nhT{ek}OqF)c~Vtvw|O<2BNA_o~ 3Y6&ĢId 0~?hV'K7kqmxXc"Vn95ow|TǝgĽ.sBEe;X'xYK|VN-[g3`=&IN_x~~|=ׇ`;H"w(exO1R9<_ ~-|}%|]EMJ"8V+I$d 8\FIB5eFN[~x *R䖞cg4]ly1T~!h1 # # ؎^_._8$' ˸`H& Gǿi:SoXc* Ӄ^s;yֲxAeF?_uvvp$\I(Y F9^v; p }?!,^\Q f'?"luhEݳrfcp{[mtXt 6qv@=0dWbρ|S dFդ“9ǤRN)Kd._=28̳F.Gʩss=|[zO uAEy>UX`91\ÿ$/Ɵ^W?vN jR(wHi&c^[EU$绒b R^_?O qo)Nռ9Vj?Yk_Ca$h~GżP#?_Q+kUGW3y_{ZsE?_z"W90_"?>|~.WV>gX?f%^|eUO5>C;Kw&#ofM#4d.|#mScZ%v^3J65T HYV#-|M}1o.iLEȬD(mF-:J3!4IRht-MaaAm,Efd~٨|1HbF62DV9@=ëx }l_xB]5{ii˵hm :]W>b$ƜO+M^麿5mo,7sCw!\,bHdG4V9-%[1Q I.NWfaixHx4eS?{KZO)bHr|?[{yXtӋfIj5 "R(­+X_ fOLY O7ڤ̍u߄;yʶ![x7Im6/Otx+O~ ׯK*IHӖne_fkI,O +$3mڿEEPEPEPEP((ޅj;7i,vc]e$3BYx \xÿR]:/ =1Cr_fMt,aYê8"fWP:NsXxIo+HVu9P3CH$ETyC۟ ω>JŢvmI匕ߒ}vW+lv=^ )3= ⟣L3LV(Mz<oWƶP<)kolv+If{Et Ŕ 'YlOޛ6/%]D+*!2 KnQI^!iv2I ӓIo1>\͝ۏ1ajEk++i?/Kt#4v-'nn&5ܧ9kv1ۯt [q&"Xep-)<?OV&P`b_N:ۼlu'*}5 .1a+8[V=gu~<Kvׁ<}xV l\Gi4ʇ˚"hY$+*3ǍxF}?5= OmV[ˉfyF{|$c"rn ?e/s ϟ&{+_ -RuXg^IB c٤_(;;Eu?N?dWWh?'˷3pwR<^$v#Y}cl\Gm?%Do쨍Q3"lozGaPov).d'1}T*l\[(}0+%4 EXX>?7<׿E=~~޾rNgrF2?gȯ cO!plc _!# &_y[/-z࣐mxf[.n?AVE~5Y_ ~)׵HkuxEE_ _.c_̳Ȁv?gRi})c􉇀8^}gnZωm0O>^9@ݱ6q5y_¶8s8ۜ1~~|W&d7 D2#l͑xt_WZ^٥]I&gR0(Mg~b+r]F&S%Ek$_ WWsq7U B>줶oD_kw? |uAv? Cw"x{M'S(mfL$a_a~¼Pxc [wOw%K]8e.I/yK} +?3Կ4}oO&8>Тo$,Yyn?@*QEQEQEQE(((`"u+$oFFc޾N[go%4+qґ'}޹/z>kt?ΓBhwҿ^_H!_rcqAC_T+gYA!a'4 GXX>%o}ѹ?m'WCq_m}ú?n?z\W_1wz3n CJG)0/'c zþ7EzAkz}qK*G`/}f?1E\W_׷w.;CK(TǨ?qW*'zzj _0z׸~?yI%|Ada??~YIJ,G3G _w~VPc 7y_* *ᯤ??"?T~l?^6_gDPyRQEQEQEQE((k?ڢ%al "XlhЙbvCv;e|px7? |UeiuAZy&'K[}[rc<"bD_Pź_Kw_Wڭv2 {]^(T1hXUv~ߖ]ݸh=3Ҿį࠭&ޞ+x3GO)/Ȼ ,%G=o4}^9ٟw fr:;/x~*V&[OۯPFNZn2Iێ2~LmCM5,U?~-/| iok xtߐ]t'v޿*?OӍmzWo/"?F/3_w WG`?!q6+ogJ?`?sOYp"a mUoJWI' 9$w5oݟĸ5G8)3_l ^()b??)_Hrpt]@HxOx{L?UTg(t +=(((((|W_OViZ2[549 p \=. ky70;@$74PȬ_d,*q?_ ;h~`ֺ}j\[ h"I]rpǽx~t{llOY h"`Z7Ö.:Gihvk5'`,7 V.yҾkJy+?ϢI-熚'n&ٌfIYp~?nYx́_K8HxE؏KIgGrm_Z>ھr留'WԿuQ{o_C8-nah$,Gm 1"ҸA}r/*rO>$~z}b7 7\}M~#gK(Wd##AU4?תC?R?+TO##m_p+Q[Z[=~ HN(BVg|E߇?K½7N#o$G~ z֗O_M,HFT!+Jۇh,ToJB/~ۿW_#־],?7P W_o>Ec??~Qīqٟ"oک?Կ~a:Ea!?~fKۦT8:py5k[m?*2YWĕ3/_T81/?^־Cjt4ְvOSfIV_)>ҏI^^*Eo (Y1@ky{(t +=((((((ucMw2,ay[$$Q)wc@U'wzV|ԯ47~;kς9`GY`X$Eha=R:׉Hu{-C3-\|;uN*F&YI*ґqۄ&l?QĿ)T{ſOD$]FO$޿By:*JQ?3Nɱppҕ)$.bt|DEk_·Gp_U`_7ܧ\/O==Ļ5g}F͵p=y?x7f-:?ZvrI K/L`Ǥį"#|*[GÚtеMcqmC%Ws`g'c???b|+eu:ag%Z3.%fڹ83<4HWH/gvcV Ig}C I~P_g>%M P>%yƫ q&[Ag3|gO~ $tcC_A?tYg~75k i1]Y)42Eg H#+2/>x46qk M?_QEEPEPEP((* [ki,#YaJ:8 0U8 /u i4K,Y@>ζ4OE#XrIPix|+_[NOo,*2/ v8<7ŭ2O:ׂOagztdQ%GYefzrd{gjM$Gfp : hղo2eryKw^qo5wƗs?i>X:< mh۝whIC͡R^2tD҅;-@ZTD rA˭G'Xm/ 1O"ӣUY]یF'FhoO\7HSBVxpcS)| q_4j_Jh'}ZhzCqaX4]IIbWR> Ci>֝-3m XP 'P2y4_0Һ!vZ+\_K ܚS&Ȗwc03_OW^&⽿R{:G [j`ᙒL1O͔o{6tkA>%Qʃ"5^x:_|9 hiҬ?q ps h?WyҮFщeDNÌq_~kGO׮<,7Vמm啴%{f0Pe2 ~_/ %|q#*3!YFUlIS5aִz&Ѵ*f|c义F t?-XPC++ 9TՍN<1KM6+X# $HP9s[x'g04he\61-1HH7L' Ǡξ1+Rn˫LO˹dIhIdTiz__HusX mn wA*D0B JAk/Qimĩ yimٴUQ1(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((PK1G63Data/mt-2FE216DF-9BE6-4769-9976-A6A5D75FCDF5-75.jpgJFIFHHLExifMM*i 8Photoshop 3.08BIM8BIM%ُ B~ " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzC C   ?(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((}oEׯ BK42J#M@BIrhR(((+#]m.Msu%DR1)v QQ u z( ( ( (OÞҤ|W[i1qw*C!TPҹEy~.|(~4 I. yHHݛz6pOAY.K\W++iX\*JAQ@Q@Q@Q@((+ ߲w ïHr 5ok:_tۍ[R{-/[xm-䐤Qp sXViN{)t_+tnQ}_E?k+O}|֣Ks,H% 71Mϙؼ~|_2|a.{obZÝ^q*&V8`vdr< B~,,> |JfMc[ kg[S#ezqD"?ێ-NNz;.6w\g wWEizY]$M[Y9*>8xPx~4#[`P]JH-.$[S+Jp2?o ~- C]^kݵD/R[ۻƆC+neeOq/n,QVVzouSk]x!+\I[ ~_OSYKZV_^ֳdWfig;M6V՞$>-/RkQ#[NPd2c\{:(qqqm$n|{+k>?k>񍟆kiđ:Noo$W1 sA G>x>9<_xjeo,ea%ɍXCHP3:6ITJOɴw-ZTUgJcRIIGIJ+w$j flY?lvn_޹J^j|7Y^Y\WPchVm5q 1OMd4ƽ'Ïz]?Ag}aowsi2Ao-SM*G#G0gTb8a'߄z~ò[Uwr1U.(F V|*'_zF[f!7Q5'?~':csweiͦlM-;8IWBr~ c(_M'[;St=jId-ե7,Rym 0g?P WωD Um [ZGTC_ݘ.ŰCJbyU'k =co?x7 G|}^h/Ķ tݶk$p蛤bcBtv]U %nO^gxnUe^wPʽYk ?[ _> w}muC-Ŵ%2[n7i 'MF6i+uȚm[l9UHYY[wm7䬯'tQD|B%~G^VC5 G\8ȑ[U0( ?6RTf>Yq𾭭|jNUY5j"\=./4x+O>ynl쨍+d~B|Tk~ wG|:OJ[yui5K+hDeIvF+菉Wo#x)>2/I>o  {'y%f}7G8OF?h?$DŽdߌ֫& |Kջj7/56ٌs]o[mxQ pthvqnm2UeEj:^҄u,/߂OOKࠟ xxCWU:{iewmym FbJa;aۛ߳'Bg/ohfZl6wTK4 TG,k'टR< W>i$]}s)Ciiצ Ine)1. aa~οG>x <)xZ~#OE5l9k[1]Ȅ#ju)5*n<ۭeOM{;ײ\~mFj޷Y' iۻqğP/zK=[w|!\jVt[K;kha7XS %G0~>95Oiu&%j+K#;g@%2F Fۇi>'$#o>.g¯N%ϭk M>M;N0\64Ks-MpN_#G+^{CFh kwm'+l dv=)tJ} 5iuA'a uW}M慴?MQEQE(((((((Yy_+}}u='}ӫľZeHa_ꟶ&:*a|Q9[[f^io*,N|aqNaXV\һ}_b JJZ?+pj'5Bo(,բjwwJc2K( Vl$}~Yk>ot;=[S4(RiIcǣQ{VKj#DW%N?><<;?4s{DK<ڝS|42X3 왅)w ((tkѶzl+MkEhK|Eoߺ>3M[ %Wޑ5ŮvzU坻jWd97^cV^ݷL3Ex 5hZOϡ{5صks[yH4S Vwvʗ8.h-~Ʈmn^ޏ +㏋?!;66^ѣA.Vs{Ub$lyq>hx%i_obN+t"g[6DIp,cFDN5jr-v{[oߩ043/SVkT}օ6R3k?0iȾI~倬M ܉Y*TIQ{QPPQEQEQEQEQE(((((()UdpyR@ tYAI g=)PTլuBeLm!c29ler?*}0x<Ө@@cOs((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((PKd[Ja3Data/mt-CB0B9C4B-E625-48A5-90C9-DBB6CBDBAA58-86.jpgJFIFHH@ExifMM*i 8Photoshop 3.08BIM8BIM%ُ B~4ICC_PROFILE$applmntrRGB XYZ   9acspAPPLAPPL-applgFKDnu descecprtd#wtptrXYZgXYZbXYZrTRC chad,bTRC gTRC desc Display P3textCopyright Apple Inc., 2015XYZ QXYZ =XYZ J7 XYZ (8 ȹparaff P sf32 B&n " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzC C   ?(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((!X|<$~ hں 厃svzV760Lϼf462wweO6I/7}?ɴWh |G3Ş;Nt3JK'^%H42Qcw#:~*>? ku"}ZM5E7u_-j^?$2(m-]6K6&k_t}E~bm|E޹ixouceg > $ cH07;(/:?ݡxFJomiympDE%Aj)?(EN(K/W۫S&_fm+_w?4Oߊ|[ ȖͮlN8 ieuU$b^'Ci0.Ρi-\M,w%eurԍ6$hig8nҺWꢛjɟtW3K~:Kxz[׮wExnT|_gȲDnĄ6/?\|K-=UZiMͮ!A~*дxSRet^kk T"S P~_|M-K't~O$WwW:֡kD1y;2cwv։^wϕ{mfZںW?bK'Cş/ VIf5}fm>q$i}-Bp$eпjxGcHYm.UYb&ԩ.d "ȳ%pe ȩq5 SM?4BvO_zi4KExg]i$>BDsO&(c>! ĜtV{)QEQE(((+>(({Ojjk ʡwHn-KM$O9bt zXy3!i:mv!Z1 ,uk#+#@B8`GL/'+a֢WKH.A_X#wZB UXP]実[K_֋>KkX|! FKcRh.IMMd&Y^䙭ٌ*H z/~'Ş=Ϗ5H HdwǦPoZ +w~T0G۾8}"kt;_'?HFD,#FS7jWiA EBퟆ%\ִ Bd,4{{kˏ: K9\C #32l3݉-io_4>>?u{潶vP n#Ĭ0F~| gg/m}FWJvwutZ&&Y~K~ZzhyW 1|L-wS]^^-̧I%W~~? ~^k 7_l]6vv#I2 !2Hj(RkniO$O*~}ug| c|lkV.[M,1_58{m-XcXuIOk߰ӯ}ӵ}&}.[{݈x^$O,+K!~?OOm?g:1/l-{mk˙dRK,$Ͻ{;[[}E+|,I)ß^ _ݢ [O]}j3##nї~x _ ZZGa w*b$쨫Y(:i}n^&[;kpmqf.V9 Tf"ty=k|ۙ[kgM__ <)7/ U{fTG' Ϊ2Ms^%[×%c=>{a"Gr lQDlNg#:?f?4lAT|RmZۧIkVÞj6&i6?j|Ax[K\=e Q%ԫ J]rnbdHkflY?lvn_޹J^j|7Y^Y\WPchVm5q 1OMd4ƷGTm+imEnu%ϹaE~EPߏ?kG/-zޭa6=I6(hY$g^WE FZ]˛O O7 4ko|CNY]%jVhVwpڬIl$F'y\=v^_/[;^Pwn_}?a[_c +>xE<-_k^8үn_I[iks$A15 T_>+~?c˭+_o5Ui$fGĢ mHdΌ\ڵtkk;M7R$ͨwխ7WM>袿j+gOG/ |2__|uiD:[ˮI4yUËY|_-# .–`y_/)wGog Ʃ.4Z[œ\-%xN8L1nʈ۲BjTE^m%ԣinƚq(~IkEsOÞҤ|W[i1qw*C!TWa~-c ׆]yR{M/i"^_z^Lsυ/F?:DO! qCOB%Ə5{uҼI6Ck[ĐJ@J1\:_ W *ͬjiM /RHRg i%n87,M^NJnZH'[|Iîxv +Ŵ,R.qt%Xdc OۧeÿPOzGm Y!ϪzGOeHx匱 0ߝoٓ s!~ο7zUտY?tk-6WRu;*c HF#5hI[n查ﲻm%rbmv'oFQ_?nڧ¿Ɠ@/Ko!qZi[[Qom,99c,C)L7%RCx=:]Zܬ , *n Q\k^7kV붢{9>/W_tQEdEPEP((+ ?|<[FVsgMյ'k^I E7R5EgRqi/J_IYE%(Iw5~O儺]j?u{K8 īUX=ۥT@X+ ;_{%+Ś5nǂ|3y+ҵmNCwdyMcn8hWtӺumMY6vOM}j0yS|'E7~(~+|A+=7l:)5ۈmo6~|iwGb[;Q^S1\'}_>zN=z>W&5a ƍ#@ΪNXE_JsqkjZwkn%Ƣn3OZއ?-_~}3gb;YZRd[$TF6`ΨA qS O?& Cdti.KmOcH\QI+ʊ M/.ov)߄TK_1dU'ýsF/[xVV4Af l$ҘFUbþ,xG[^ }¾'iW &-Co],7m 3\:&*j'5Bo(,բjwwJc2K( Vl$}gB P[w^*zkM$KJJ'K_q}vI"3_?gVZnynniĺ ]vvx!,>c5ω$~U-|sǞ)wƯxTk _ k>6)n-.aݤqH_&ԓ[Y^%]' ~?| >*|G5k~;xJx`Gxl%FXl׍;i#942mڿ?/_Z_g ^Y ºRJRDB:%{E*-M| f0So'r?",~Ij?[ڀ(MkAGI ܕC%bʄ3 u@վxO^ׇ~#x+^3jړizݵil$"wtS_Sv6%:jI|q*4($v:bC.Htckq ׷~2wVg۳t{oLxGM j~h'Ļ? [x{mRXm5vׅH'2pW];vRVf$iu"'Zkt~qirZ5'I?)'Ǐ|8w>Ϛw/%|gxz}o\iiuᶁ[moKr|cX~_Qc$5 x?𖟦'Moi$]}s)iiצ Ine)1. h߅K߂~(hau;y-nmA2RPG~QU KwvJRwedޗ(AEPEP((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((PK1G㞉3Data/mt-193E61BB-74D9-4ED3-B8E9-13631E84744D-77.jpgJFIFHHLExifMM*i 8Photoshop 3.08BIM8BIM%ُ B~ " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzC C   ?((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((Pk? ~ 4o~,Ү5^6].5l"̌J ` NI4i/{9tI袊`QEQEQ_!ݿa{?kOt2Xؼq)o*ҕA'j)(-Ize1oD}yE5rT (Q@W퓥"mGsGt.[hn.ou쭐Iw$P2Ƞ$Dki|I}$+hQ_?g_ \|R?d6mv M6ذ]Z"̓Hl`|7oO uH5x KL-[|76Qa3]P hkӾn'vtvTS!#;>hi߲?j/ w:.;exžcF'MK~7ϧ(@QEQEQE((+ &/+$ٺ/ 7 x#ƉZ|ExO֤XH.;诡 f6"(9 ucU>jrJN- dR_7Ͻ5_߇?5ۯx>!y<=_G~jW:em\[YgS$Ĵq|'^ti:k Xmom4>YIwkۥ̾CMdܦI.^~ؿxO E῏ e|;VKGR&nA9-!(d کҼwu{I;5oxjoZZyggd{1~ ??O(е㟇~)wn4}C]'iD3F2[YKj{XQ8`E[8^}3EO%//"Kk:'ۯA{iwݙ#nR.Җj'?~՚gVSh#^мCA$ya'iYu!hQoUGE.g);/z^˕J[Kt#$t|NU\n-s jG:Z_ #FW=֧}}SLekˋ[w9!-)(1uef{k\̗ݏwYSǶ߉^_kf_Lb~=}z.UHl^Noq&6mwej!E)}i7⤹n2Iss=GVjtB\U%Ϟ*QV~k~(_J]:kh5TӣPYi 9|Dn6|kӿDįe}?$>G!ּ)MiغOڼ?d-~w??of'ڋ um@ Co.g`i%AUe%hݕKtKgodw'Ag)3+ {׊4j:TZvuX١)1YbYej?w u'\|?[hⶻ-g..IḌMCvHˇ 8M?m|JYO1O4}bFM[IQ[)ຕdeluud&#_oo+s7ei?Zlk,ux RdcU.Kq[s^UWVգe%DZJn²6v[]k/+ mOf_ڛMմ~+_mIilu_L5_(˺FUk_XZ}{u>u,v]j&gh3cUT`k_ga,vOHo hӄ(8_v?iZCᦫ YxgF~T{[ Vt#̒)Urwl%IhuQ%e&v^IET"'KD߼jj?_:x??A]Fo<-jfuƍoCHg['UhIs+Q2+;>9j& &GKϬ)vVZTѕwrBBX&H?\|*&|@O⿌9GRnc˩L5dE(2~{x|y-w/k_b/i>Oykwv͛F F1U54ӋMWO~cJNI꓌|QjѭO̯ᧆb+ύbڧIZ>j:wO-?hdUp.o|:ԒξǶ w}7Y{C*Iu3xnXD1!W~(g{^|?ִh%4 +CYͪȭ$JeAW^nT(9wk9->[kcjP2F/C\跖A"ܬ%H8QX~ٚ jx7KImsOr.Q%M̭N^:'?d[Ɵ<XYǩCgc%iw,lLh. !I]^>{)k$,\U:k]]J~ΞWwӥNWvѨ42?>>"UzW_ZޱMԼ?bc>-*-$ Je>>4<?o^˦ڵnba߆12Ud_?`?nTLJ 6z^MG|u&O~*]J>xK[5M~LԼ?bcqu=ʦK{@IFBJ_o7쩭韲7?n_ck{_/;JtV3J` 7y_1 6~[pT⧎<=]^44?Z>_淴k彺K"&0Bo/.W$xX[>$ Fm$y G7o:ҫj^dsT{NɊRNK_%}-M>+AEPEP(((((((ۙEB)9#=qҦ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((PK1G?3Bu3Data/st-615F7CD4-E262-41F7-8138-806EC6AB1FAB-74.jpgJFIFHHLExifMM*i 8Photoshop 3.08BIM8BIM%ُ B~ " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzC C   ?(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((PK9LLQ3R  Index/Document.iwaR)% "  * !   "en_US: Jja_JPP`x 1677.10 gregorianlatn"January"February"March"April"May"June"July"August" September"October"November"December*January*February*March*Ab*b*bly*Aub* b*O b*Noveb*D bL2Jan2Feb2Mar2Apr y2Junhl2Aug2Sep2Oct2Nov2Dec:<:<:<:< y:<l:<:<:<:<:<,BSundayBMoTues Wedn Thur Fri$SaturdayJ @J @J@J@J@J @J@RSunRMonRTueRWedRThuRFriRSatZSunZ#Z#Z#Z#Z#Z#LbAMjPMrJrFrMrAJ`ArSrOrNrDzJzFzMzAJpAzSzOzNzDSMTW F MTW FL 1st quarter 2nd3r.4th2828.8.8Q123423@4BCAD Before Christ Anno DominiM/d/yyMMM d, y M $EEEE, M,h:mm a  :ss a   zUzzz.,.,+-E%‰+∞NaN #,##0.####E0#,##0% ¤ L00USD AUDA$ DBRLR$ CADC, CNYCN¥EUR€4GBP£HKDHK AILS&IN33JPY LKRW&&MXNMX @NZDNZ TW T$  VND? XAFFCFAMXCDEC (XOF, XPFCFPFLXXX¤en" *!2 @JApplication/White/Standardb px    dXT>   H*   " D@D* @HQ@Y@x L @( # $7"   L* 2 08@R CHCp  ſ**/!!!!!//////// 2 White" R?%?-?5?`RC]]?%^?-`?5?`R '?%*?-*)?5?`RX>%.l>-h>5?`R!%-.h2 `4ݐ>%"'?-7Wz?.408<%>-z@20r=%H>-֬24{2%>-X >.N0X^>%??-q20R3%l?- /,243=%%>-Q=.N0G<%0E>-20'Yv?% T?- 2N0C]?%2>?-., 20C?%?-x2N0#?%V>-20`t?%x?-N20@_?%>-20*>?%>-zSA24?%>-<.0Dl?%P>-f20r5I?%>-]244?%0=-$;.N0>%Vh<-Eq240Ϋ3?%">-Xlb20R>%0z|>- 20&>%4pH>-H20|Hn>%=-< ^\$ V|AA? &Ra& *˖@2`RtB`R`,+a|?%aa?-UB`0>?%B?-U&1`0wp?%1?-S:2 Rp`0{?%X>-Sb`Rh`0|,?%>-ss2Q:B R`^`JHA>04%o?-W}^ ?`h C2@J,0<>%>--,hL04%5 Q?- A~L?-,:LA4%0a?-,>5F 0E?%5?-^L0 ?-!=5(FL0A?%>-L^LƘ)>-aj0/?%>-HJL0k?%FY>-d%>- ,!0/a2B@ ?08z141 @ 1 bA 1b1@ 6~]p*? -A(08R y818i8(>;rp - 8J 1>%a=3A .=>% ""*(2:BLJ/  ! m |/B4/     !\ / /< $666B202E-F9BB-4CA4-B8B2-C09B05ADD8EC*28.4 x*   0"                      *......% 9*F, g aa2:BJRZ`j/rzq ......<<<<<:/A/A/////(E/0.....:/F,1A/U/A/A/A/A/U/`jA/A/E/E/E/E/E/E/E/E/E/E/E/E/E/E/E/E/E/U/®:/A/A///// M/(....B/F,F/ʁ^A/A/A/A/U/ `z/E/E/E/E//E/E/E/E/J/:/A/A///// ͍(....BF,Q/ٍA/A/A/A/A/U/`j}fE/E/E/E/E/^^^^^E/E/E/E/U/®:/A/A///// M/(....B/F,Z/A/A/A/A/U/ `z/E/E/E/E//E/E/E/E/^/:/A/A/////(0.....:F,Q/ˁ^A/A/A/A/U/`jˁ^E/E/E/E/E/^^^^^E/. E/E/U/® LG' <*:!4(("*!R:RS|HS0 JE*82L:*o-[B6/% L:(("*L:0bER6n/6 J>بL:M.ɦ0IyX J>L:bϳNѠ?S FAuؘ*4L:BNuc0@1#[pb '"rz$2K.y*yK*u| 'ov_ 2Lj_Lb_z_ 2Mj_Mb_~_ 2Nj_Nb_~_ 2Oj_Ob_~_ 2Pj_Pb_~_ 2Qj_Qb_~_ 2Rj_Rb_~_ 2Sj_Sb_ z 2V2!6WVb_~_ 2UaWj_Ub_~_ 2JaWj_JZ_  ", ?PKKLQG2Index/MasterSlide-9.iwaU.)"  -*  "20B. Transitionnone?) X0X໺4*2: : XR!タイトル & サブ.h ^Lorem Ipsum DolorDonec quis nunc4WR%@d"  "   "    *..   L  BC $NDC%!g%@A-?0(8R.Z.`hh*bKT ]V m:C 0C >D5I"X0.  2 )OpO*  Title Text* [02 :Pr $ W2..R=B!.-JBB6Bn!! 225 *))D2 2WRI1% %& I AM4..  56B@DNB96b!6.Z)6=;Kf; "5; B6;BN;5!Y"02>2 )OpO*  Title Text* [2 A :Pr $ W2..R!=!1J³:r!! 225*5(66rA(Q(6Z5mA(A( 22.C*mu2..:C6i%-r!16 Kj:r!! 22:q5v DaC ,D D@D  PKKLQuʤ  Index/MasterSlide-6.iwaU.)"  -*  "31B/ Transitionnone?) \0X։*2: Rタイトル(中央) ^Lorem Ipsum DolorDonec quis nunc,WR%-d"  "   "    */.   L  B~C $NDC%!T%@A-?0(8R.Z/`hh*bKT ]V m:C 0C >D5I"\0/  .. )OpO*  Title Text* [02 :Pr $ W2//R=B/Z/-JBB6Bn!! :25 *)D2 2WRI1% %& I AM4..  16BU C!6.Z)6B;C;C6;CN;5!"02>2 )OpO*  Title Text* [2 A :Pr $ W2..NCU!1F6J1!! 225 *1)D5"X0.  2 )OpO*  Title Text* [02 :Pr $ W2..RMC5F!.f6j!! 225 *)(a\E(ND(A(V(Kf "y 6(j(A(A( 22.C*mu2..:C 6Daω% ~!12KjE =B6Bn!! 22:ñ5v  aB DC  PKKLQ߹A!!Index/MasterSlide-3.iwaU.)"  -*  "31B/ Transitionnone?) \0X*2: : Rタイトル & 箇条書き ZLorem Ipsum DolorMaecenas aliquam ma Fligula nostra, taciti. Sociis mauris in integer, a dolor netus non dui Xlet, sagittis felis sodales, 5sW ^osqu Esemper aenean suspendisse El eu libero cras`rdum at eget habitasse mayleoDpcipit nec amet elementum!4WRE8d"  "   "    *..   L  B B ZD*C%A_%@A-?0(8R.Z.`hh*bKT ]  m:*C 0*C >D5"X0.  2 )OpO*  Title Text* [02 :Pr $ W2..RMC5F!.f6j!! 225 *!)(C\E( (A(V(Kf "y 6(j(A(A( 22.C*iu2..:C 6Daω% ~!1Kjȡ=B6Bn!! 22:ñ5v  aB DC  PKKLQ60Index/MasterSlide-5.iwaX0+"  -*  "31B/ Transitionnone?) h0X*2:xR$タイトル、箇条書き像 Media ^Lorem Ipsum DolorMaecenas aliquam ma D2 2WRI1% %& I AM4..  56B BZD*!6.Z)6=;Kf; "9; *6;J;5!t"02>2 )OpO*  Title Text* [2 A :Pr $ W2..RMeE!!VKf"=Aqj1!! 225 *G)iJJIndex/MasterSlide-8.iwaFU.)"  -*  "31B/ Transitionnone?) \0X޹*2:R 箇条書き ^lMaecenas aliquam mIligula nostra, accumsan taciti. Sociis mauris in integer, a dolor non dui [Cet feugiat augue imperdiet laoreet Sagittis felis sodales, dolor socpH El eu libero cras [rdum at eget habitasse elementum est, pede class Wisi mattis leo suscipit nec amet, nisl fer B$tempor ac ! nbifend!$venenatis,( vestibulum Din hamenaeos A,WREd"  "   "    *//   L  BB ZDD%A%@A-?0(8R/Z/`hh*bKT ]  m:D 0D >D5"X0/  2 )O *aT NBody Level One Two2hre2 Four.! Five*    / ?2(  /?: EPr7 $ W(2(//R( ](*C(A(/j(*C(*C6(*Cn(A(A( 22U(O*I', Title Text*1255~2//>Cu !VKf "y ! 022.C*-5ҧ2//:C 6D% ~!12Kjȡ=B6ZBnZ!! 22:qZ5N  <  PKKLQi3N Index/MasterSlide-7.iwa[4/"  -*  "31B/ Transitionnone?) h0Xҙ*2:R画像(3 点) Media-27  . \1 ^(8ID%N0}"   "      *..2 L  DLC C4C%!Z%@A-?0(8R.Z.`h"C8*8J DtZ b .  2B= Җ.. @@@C^R.h*b.FT !1 h6C 0>D2 2I,..2 5"D0BC="r.Z%"QC *M @uDZ b E22B.Q A5>!2n2 2I,.. 2 U;E kD*D.Z%"UC* DA bE22 B  ..AU.n>DD2N2 2WRֱ *  4..  56B EZD*:.Z)6=;Kf; "? *6?J;5x"02>2 )OpO*  Title Text* [2 :Pr $ W2..RMCA%6!j6j!! 225 *6 )(aeNaaA(V(Kf "y :Dn(A(A( 22.C*mu2..:C 6Da4 %j !!12KjE =B6Bn!! 22:>v H $- 8DaC   @[C  PKKLQ>g~ccIndex/MasterSlide-10.iwa_[2 -"  -*   "31B/ Transitionnone?) h0X* 2 :x R引用  Text-1& X   ^( w8 S N%# "!#!,$  "    t*//  L  BC $NDB%!<( d@A-?0(8R/Z/`h+$h*b.KT V m:B 0B >D5I "P0/  2 -EX* –Johnny Appleseed* 2 : wPr ( S 1//F=X!/-FX³X:Xr!%22. x*53“こiを入力してください。”* -W Ri"  e  i iam(// .B Ba $ZD*C!12Kf "y *C6*Cn! 022. O*5 Title r5ֳ2//RMe%6!j6j@!! 22 B *፩C(heDA(V(Kf "y D6Dn(A(A( 22.C*ju23:UW2//:C 6D !1: jE =:\r\!! 22:ñ5v   *aD DC  PKKLQxIndex/MasterSlide.iwaX0 +"  -*   "31B/ Transitionnone?) O0X礲* 2 : R写真  Media   V( 0I D%0}"   "      d*// 2 L  !8 DHD% %@A-?0(8R/Z/`h" C* 8JbV|DZ b /  2B = Җ//B@^R h*b FT d ":@D 0@D >D2 2W RI1% %& I AM4//  56!6 BZD*C!6!6)6=;Kf; "9; *C6;*CN;5M4 " 02>2  )OO*  Title Text* 2 A :Pr $ W2//RMC5!j6J1!! 22 1 *)(aeNabaA(V(Kf "y :RQ(A(A( 22.C*mu2//:C 6Da0 !!12KjE =B6Bn!! 22:ñ5ʧ  D<  PKKLQw Index/MasterSlide-4.iwaU. )"  -*   "31B/ Transitionnone?) 0Xۊ* 2 R空白   ZP W Rd"  "   "    m*..   L  B B ZD*C% %@A-?0(8R.Z.`hh*b KT ]  m:*C 0*C >D5 "X0.  2  )OpO*  Title Text* [02 :Pr $ W2..RMC5F.Zj6j!! 22 5 *a)(ae NDDA(V(Kf "y D6Dn(A(A( 22.C*mu2..:C 6Daω% ~!12KjE =B6Bn!! 22:ñ5v   <  PK9LLQ[Index/Slide-4207.iwaR+ &l"  -*"  "20B. Transitionnone?) I?0XV* 2 :"   ""' l"  N"   "      *R///+"-+1"+"//////)**+++ L  k`CC ^DC% %@A-?0(8R/Z/`h Γ[ DA"(: i/shamlit v2.13.0 erubi 1.9.0 slim v4.1.0 faml v0.8.1 haml v5.2.07 3333c3A 3333# A ffffr A iA ffff5@" ( $C7E56805-7B01-4FD7-AAB5-3822BA2E2B70( $A1CD2A32-7CF2-46FE-92BF-1FD5E020E09A( $5F618879-6816-424A-9432-BA8E90701B43( $4ECDABA8-0674-484B-BBD7-84D0E2BA4E0E( $D61FD43E-710C-46C6-BB40-9936701501DA( $0D816FF6-51B6-48BB-8C48-E686CE25F92CJ/R-Z+b"j+jr1r"z+"8////// )**++  *  >/  2W Rime em ai@//   LeXB B ZD*C$/Z/`ha$h*b.KT    m:*C 0*C >D5 "02>2  )O@C* * O2 :Pr $ W2//RMC5:!j6j!! 22: 6N~2//:C 6D!I N!12NKfNayN B6NBn!! 22 uN S* %uUNJq` v  mP  "decimal!i   0 *  .[ >*N^PKGLLQŸAIndex/ViewState.iwa!*2 22 h* 22222%0A* 0Z2`m?uz " (08@ A?|BC `D@DFC ,C <2>Ch22  2        ( ,HP2  1T w=%>-m{?5` %@-@=EAM UAXb^Fj4>%X?-> `r0#y?%L>-zP|?%`P?-j<>5?`PKKLQPm=PPIndex/CalculationEngine.iwaLe& !"  *// /   ( 0JH"*," *R2,"R*RBJ h  諨 (ŲD " *:2"j$W      7b< 蛊UӨY(2/2/ *en_US0ɽ:IǕ]ARAmerica/Los_Angelesjr/:O/ */ " 2*2 "*::,!8JB,.J RbxPj /rz/ Ev " /  ^R: ::B" NjG D*     f! 1)  )VwPK^0GN.!Index/AnnotationAuthorStorage.iwa<  PKGLLQA%iiIndex/DocumentStylesheet.iwa_0 ]"'  "///////2"))////*///-  !!!!!!///!!!!!/////////                       -    ! (' * + (- . / /+ $captions-0-shapestyle-Object Ca /) "r-\Title/ character- R hyperlinkM >" null? ht-0-categoryaxis_0 0hart  -0-legendL $paragraphSNn!1Y:B1r"Dr"2nf3r"4r"5r"6n2n!n!n!n!n!7n!8n!$9 Q8,referenceLinI7  serieINAN!RN!JN!BN!: valueu7Zyr1Fr}r1-_ }r1yr=[1>0a/n!y BBern"Dr"2r"!r"!r"!Bnn!n!n!aPn!aPn!aPn!aPyP1JPyP1.P]!N!RN!JN!BN!:}41:PZ}P2FP2uP2yP]B2NPn!]BBePr"Dr"!wr"3r"!r"!r"Ann!n!n!n!n!arn!arn!ar}r2Jr}r2.rNAN!RN!JN!BN!:2:rZ3Fr}r3ur}r3yr=[3Nrn!]BBerr"Dr"!wr"!r"4r"!nn!n!n!n!aPn!aPn!aPn!aP}P3JP]3.PN!N!RN!JN!BN!:}43:PZ}P4FP}P4uP}P4yP=[4NPn!]BBePr"Dr"!wr"!r"!r"5Z nn!n!n!n!aPn!aPn!aPn!aP}P4JP]4.PN!N!RN!JN!BN!:}44:PZ}P5-B}P5uP}P5yP=[5NPn!]BBePr"Dr"!wr"!nCn!Bn!!n!!n!6n!a n!a n!a } 5J ]5. N!N!RN!JN!BN!:]5: ZL% drawingline-0-0/ equa-0-imag- >16626364656  &Z 1626364656 movi!>1w1626364656not listEA "722732Idefaul%2"::::: lid1a .j  -10- 7 16 S2:n36465666768696 ,stickyCommen21( !v'-!*{*****2f/2ɒ*~/! >zee tabla A-1626364656(Cell-0-body. footerRow#$ .#,headerColumn&BI &I:12:A1F:1 d6BIB622:A2F:2 d6BIB:32:A3F:3 d6BIB:42:A4F:4 d6BIB:52:A5F:5 d6BIBVENama2:q::::\texS"X-CircledNumber!' B'4HiraganaDecima"!2 +B) Ideo$icJapanese4V]Katak2]!, %B]) Iroh!e>Non" "  p~L-.  $1=Bulle &  ND A  (0>)C  Re * # +* S& 5. ' ,*>F, #  0* 0 Quot!* % -E--7n--8n--9n-!* -I u  * a  * A .  .*  A*&%%U.          .% +/%+   +% ('//P         * *0:&drop-capBa/ ("JJJJxJ: /Bi 1' - &*&:q.Tex/,//X' i1,*/  +'T* PZ  %-5 `QV,?`? 1@2'5 FKN7"/nX(C@ --@08*PZ2 @z@H@%R/4!D/-,"   + /" .e2* = :()?7Z @A*p ,KakuProN-W3:RW!;(@PX`hu!3}( ,DZvDbf.%B(=`@HP] $jpx %{L  -4 $ なしk) )QX>em-mAm mX Cr AN?*y,*/  )-+)/q/4/}ؖ< mB)>b m83 + リンクf-)WZX.C% #R-; ' Z-0eɨ8w?%{?-t?5HJB >(8MOeG rdFd^ ]i o:>$9$ȡ -i 6/1`%` D< Fill Center F?]???"R->G1 8@J 7, ApAA( Direcal Key @?fR4(GdH  %Right LBſ1x Lef =f-:( Medium Top LrR?23:A3@A3B=  %I Highbht?9ll11lZl -oZnL8B +@ -K?08  R = ca"6}_1FZRoZxxmm.mmF ZmRdZmv !a    6 92B+? F93>94AR95ޜV)96>. F ^ $?%?-ҧ  o1$ : R5F ^R-қB ? -ff>K*KR. fR" ,A*GillSans&RҔ///r/.F^zRzVzR//5F6j6).7 "+!..l681lf6R[e Ve R.91u^ RZytU  } ^U%JY v@@ƴ 3   BV( 6 */  1 @@L*9D8"v61\S02 Marble+:2  B2  J2  R2( Z^\$20ݐ>%"'?-7Wz,"(? &08<%>-z@&*#'$ *˖@b`z`j`z`z`z`azaa~aD      34r 4 ? + 22np d222 @@ z2(d pz4hX>%8>-h> 2t TRB|!T T^!" ^T6$" TP.P TP.P T. T. T^7R@zn~nnnx1i 0_>%0:>-bΐ T^t T T.)P^TP&  v; vC>%+D0*W 2 ~ " > > > > 2 0X^>%??-q5 0R3%l?- /,& `J`2 `J`2 `J`6 aJa6 aJa  0>%:>-:}S6'C n ^?Ο  ^T6 P.P n . n ^ ^w  ^Yt n . ^T 0?%,s?-O j @r.# > > > > 2 ,`|?%߲a?-.q 64>?%?-=& `J`2 `J`2 `J`6 aJa6 aJa  0>%Ԧ>-6'  ^?Ο  ^T6 P.P n . n ^ ^w  ^Yt n . ^T x %d?-S/ j Ԃ - > > > > 2 0p?%(?-0*q 60=_?%>-& `J`2 `J`2 `J`6 aJa6 aJa  0=>%`>-%6'  ^?Ο  ^T6 P.P n . n ^ ^w  ^Yt n . ^T   ?-*W j Ղ 7 > > > > 2 0{?%ؒ>-y@.2"4/I?%p>-j<.`J`2 `J`2 `J`6 aJa6 aJa  $ҘJ>%J>-yS6'  ^?Ο  ^T6 P.P n . n ^ ^w  ^Yt n . ^T  X>-Ɩ.} \.f\.ւ A > > > > 2 0"?%ҷ>-l2.v02 0>%Q|>-&.`J`2 `J`2 `J`6 aJa6 aJa  ^/56'  ^?Ο  ^T6 P.P n . n ^ ^w  ^Yt n . ^T 03/?%x>-e*W j  mp NE? Ejp.jp8~um#z p*twwo~pu?]?%)q=n?MEvww]rhpvvhp&q^a"W;aaa6afrq6a`9a*/s>Q6/s0$9?%*9?-!96]c|^/sd.dB/sj]fr/s+N/s1t1`/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s zR/s1; /sz/sZ*(p/s/s/s/sn/s.laBlP8/s/s/s/s/s"/s&t/sFFQcQc]]]&]0m1mu "^aaaa>a.tFF.v^_R\VZ_zgZBb6sssRs9<=93R8Rdd9)= " Fo^5n5n5n5n5n5Fn^R- dqdqdqNdq..kB mf.k/////.Fev9 odqdqdq^dq5dqdqdqdqdqBdq.dnBdqdqdqdqdq.l6dqdqdqdqdq&dq. dqdqdqdqdqVdqBMdqndq'6Z&dq" dqdqdqdqbdq@ Green PaperU):FnqFsqFxqF}q k8kѐ=%v+?->5X`bjjjzjjn    o  BoooooooooRB9po5^T~2Ndooo.5n5^5J5j55Ʈ5$>%>- &aE^4o^05o.5^TPo.o0=%^?-yEA>EA "o  R R R R  :f2 R R R R R  l.l"n"nI RUBz(  P.P?n?. n ^ b Rq  R0 n . ^T :m j y R R R R  :byI-R R R R R  _l_l_lR ^Tx P.P n . n ^ b Rq  R J . ^T 0?"4%;?-l ( R R R R  4G<%0E>-=6 R R R R R  Li.LinR ^T P.P n . n ^ b Rq  R J . ^T 0# =%>-M|v| 0 R R R R  ?0@ R R R R R  g.g |%NQ  ?%??-@>5fff?`? -@2'RJ^vT@T T$ҘJ>%J>-56T T5- T6T T^P6!bP T%f T^6EL?%!-?-P Rq R:nnnxpAI$>%>- @ TR4 T T.)P^TPA}  /E^BB0@ ->08 43?%,s?-R?^  ' chart-1-series_5*  6  ݅ @ A0L*line68")nA*SFSX2 Green Paper :F  BF  JF  RF  Z43=%%>-Q=M-bjjjzjjnL      a.@v1C6 ?a122d222 @@ z2i l, 0_>%0:>-b60 TOT R ^T6f P=P n . n ^ b Rq  R J . ^T 0=%Ɓ?-o* j    c (valueaxis_0 ?j 0$9?%*9?-!9O 8]jm zy b.bO z]Zha1aaaa? , %o: @  6a%a] I$2-category6 AfIc,}+9?%09?-]((8MAearMjd.dE ]fHE!i'   5i3Q%`x Default Fill Center !'b ??B "R->2G1 8@J  AAELL Directional Key @?fR4(GdH  %Right LB2x Lef =f-:( Medium Top LrR?23:A3@A3w %I Highbht?%8>-h~B5k!9n9RR,`CB^T9P.P9n9.-PR- BLC^9J9ݎ::.:C,`>%_:>-x.= C^cC.C.:^TPC.C! %QW?- 93C>C C> J " N N N N * 8t?%A,?-I.?5%7B  0>%>-A[: LL* LL* LL. MM. MM 0>%:>-:~ J RB( . ^Ti FP.P n H٢BP n JzP& Ru:r " RJg n i T6 09?%*^?-|b v > )J l& N N N N * 0x$?%([>-,": ) 0>%>-T,: LL* LL* LL. MM. MM 0>%Ԧ>-~BmLnR  ^T P.P n w*:B ^rRu " RJg n . ^ 0W?%?-b v > Nd&1 N N N N * HG?%Z?-T$d?5>Bd&0?%?-!4*d&LL* LL* LL. MM. MM 0=>%`>-%JBm  0 &?%q-?-ף0R ^T P.P n .n^ r AA " ^c n . ^T 0i+V?%H_?- cKd&jd&> Nd&< N N N N * 0c#@?%?-B":0?%>-,N* LL* LL* LL. MM. MM u.unR ^Ti d&P.P n . n ^ r Ru " RJB+ n . ^T 0Vs?%XF?-yq  v> Nd&H N N N N * 0 >%.>-5Q/: d&0>%>-,: LL* LL* LL. MM. MM x.x n R ^T P.P n 0٢e n ^ r Ru " RJg n . ^ 0>%J ?-N $ ~ uNz2zv.vVzb.b0g.zj]Hwfza"]A6p{j·aaa%a^z.a.z3zr|.r|^zd.di*zj]rz!iNz3-QRzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz^_Jz3zzQa3zzzzz.lhBl.ju^hRjyXdhVhRXdXd.pFb.^YdRF9F89%L88rjp.pR9@R^>R95=9*ʜV88i8.C Fo^quuuuu5Fn^RnhyyyVy.rB mfr/////.Fe^ /y/ew V R 5yyyyyBy.vByyyyy.l6yyyyy&y.yyyyyJy3yy*y2&h_3Byyyyyby$  Wood):xxxx0.: 10_E %>-[.82j2z233  &Fx *Fx0  FxFxFxFxFxFxFxFxFxFx0^>%>-p=J8^TJ8FxFxFx.J8nJ8^J8JJ8Z0808.08ZĴ6)x^F-8.)x.-8^TP)x.)x0s>% h ?-- DZD > J   6 6 6 6 R  0>%h>-lQR r2R r2R r2V r3V r3 v.v?Dn?D0o?%>- ^Tί QP.P?Dn?D. n ^ r'  ^F n . ^T ,ҢR?%b>-i" v > J $ 6 6 6 6 R  ;?%?R r2R r2R r2V r3V r3 Hu.Hu n 0M?%W#?-s TT.Tί P.P n JP n ^ r'  %FmF n M ^T K?-.iNi> J / 6 6 6 6 R  |>%> r2R r2R r2V r3V r3 qt.qt n 0 >%ڈ>-$h ^T  P.P n . n ^zYN#r'  ^F n . ^T 0pb>%?-嵪. j > J r9 6 6 6 6 R  >%-nr2R r2R r2V r3V r3 s.s n 0>%>-^Tί P.P n . n ^ r'  ^F n . ^T 0| ?%0?-//> J C 6 6 6 6 R  ŧ|>-QR#r2R r2R r2V r3V r3 ^3760,>%^>- ^T6f|} P.P n . n ^ r'  ^F n . ^T 06L?%>-2 oNs3sjpprrb.bBsj]/qfsa"*=6sjaaa-a#`@2'%o:%@:y ' chart-4-categoryaxis_0*  ?Q R ?%6 ?- ?5?`? - >:(8M e?r d0$9?%*9?-!9d\ ] ft!i-i  5ihart*-`%`x Default Fill Center !'%U %?%}"R->2G1 8@J , ApAA%L Directional Key @?fR4(GdH  %Right LB2x Lef =f-:( Medium Top LrR?23:A3@A3BQ %I Highbht?888289288r9349[C pp>pRpp94ʜ8j8)95>.C FoZ $?%?-o1$C JC R5Fn^R-қ? -ff . R. fmy,A*GillSansRҔr///^/.Fe^ R V R//56B6j6).71"!..l681lf6R[6V6R.91u^ RZy} ,referenceLinY v @@&"(Y   (  series4 6 * @4@@L*line8"vAM@2 Gray Paper):B  BB  JB  RB  Zs0?%K?-V:bjjjzjjnD      l4 r C( 22n d222 @@ z2d pI4hX>%8>-h>! 2 TRu'.DT TRBT ^T6T TP.P TP.P T. T. T^ΖjNXNN:nnnx.I$>%>- y TRB, T T,v?%A?-ջڨ)P^P\#  v?@ - 0@?%D?-K% 2   v  N N N N  0?.?% |0?-4Q( R R R R R  0>%:>-:6{ n R ^T6f  P.P n . n ^ b Rq  R' n ,7.?%t0?-ջڨ ^ 0_?%b?-HNg v ͂o N N JB N  0>%tU>-y R R R R R  0>%Ԧ>-1B  R ^T P.P n . n ^ b Rq  RB, n ,x>%>>-dջڨ ^ 0?%G!?-% ΂ ( N N N N  0Jjv>%tv>-gv R R R R R  0=>%`>-%1B  R ^T P.P n . n ^ b Rq  RB, %H<ջڨ ^ 0.>%̠>-mjmς 0 N N N N  034F?%J?-WQ  R R R R R  $ҘJ>%J>-&d#6  R ^T6fmP.P n . n ^ b Rq  R' n,-F?%ɦJ?-ջڨ ^ Jq?%w?V'mvmЂ 9 N N N N  01>%8>-< R R R R R  0_>%0:>-b1B  R ^T P=P n . n ^ b Rq  RB, n ,>%>-ջڨ ^ 0>%^E?-Q  Pd :value6Md<?p:Md.Md8SmX2zc;3T?]KdU6eKdɎa"o2aaaaja^g.a.g5-gf.fgggvg!iNg5-3@gggggggggggggggggggggggggggggggggggggggggggggggggggggg^gvgpMJg5ggcO5ggggg.lWBlggggg*g.gFgg[$b6? -Mhhh"h9F8^TRKZTvJjr94@.^R6N>R>W>W98=. F7^[`````5F6^R-cccNc.]B 3P8j]/////.*.eccccc5cccccBc.`Bccccc.l6ccccc&c.cccccjJc5cc$c&c5Bcccccfc Br=):2c2c2c2&cLݐ>%"'?-7Wz?5333?`2R2R2R2R2R    c &c0     ccccq{ ? ccc&cR2^T2ccc.2n2^2b2Rq22ƻ200L?%6L?--L*0k1cR22.c.2^TPc.cvC>%+< > > > c4X^>%??-q>Mv > > > c0OpO?%2?-4Q R R R R R  Nb.Nb n R ^T P.P n . n ^ b Rq  R J . ^T Y' %Tp\?-ȩ v 삻 g( > > > > c0L[?%>->XQ R R R R R  :b.:b n R ^T P.P n . n ^ b Rq  R J . ^T  p?-z{ v 킻 0 > > > > vc0??%4>-.plQ R R R R R  &b.&b n R ^T P.P n . n ^ b Rq  R J . ^T 0Fr?%>-ӕ v  8 > > > > bc0L?%L?-L:0R R R R R  b.b n R ^T P.P n . n ^ b Rq  R J . ^T 0?%?-d v  Nbc5bc`.`bcbcbcbbca" 26bcaaaa2aVbc/h*  %drawingline-0-bP Zb RXH <"*2:P Z2}b@\4@R4/lق* = ラベル(代替)text-8&tT4style-Label Al cP7&ߣ;F;Fߣߣ8*P-  ~ equa-0-imag.CZ\zݣ6hj $"  RbrDD ?08.1JH~6 ~I¼ս ?..}2J}Z A -8GA9^3 ~EI} ^4n0s?%w?-jv*;6xp@ 2x.]5J  gj[OlDB Formal ShadowVގ ee ^shapegX ZYjYR *Pzv1v4h=%?-=&~6{?V.)92J![E0Dl?%P>-f6u*n$:Chalk2j.F3J]0>%Q|>-Ojv4v0?%?- fv5v^ @@.b *y r movi * ZS J Z1.>>-2BZ~3 63 vT @ ";.7y93JZJ" .>=>4BZe c^7 B Headse+.5Ji  (?=aMnotap list*X>e!6m-mAmM mX Cr *  4*ϊd 0 発表者ノート-N"=S7Z)@A* HelveticaNeue.!30~~kj = ?.Y2>X>e۞L]•.L9L3FL>e?L"5 x>4.ъ  5 リe ォ u-e-d *}@Z\:fr}"(*2 7h-0B ( Z JH04%o?-W} ?`"շ4CC2@J,0<>%>--,vvV  v @ "[ 0*P Z#" fD4.ɖ- "D86:8B^4 gٶRv2Ae4v4چFB:,4%5 Q?- ~?-ڷI Ʒۆ9F:9I(%Ƙ)>-<5b0/?%>-H99܆9F:90k?%FY>-d%>-&)rrp -pբ).K*3_F1, Z ^\$2+a|?%-&e ? &>?%-&(? *˖@JJs.JNF .`{{{_$  DO - master slide   9 Z R*f^1-^ P .RV-10__ʾ2ƽ^3^^4^ʦ^5^֦^6j^R ^7j^ZP^8^]z 9^ 4* D%stickyComment-0: *u@uuuvv 4!=t–t(!vt-rwwwwbwwVwF.wP2wVw>.w`wwww2wwVw^6.wpwwww2wwVwnwwww2wwVwXm=wwwww2w/*2WP8i4zVzV=zzzzVzk=zzzzz6z.0*!  !> \*% Z.*V >yi 2 Z"/L?28R! .6J tabl 4Z6 0c?%e?-h  %0(=%2>-+'m-ZS.S0S.S ?!`?5?`@@ -@2'%fLQ (=%2>-S  XFXSFSN/ , 0Helvetica-Light " - & ?. ~  T0([>%?-F* 6T T= T.TJT T. T. T. T.TJT T. T.TJTTJTTJTTJTzTTJT@^LΨTJTTJTzT@2TJTTJTTJTTJTzT4TJTTJTTJTTJT T^&, TJTTJT@.TJTp .6 table-1-HStyle* P4Z6n0!b?%`?-ݲZ (*E4(=%0>-<&- AS.SAS.S ?&WX.X*=*=*=*=*=*=*=*=*=*=*=*=00=N=&=4>%>->&ε=T.T=T.T=T.T=T.T=T.T=T.T=T.T=^T=^T=0#9?%*9?-!9K,.kb=T.T=.=T.T=.=T.T=^Π=T.T=T.T=T.T=T.T=^T=T.T=T.T=T.T=T.T=.=T.T=T.T=T.T=T.T=======^=2v=$C?%B?- V=,>%T>-.- =S.S=S.S.=X.X=S.SN*=.*=*=*=*=*=*=*=*=*=*=*=*==0x>%~>-t==T.T=T.T=T.T=T.T=T.T=T.T=T.T=T.T=T.T=T.T=T.T===;@>=T.T=^T=T.T=T.T=T.T=T.T=^T=T.T=T.T=T.T=T.T=^T =T.T=T.T=T.T=T.T=======^=3v=0]?%e?-sfv=0`2%>-*- =S.S?S.S.=X.X?S.SN*=.*=*=*=*=*=*=*=*=*=*=*=*==^Fεz6T.T=T.T=T.T=T.T=T.T=T.T=T.T=T.T=T.T=T.T=T.T=T.Tz6T.Tz6T.T=T.T=^T=T.T=T.T=T.T=T.T=^T=T.T=T.T=T.T=T.T=^TΈ=T.T=T.T=T.T=T.T=======^=4v=0^?%k^?-Q_v=^U=S.S?S.S.=X.X?S.SN*=.*=*=*=*=*=*=*=*=*=*=*=*==?%^N -;oN=T.T=T.T=T.T=T.T=T.T=T.T=T.T=$?%?-UHڠ=.=T.T=T.T=T.T=T.T=T.T=T.T=^=T.T=T.T=T.T=T.T=^T=T.T=T.T=T.T=T.T=.=T.T=T.T=T.T=T.T=======^=5v=0m?%n?-nb VQY Y Y Y *l====================================================R1Fl^-=TsM=T.T=T.T=T.T=TSPk=T=T.T=T=T=T.T=T.T=T.T=T.T=T.T=T.T=^T=T.T=T.T=T.T=T.T=^T=T.T=T.T=T.T=T.T=^T6=T.T=T.T=T.T=T.T======= 1X ((Cell-0-body*3 Z6 0R @J $@ d' @.h] !.h footerRowRmRnm.m` $.m,headerColumnRp0c>% ?-Nnp.pB p^08<%>-z@m.m:1f0}k?%k?-{kh.h:1zm.m:1-Bj0D>%pH?-BTn.pBv0\ۜ3%b?-,m.m:2f0f?%bd?-ٌW.h:2z0&?%^>-^.m:2-Bj0?%?-.pBv.m:3f.h:3z0Oh>%]>-B.m:3-Bjp.pBvm.m:4f0RP?%Q?-kRE.h:4z0?%K?-Vm.m:4-Bj0{>%>-Ž.pBv0>%>-.m>6z5F n.NC6`5ZzS.SF6F5-J~zV.VBVdrS%   5 (Name-0-shapZZSz=6Z PZ2R z1Z.z2Z.z3Z.z4Z.z5Z.! t 7  丸付き数字text-0-liststyle-CircledNumber*X>eDZ?m mHBmCz Cr ?gx0>^.cP 6 ひらがな B`8HiraganaDecimalIbbbb>^_.b$ ;  漢A+B\HIdeographicJapanesegggg>rg.gQタJKatak>rb.b D  !\1b(イロハ%B1k Iroh9999>jp4/,"   + /" 0.* 0 % トル- paraX#Tit87ZB*,KakuProN-W3:&yn2(@PX`hu } ϝ<  49BvDbf.%8B(='@HP] $jpx {4~*L , 行頭記号%]1*{BulletX>ex?t o e/Rut@2t•4.ٖ= .((小)-N Al-]p24.薎L !キャプション(レッド!")0>(Caption Redi3%Z0r5I?%>-]Rv4.ږ > スラ 番#)1>Slide N*6 %A.4.vN F (代替a)')2n.^RBZ./8BxBk? ?08R]].ǖ](+ 引用)3> Quot=}JZRwZe e e &e 4.|Ԗ| 1 属性[4>|Attribu_[q- A*:Oblique 4.b 表. 1$i5>T$ {  11"} bbbb:b.b>-1=6V"9 ^R'#ZzRCu@R ?0RRR2R;n;4.M=2qM7n2MMMeM~.M318n31MM @ - . bMm%  Bn4)419n460R^ "2 +,メージ@2*W ImagJ X>Q(V ff>F4.1Ֆ[ 94 ブCGeFubtRJ 2 .J  . テ:トE3]Letter^^^^ >r%.Ŗ() 本文-x:4 Body" ^R[Z (B. ( !I4]V>r. 8 I& !BA Smal!*~~~A~4҉6 cB fff4. HiJ&i!%BU-Rc^RZz  ? cccFc.떨O $FQ]+ 2`B 1Bol`Bhh"-0*  a+box-A" Z ~k2Z-i"rJ=0*P Z#" Z .4R/ N.4 drop-cap--defau4 ./P /.0)0Zb2 0PYAPai@?q?0/+#bNFO Z^|# 081K?j|3/.u|΂2F5 nRGZR,__zqΠ*JH(04%o?-W}5?`"~'4CC2@J,0<>%>--,."(4*  )X0Zb-K>0*--?>L?%-bD= W?%-DDGa?%-DDk?%-DDu?%-D:D)TJT0V>%0?-.DD0>%;>-$W .DD0>%M>-"v8 D0>%>-=.DD07Q>%q>-.:D)TJT0ٹ>%~>-ۂ.D0n̥>%>>-.DߦD0U>%L>->.D0$C>%^:>-f .ަD,ߴ>%>-N2 :D)TJT0K>%0>-.D0>%̢?-'0.D0l>% ?-W.DD0?%5,?-} .DD0Z ?%p?-.D:D)TJT06>%:Z ?-.TD. *ʩR-jq0l>%^(?-#.qD0ܢ>%@c0?-+.DD0إ>%g8?-T3.DD0>%Fl@?- ;.DD==)=R=-==)J05'6>%(>-ǐ%.D,B?>%>-fD0T^H>%>-B6.D0yQ>%J?-f>.DD,sZ>%Q?-"+$g1a"*R1 " *,6x9 R%,0R }4$  アンダ+ kZX.4  +リt-... z&?+"* ^ ]PZ%$0Q #*I.P B*GillSansb7J>RgZ..~ .0r^.b: *  .'mJ'env?m  mAmX11"= XC+*$ $*i}6A* "(b+5c.* DD ZO`B  R QR!: ww>*f6 DDZRrRR *=y /* zzZ^zC/'m* CCL :3 3j3:3 3j3:3 3j3:3 3j3.3 %* 335:A9-8 * 990:( (.(@(P (.( ( * ((0 PKGLLQr44Index/ObjectContainer.iwa0x= V )"01-" ' 0L :PJPY (0BT Bt  \\"j1S<E\ i/s Af*-  K cZB8xゟ2 EW!A" PKGLLQSYYIndex/Metadata.iwaYU"   *22($DBEAF416-1753-4FFE-8523-239DDE749026%GDocumentMetadata"*P`* AnnotationAuthorStorage"*P`  MasterSlide MasterSlide-7"*2 2 2 2 2 2    ^2 :: : : : : PZ.ϓ⫪鱇Z.ի̲ѻZ8ȘmᨕZӥyÿfZȰZԯpݢҰZ.Ł!ϙčߓZ.șߘרOZ.ӝ2Z쏆ץ܊ZɌŰκԭZ [հ؂Z.Д@Z.Ó`ɵՖZ.ֶBŅZ٧尐Z퉖ȢŃnZ.ꟳyҰƅ:Z.ͼHZ.ֿǜVZʌ鮦ṚҳZÌҧZ֘dꒀZ.֡Z.߶ʱZ.‹Ӭ삯SZ.݅όZ،;UZ̥cZA\ǭץZX ﰫlZa,\Їں4ɷՉZL㞹ݠǮAM9H̪{捎9aJLޑج9hůâඐV`n8"^PZiobZ/Ӯ'Z/`xZ렋ݪdZ7XʜXʛUZ!$Hא˦Rʃ!@HӪ˕a:\ݢ)Z\ץõ ZX̮ŏ̤ ݤZP֌֘ҰxZ!ɬGPZ/═ϓ̯ˏٛ!L\̪ѕKZoXЩޭJՂYZXϙHZH˯A˝`  Ma"b N \ x߻ܸ!'!'HÎHϯ ڀ֧T\ᣲʭ9Z! L퇩߱!|XԻҵͭwZT\У󱚢nZTLęحTl ҊʘpHZoX†꽖oZoH닧5؀RRXf͑EZR޴q튊cZ ڏɑϖ!2!NH̆䦾ƊAoXۦpͦgZ7HޕL̇AvpL܎Ȫ!2LβƯţ:LԜL䠢ὄ!Xؽ!䒄RZXܙ2ܶ‡tZ6l㱁¾G`t }M2  !I  /                          q                   -x    0       - X         ` `                            m      8  2  m      .i-           h       P P          `      @ @        !2 e     E   .2M 5MO       U        P  -  E     =b b            m                                                                              A}2t::V:R:P:N:L:J:U::Q:S:M:K:OPZĵؓ  XkIJ@Z X€֠wǖ$Z LӤɢʇ|Xݝuڕ L߳⃏Ŭ pĺTZb ˗伉q0ﶻXZ\в߅ZHi홭p\ώţmZ8\롔οfZ!X湘ŕͽGZ7\⿲ڣǡYZLЈٲ!!iԳͦO Z㢤½ȥZۣBZӹᴍ Z!2H˫܉ Ѯ̙!`ὣнLܷ֢!PO#Z텊GZ⪽ɒᑰ!8Xۤ˃w=Z!3Dګm!hˮϘ惡M`n2*8 2ͣ l  M BJX JZXߛ֎ܫˠ0ZXޓ1ȲZHաɤԋ!HŪTݳ\êԐzZ\šۋUZA L尬ۣ͟!PϬ<ߔZ!uT벭غݠǀD۬hTTXB甜٩Z7Ȟ٘SDώ6Hԥ8HѤAbL䜌֫Ϙ99hǯ,`6 *-4^u~mQVuX㘹ա'І̯'ZXͧZ&Hؤ 埭Ɗ!7X篧ܥ"ʰ Z!%Lǟҳܑ݋ᡂ88Xä#ݒ Z!\߈߷ޕlZH錒z׾圦SE TƲZHȶmǩũ!H퇮жIЋHޡqژA` ɲөϟѳL͘فİVḦ́؇`܍HͻqÚHԙ"!Pdݎʖ)`=ObjectContainerYh\"ϤJ隬w\-ꌤF„8HߙӇﳩ۱!`1Ѕ䧥̲99D椡#ِҼ)奈͎ `$ CalculationEngin* P`n396j 8Nj!H۬!X֤󬫻RZ̡ULÐ!QAULӮ!QȁvH輏'ڄD㌭ E8Han8H֖ѯ׃TD݃[߶ L⪲ӀͿLٟά!L҉ުLЗHĔWHԝG!XRZHªݤ['RhӤŮƄ`nz1>zQBQzIYMr &qH庉̺ݡkӰۂx !Z.P楰Z俞æDΧ÷6箳ご!3HҪ5ًݔ!O!\֧xZ!4L솣ӗ!4ޕþݜZ݅ؤSZpHǘԶzΓ!3Μ!0Ġ(ZHɧ;ѡ˕]LīHﮮ!Xֹ̗}{ZH㉣{ށW!櫛0‰&ZaLůᕈH묨ӂl*LȴǹHйߓt)Hٷ㨶ٝ.!oDL/ X皲ϰ٘RZH昝fЧA Hαըɲo!A Ä (؆ ZD!ڧƥ]LĞ•pX[ZAܠ¦ Ͱȕ!\ԋ)Z!X١h_ZLڋݜ;\!Lߛ񩽯څpLӿܗĽeuADثꏛGϝجDѠ~˞އD۪ߞz Dӫϥ6 Hܭƌ!N!NDXDž A\袄ˡ`ZaHůuSXݐbޯWZX׿إ&ᜌ!Z!/Hx!K\崣-ZX;ɡ ZALãa`H qL} AH΍ΨDݡѨ \޲ث؈pZDϖȾNJ !\Ȇ뵝ؾ~Z!Pɫ,ᡭ ZHؚͶ; !H鵜f HٯљDŽAH櫴𘩕/XӺͦ{,ZDު銥SǧDݡ3AH7!L坧㢢ĴAaD䏭ɠaّ A1X͛ҢjZXǠ¦FՔ惆.Z!H/A \˥ۮbZ L׭LĦզLܾLؼ¦퓱!mXݧZ!mȰA0IZAL𴑻DZq!nLŀ!a/Hӂ|!HCȄ8F\ǡ۱zZq Hѧ3HȳإDؤϡNǔǢ׊$X߳\پ'Z0yZLㄻԨs68HչӻaAXۿ「 Z@›עĉ%!H~ H窥mۭ!Dþrʫݒ \ԷبZHÒϩAߎ!iAֽ& ҋ!(D긎řmaH⦵˔ LɌ͏ĸ䣋຋uׂ}ZȰ!kX;ѿȓͮZHdz6淇[ DЯ~ʎ۝dXךW㳠ZHȠ!\ɱgZXԨܧ?Ô#ZLƏاXђ9Z!\Ý_Z!H֣֒ͪձʁDk[!\ʷǮ3ϻZH͛ɔ˙A-L裎ű99D(¡aHͤYُULۣяؖU9H̵ ۮæH狤*aHނF޴q\!잨? \*IJuż9LᐅLؤՐa-Hگ‡ʐDA5Hմġ@ۄd*!pLσﯣϲqHɿېܷ Lij̥݁!HǓ䞠m!UH۪rULޛA% DۛͤPߺSSԩŲُ֖A7H)HoٗڜD̤aԇELՒ׹ĵ]LпU DΨÆa5D缗ɪ HůB߽M[Lزݑ<N򝈦A,뾅Z!h% 휓\獀֋dZ!H͋٬ D׉Җ8TDߡ 頃Ɏ@Ρ,D휹ܖڪ~ծ Xۊɼ֫WiZAXקġNEZDŕ' !H͹嫤H ԱA!LƢʓ鰩ô!1\ɻ0ZUЃۡ✚SZ!¾ʕZ@ʜ $!H㥅y-LطЧۣi(Dۆ󄤦V䅪϶bHǐa\ZbLǺ研ڿŌ!Uםܨ0ӻRZAXߕQʹ*ZH=߸З !X萡ّZXߙ՜༭ʐ%Z\̟Z!LﯦH&瞭ێ֡yDĉA偣%Dç[⌒ aHEDߧ%ٟC\ݴ߾PZXǤ)ò꜕gZHٗȁ!H뽘!kXʻ澣ʵyLԻa-AHᄴŀAXթ셦f𷎚|Z8Lɐ!mHҐǭ¡!\ڔڑNӞ8H֓׺Hբȸ&ዸ XjܫZ\ Dꉓ 㓺ԑE0 HĞ`` ˀ󁥆!5 ѻ Hћ閎݋F!6Ló!nX㾃ͯvZALӓ̤ȏq!6\طWZ9LږόΠijչ9!SH4APDȍ ) HㇹS6 H甝ݞ߾لqAHEkX-yŔʼbA2Dfڹ!4X؇qӝDZ7򅖐%,͝įZA1H਀!2$HѪšݙ!OH٥ ,+LŮάAH-$C~H֑嘗A0LƜ߂ALâLꀿ熞!6Xگ.ѭ嵄aZ!X0_ZD܄0y Xс,Z!X鏨=Z! ˜ѡB'MH͗ƴ A\˝ԥIZD¿㵥=۰{ !LㅰATH׍ڡӼAL쬒뚬9FHţGÙήH³ю !XÆsݵGZX*ّBZ!Hٲ̳!DӃw!!HӘţMמ !L˸ݹ!\ČZ Hĥ]!HӯAXߢǥBܬ!2Hjԝ7!Xѹyݬ͹rZDȊ9ˬ7!XҩJZHʅˠJǝn!2Hdp"nAՒشa XԷ˩!ѨhZa\ࠊڤ뾈⭮ZHٺ倶ҥ1XuᎼ8Z7HꗠӀHsžʃ!Lݢ!!L䏱tU Hʨ=ҲDć*SHŽ^\ȍΝmZA̴ԃ 瘋p!X龓Q򨀷X1 02*Bt*Q PLHÿѪw鱊ӇhGX㱀.댋7ZAHݘ끯!̿A8\αگ&Z D򂪎ᾨ㰌pD֡PצܬpLĝИȧIpH̀R!H¡򥣶q'Xͬ\ӛZT\ԁʨVZ\ۀؙ̑0Z8\ijfЗZoXݏέqBZ7HƝ]̪!3ѥ0Ջ߱ZLȷq!PXþ˭ @ZUHŭɱH˧ښ5X.ۙqϧߚ8Hж҂ȎAӢ茟q ୹Ջb6ɕA2Ulϩn` n00}tEQq 0m eI-q` qx X2NTe8EHGУA% (X奠]Z7X®ͯ4|Z7\9Z Lʩ!?9HΨ휥뾌񎪒049Lެϩ99\γᓽwZ\ʱĚᡐɕZXLֲKZ/Dͳɒ֯ ܪ06D۱}܀PmDU̻͵HӂƩ_׽䰗AVL胄ۤퟱAXڦՔ_ZTHح1ӀȽۓ!DN& D˪ؗRĶTHҹJT8D疰nʣ؃8μL-0䓡5Z\۽؁4ƚݑZT\ÎҌюwZ!kH܋͋]!3Ȍ һP :2=5>lq$tJqLq\qѬ 0qq\W8ہQH򣿞ơ$4 ڜꅬ9(볾XZءLブՉA4LЙݢ!Urު˂QR߿̳TաOX鎰gѱ㊼yZTLЭɟ˝TTLܬɄ˥ 9Lۉ譌鲀 ɋV!Lܨɜ+ rDǬО}!׾ 뱂UUHڏ̢,퀵ҦUL֢̓ʒNULѠaDݐ+ЀTTHۺȰƽ?Hǭκ0\Ҭ8ZLҲȤŌXκねҰyZ!DϨ㊑Ѡa튜.!LĦ﫩푨ĩa4 n49^444m q4> q,B ŐDء!f\梫դxZ7P㌞<UZTܺà!I!IH쩺0ƝCUDÊ啉Ω*!\צȓ٬ZH ÌnSH듶%km7HŻԷ׹A_DT\΁ZACL锅UD񃻝˫[ɣD俺C٧֤Hۋ٦Ͱ椛Hۡ6װ|^`" 9;V;& f!0110809_familychineseoahu_en_02390_2880x1921.jpeg*1white/110809_familychineseoahuJ8R\ N,>%p$"v<0317_2040x1360.j68] Z EN[ACtile_paper_yellow.lL$t11/photoportfolio/B+_hYEXorWVAӹNuMYp4 blue "v])[h[urgU Hd&S[green \#v\*]hW.hk\vAy]red [!v[redY`]O|Tҏ tIY2ppurpl-zp +_hZ{X~PU"xAmedgray ( 21_basicwhAF'\`XE@6 D)oSS}2lt[b[ &Zl eRa^'bT.v[(016_981x654 / Ƣ6`Ya6{{3` 2z)[`P)C}:IɢZd뎎28dk4  = R@uUjJ6:&` PQly+mt-C1125456-CB99-40E9-B950-F75BF800AE1!-g".--85.jpg" +H: km751:-smallR8v2q 7-1gR"uS: W64y0; ! E8BE52CF-0FF7-46E7-BB78-0EDAABF659BE.! --83`uLN6Lɓsǜ%1D92F908-FFE8-436B-8459-224D9459024w--76 wXQP4\?mi:yRwDA150A6E-6AB1-416D-A055-09ACD9E13F6F.--8%\k6P=eDFJv6u)vN7-1E9l s(mS-ܚn{J3vX665-12`uRT<<8J$ hӪb%5392479C-4C8A-48A5-BCB1-F280A815587C.1--8d"uPo^hJ%Ħt_'MpwA755708F-7FAE-4394-A6A8-F317C097896I[a--8I`uNC{Tf|6(?wD4D90C95-2A35-4D4F-ACBD-6EE33763DB0--78!nC"wӯ>B8xゟ2 +st-4200AB5F-6B58-4177-87A3-C525A84DA824H/- -1891Nٌ ?F&@bullet_gbutton.png* s/ 2!d"uK[XP6?09|1Y%@X2FE216DF-9BE6-4769-9976!5D75FCDF!--7 0`uVNdU;mw0CB0B9C4B-E625I!,-DBB6CBDBAA5)w--86%>`uO#}FE"Un2V{xwE29FEC89-CF69-4791-93FA-E3187A9FB75)w--7 0`uM[ |VH7JE1w193E61BB-74D9-4ED3-B8E9-13631E84744D.q--77 XJ'PjyT%opkEp615F7CD4-E262-41F7-8138-806ECFABG.st--7*CP: @R2+2&Vju*0/0/0//0000/0  4 /    )   -400  < ?%?-(5?`/B*0?%.?-B*FT05?%E?-:*FTR?%O -/*FT4|>%>->FT09?%?-P*F*0>%>-~F~01?%2?-4*F*x>%-F*0>%>-*F* *F t>%>6FT@%l>-l>5?`PKGLLQnBBMetadata/Properties.plistBBbplist00 _fileFormatVersionXrevision[isMultiPageYshareUUID\documentUUID[versionUUIDV10.2.3_'0::DBEAF416-1753-4FFE-8523-239DDE749026_$812F3519-1EF2-4CF2-BC90-83C49A75C263_$812F3519-1EF2-4CF2-BC90-83C49A75C263_$DBEAF416-1753-4FFE-8523-239DDE749026)2>HUah PKd[Jn=1$$Metadata/DocumentIdentifier$$812F3519-1EF2-4CF2-BC90-83C49A75C263PKKLQ| JUU"Metadata/BuildVersionHistory.plistUU Template: White (2015-09-16 11:52) M7.0.5-4052-1 M7.1-4328-1 M10.2-7028.0.88-3 PK9LLQvRR preview.jpgRRJFIFHH@ExifMM*i8Photoshop 3.08BIM8BIM%ُ B~4ICC_PROFILE$applmntrRGB XYZ   acspAPPLAPPL-appl%M8 descecprtd#wtptrXYZgXYZbXYZrTRC chad,bTRC gTRC desc Display P3textCopyright Apple Inc., 2017XYZ QXYZ =XYZ J7 XYZ (8 ȹparaff Y [sf32 B&n" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzC C  @ ?((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((w3/ ^2hu}{t"z@%H翄g/^-n{5jVVwbš5vܶݪy{%_쭮2[M3S5mSKR^vsmc  ?><|u(κ^?rxů'iR[[XJ2[zo0)͟ t=u @1O"-MŁ-1ȭOuw6,[ۺK m!kHNުɻ.x{~>}7X|:On)iX}I7XPP׾ /^,g&þ:SJXe`ǻO w#+!F⸿0ֶ:wo=_BiEmiBK!5|Y>x<3asK} PZ(6tVpA0'[;)mtMK]2;+[VdO ldxnh/ ~0Q2fezFc&c5ݤVY丑%0YR\><;YhFt*BdjH/՚9KHnyK0&MQ''yqqE,UPI$_$"xMEto5o.=7UCGgy4) B9BĀ{ož+3^KsTv-hwy4j;|Yৄ*:}΀-˝Gs\mV\$~ݟW|YxKZ۶z4gSү4._"97!@_zf^|Nt;M:}NS-mogIVRd`ܠYAOo؟Yͷvf{yu_XuXɚ;YPڻ |$_g~t ERG^ix)԰"+dk\[;C'q|O^ֲ,aV7/h .`!|2P:W|-gߌ>+Ou+y/4}SLҿmb]5A (\ m ?&o D|G*Jԯ~khKXi9U2G+B*v9v n}>!t㮽@#m'J--VԮ-dT,Y6gf@>о?jt+uˣ\|GԴ?C,Z暨g;%[vV/89Пz9}7RyO<%Ȳl/ ]ŵG*n^T`|{G&[|B!hZXEp^(eM>%_>-i|JҴG#AD^A 6m]=aQ@gm?|C&iKZEcuu5ݳdX8fH(.@E,3>&~_ ^:ZkiwڣStpL- 0HmH'ȵ'NO6Vd;kܺz1i>k;-$p-qAcxCΎmk[ۡ0ydݿ:g'K[Ex{vQ9?xDC媗j/ګwŝ:ui:ͬMƕYnb&H8݃n?1|>Ӽ5s@WtOmrص= E%S > ~&{k=αwkhw&UUvDUN(?v}[i 0f{H%ܰmr/1?qtSéj:/_W0K1#"$Da.> |_ㆡV񖿪EZ_]ZM{k4kLı,c!w1ׯ= h|Q>Kk6b5rZC2yh 3/~9?|+x3Qmp14ӤFKƿy#}qV|k͗~7Ⱦ2t_xzHDFΑ3 S0k8;Pi#Y]%4K=Y,4au<1r#UflC(,Usn~;%_5x ]:yNҿخ-F43B- K`c ~xO+<9i-ڕ,B@8R3_Z//Jy~^0crl`@~z}U_\%Z_Ti 1!a_ XZ|=)[@=U"7u߷o8/~"צ:Ny]؆nn#c i6 M?گGf2j>L&þ% ­*kE.q*Y HPpJBA[dϿ|Wkk)V^iV}jĻkPl!/۴?&;h_j v)scnG/_ V^'k]nRkۨ 4&ˠX Xg3/k/Wdoׅ:ni77v]m|\X9/:߳īk;:%xkS a'he3X0IH3Qc]ݧǯ'ό~ Ώ+mSOiQ{`5 Xmdԅ!Yrʀ}u|~֞6"oXjD}atГS$/ٛR]ێ oRkf|AW4x54}*UM˽%{HeKudci ir|+?׆e-_*P>~Mk"_jڍ1Vh4^qʌ#R5O3'5kZ/={!n<$b|q^~/>0Hݭm฻;(IBx>a"d C媗j/ګwŝ:ui:ͬMƕYnb&H8݃n?*g߇uDlzvHำk$(*LHq\35Wxc:޵5v:UWT>@ 8$~fÿSp/Q+zU^6rY!{G-Q252BDHPrH|G +~-gv_IB<$Ԧt3IMm$CH{8ZkmGaπp|_7_D/Z1HY{q==afK8`-"$p#'>%-+߀|e/58d[Ab`ZgT*;ao) qi:TC(Kp$`Pڧŝ:ui:ͬMƕYnb&H8݃n@ ~_nj5ÚG.WP.m]hڝ漐E `]4%]O3ڀ:?ڿ>5૛yZ74X_K2mO-#6HSDk?%E}6wwUv,hE$n&v>Ɍ:5\;>V+?O¾'7^}){ ]h4q#Fn-W`ž#oF" t뗞[[qI_x?>HnJr(~7fك'K+)5ᾤ.އ.٘+$_||٪xND{ =˙$nzٟ|i< 7-^"֣Z d6ռxHDQdMMTG?kco/?x6f(kicE2D  *|"/`EEj4&}JxI+ntRax "ciM#Xsu8POsNo!;‰eTQ$x ;gZ 3u 4dTos5fv-zJR952PFp >;_`eXpj@U0vn`Ick ?3E@}5vK[x&RG"GVR vv6ZuYZ0Bj=@Q@Rtakw!2ƮcqJXsWh( 6VFSgow2JcEMz`rLt뻈.a{c d]'1U((g-u"?ngS.t>Xgy-|/,jy PEP[k+#);%1=Y9cy,Qea KEx)x EԚcXЬ$'EyScpd?fmq.4N(>'JT;ۀki ;K;Ih#yϕ# .b23f5\[,Z6##*H;>2=_;lm:Ds-Xy~`oϷn6tPk[+;u+uW @yjP|@.}oTڽū/gyIet`3S5ezO%= KBIah!'yXcw cye?n@Q@Q@Q@x h|_YԛWiT2}(((((((((((((((((((((((((?h |xg֧k}FaZfZNbb ͝W_4|J"xK>:?Ya&/CJ dYAJ^C j gZt_i:Z:QtJH V bhK:I ܎U.|h߇m3M+us+7w][ZDGV!`A hg 4.~ѧMOw=5k6x"KEIBp>Lߴ׊mw  \|KյCzzu m#Bk˨ sNk)Foxcާ;_eZ:i Ŕv*э s3i~ ۧ[J#m;'W.m2D̒]A%ղb(X+;_mF>xwP7?PCX#GјLq0NK*0P˾+|c)x3zԼ ռU{CN]n-xaIcExvr Ͼx&__i |'߈^}WPH^vBZ ?v2!/#iA׌5i𵷇渿#u{4.  |s?ƽ/w Οu?]:ዛ^R6' vO1 !U%p,j 6ki'VԼmyd;1-ʙ6uݑO`F.|y⿌:|e'Tl|/gu[Oz$͸nI$rv~UO|54}6s~ ]Fk\Хʈm!)nYyώ߳w5+g@[#R2VP ן awh/4Ozq0/V)$RFS\p»zoُo~ | _jZxg 4.%mH!A:y K_xn?bln?W1ھϟ7wص[?;>Uov<s+nĵ7-VOs||/~-|MU\j>|'k3߷;{(~$ggi3;qE;*OWkho -k"< O;`=N0;οf4gu['4]OŘ*MGv^v&~Ūiac}>o۝E7}j7~w|_gϛcyx;o|W H6q>\q夺U3ßh/1k֍ue3:%[[1ң8)ֽ敯ܪUov<s+o|wF=+&gu,+p\cuc9|vo4 HM]IG(',pp8?<جG49V#m{Ocisw>7-VOs||/~-|MU\j>|'k3߷;{]ů7~.mm3_ڭ%>3+i6hUrt9 29QO3eBwJjn|Y5VjJ/gm7}j7~w|_gϛcyx;o|Qko }Z*7W;X^7~;dxB,\BHK*sVz ogo<$n$ǖ1wۗ.XjIхL#qS}k#ح|MU\j>|'k3߷;{_xn?bln?W1ھϟ7w+O|ĵ7-VOs||/~-|MU\j>|'k3߷;{Uov<s(7-VOs||/~}]~ϣ_kwacq}ʹ|N>gnv&~Ūiac}>o۝Y~ϣ/o[tgbԾA?_z5|MU\j>|'k3߷;{_xn?bln?W1ھϟ7wXgѿao  7 -?_s ~/&~Ūiac}>o۝E7}j7~w|_gϛcyx;o|VG,_30}]ؿ/}w?ލ{_xn?bln?W1ھϟ7wص[?;>Uov<s*OjבV^]K. {ej+8PI ѩIՋOXڝXTWMy&~Ūiac}>o۝E7}j7~w|_gϛcyx;o|Vf%7}j7~w|_gϛcyx;o|Qko }Z*7W;X^EbZwacq}ʹ|N>gnv&~Ūiac}>o۝[tP%7}j7~w|_gϛcyx;o|Qko }Z*7W;X^EbZwacq}ʹ|N>gnv&~Ūiac}>o۝[tP%7}j7~w|_gϛcyx;o|Qko }Z*7W;X^EbZwacq}ʹ|N>gnv&~Ūiac}>o۝[tP%7}j7~w|_gϛcyx;o|Qko }Z*7W;X^EbZwacq}ʹ|N>gnv&~Ūiac}>o۝[tP%7}j7~w|_gϛcyx;o|Qko }Z*7W;X^EbZwacq}ʹ|N>gnv&~Ūiac}>o۝[tP%7}j7~w|_gϛcyx;o|Qko }Z*7W;X^EbZwacq}ʹ|N>gnv&~Ūiac}>o۝[tP%7}j7~w|_gϛcyx;o|Qko }Z*7W;X^EbZwacq}ʹ|N>gnv&~Ūiac}>o۝[tP%7}j7~w|_gϛcyx;o|Qko }Z*7W;X^EbZwacq}ʹ|N>gnv&~Ūiac}>o۝[tP%7}j7~w|_gϛcyx;o|Qko }Z*7W;X^EbZwacq}ʹ|N>gnv&~Ūiac}>o۝[tP%7}j7~w|_gϛcyx;o|Qko }Z*7W;X^EQӵ=7XQ.ྴw=,OmW ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (?(((((((((((((((G7lѶ C\I$}9}_z/K;[׈/krZJ|sTB#7¨EZq-H 0G|IW"緸9.dtpC+ AA5xu!ȭti]v7IƖ.ng[+=W{cM"?#^nu6 }חW,|p`v%mY-G:.b*8ʳH# +tgUgk"k)6Fo)vi0wE}!f 8nR s\48gXJTWgo:k:ҕ6OKieg_,u|RFvfY)x,BoDPI=')mt'^fҢЯZBs]Zl.(׎W~~ cOӄ~^hl $FO%@`V''5:ɥ]h0̐ɍql kõ1N܉jVm9~u ,iGs3zsZ~5hJ+&o*_n FV `0dWkx"D#FE:UEi{&[Q*HT1!L =|U>Icwȶ4j w=kK^ybK#wfcII%IuXyI)5.nXq(EJ4/sFȚMu>",o/L【fkhI=tA%ۚYuTRl[{q4(STvE9s^we\4{[uےcc u{}EW'__ {- ׿I Ҽ-O/#ïz?{j:[tKkFp n2B 7^crwS&$q%CӴprO׬ÍzioNmZiw,@T$?].OJߴjfIY2( tWu)Fj5̣'}ꏕ콿*KV}-riuKxixI./YdLұb̪KN 2}kk=Ο錄odލĬ" bǎ5㯅jυ]I!yC4 lF̮vY^'ÏxgK{}-K'24lYDıZažuISQ\7'ufJo։yk&Eͷ˺Is%evq>ÛOsr\y1iZ4!Hr뵆}u'েm#kot3FmV1eM(Al[+5H< u4?xZL+qg{ecD# )FGE@R|Ehi)g&gEBْD́JÕUeSŽc-5kەO4qMb#dUC<Ciwϗ! 1D#1r[鎵/~д=ZKY(kcE#~>hz<9KCckiOmr&bdLi)9*Ǐ~x æxh(/֛"=*|N8sIogilLc) $ϣM][~Q_> 㸟Y4XiNZO%9PY1XEVBqѱj8ʝ5wpZhӯS e;o~QEiEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP(((((((((((((((wu.uY6]7Q`&KF,۩wTEu}!Yp7Wڟ% ۪?__}/ޏJ(¿2?hS$o_9^_G~gj׷@>|?ƿ;7Wv?"'FuuAX QF,~G/?I'z~0z;`FBs_"juA^3G)vZj꭪s1 ծշtk^éwѻGۛ+L!q!1rH@ ǞV}xZ- >E#%rN_ u{8fISu*m}bwQvWG pSPͿݫ}{7BZoټV{!BB]F rO~i]kߎuq-\[H.DlkH eO?4nua8J좝iZI>Wn!jZ[OVv+NxZ)Ϫ ~=6K4aF7),p >д oXkg\ 1<@gXnpvc'6Fp S)TvӶVn޷d.!:WZax7υ|GEhUZG4%XQv);sWZaeiv"v"€pO>eZUɮdZ6mǍQ^ͻ']<=EWQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE(((((((((((((((GuѺmnsFuѺ&F4n W% ۪5rs w?7WK7o,j($?H>2xܿ /¿ToJ}"2XѢZ໅bnn0K08iߌW?&Hj:=:?4ͬ-a\٨e$VpFBEl+Mτ'xz[oYu K!hn4s2koK?k뿊^?fox _ 47qw9f8# *Azٮ|𯂗þ-|sCkբZXieyu<Ivh8%ɯ,_H|W?oJu; ,izm"C vRv;vCougx?Uӎ욾"ڬ_M94$ a{ D_a7{z,bYWbVO}ExVi-?h >!5 jڡWNKKkui{oE$>nŅ1F~o?k;W_oaxSw|)y}m=1.Uh3#H` ?Ah#/ V6K6A2|'k3߷;{_xn?bln?W1ھϟ7wlѺF?FulѺF4nwQ&}apW^N߰} $U(]4Z/-N+|@wK#z?ϼK_xn?bln?W1ھϟ7wص[?;>Uov<s+ۯ@GH{_xn?bln?W1ھϟ7wTu]}i/Yb}mt%Npx /¿ToJ}"2o۝_x#jS?]oIEbZwacq}ʹ|N>gnv&~Ūiac}>o۝_p|we!q?wWߵީ~ t/&綑e_oAC~7n(un>jۨPurmnwQ67T;@\â-|MU\j>|'k3߷;{_xn?bln?W1ھϟ7wsTۮgƚwU򮬴ˈ$m 68` v&~Ūiac}>o۝\g|Mص[=VsyN>gnvu"+%5Bmog.:S7GN4=Ҽ knܪey6Ֆ[W^5+MZRn_m̭ SiV:.uh6-b^}y3sY7tjCѧ6Z6ē nG<|xIGoCɤvAo )Vo2,d3eox–Zo,#h]\;P#*wq^u9a:FyzS_=o{{g;Y8Q8TӞwkHNw$ux soqkoi$D=P=zO_|c/x:U5nI-|MU\j>|'k3߷;{_xn?bln?W1ھϟ7wͺ+ص[?;>Uov<s(7-VOs||/~ۢ-|MU\j>|'k3߷;{_xn?bln?W1ھϟ7w +ص[?;>Uov<s(7-VOs||/~ۢ-|MU\j>|'k3߷;{_xn?bln?W1ھϟ7w +ص[?;>Uov<s(7-VOs||/~ۢ-|MU\j>|'k3߷;{_xn?bln?W1ھϟ7w *ŔzwۼYb}mt%Npx @Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@((((((((A6|i| Lާ 6[;I|G6Wِf ;?6~*}%Z [ Ή+ U]7׮e0Ey(x_?f4;WqRP?K}ߊýj hN_Z]Oukk\]CO<F7 c>=~':G z^j6zʆIQm "3yۜ}E|)F<ݨ\_?+O(mmD:ޫse<捶X w2g?k@>j1|el5?FEHI{k 0s6߳gß|-pQo庞;I.%{hn."s G[';EQE~nuAudinuAu67TwQ`nuAu6-9u_bLu @nq>oGY]Q_!_ƯۏA_UCK6>6x޿KF?Ҡ|?Ⱦ_LFujM7Q`ԛun67T;ESfßS~P'?<9oE=~W>*ڟ{_TxEbQE~h}q־_p'Smk-(\zFu쏚&n.Fu lѺF΢+ $;Ou'J%:W5'r_lgOG37lNp=*7W)^k`i\Ƽ%A0O Cb+U7QD;gh6UM?fQ_EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP(((((((((((((((u nu n QFu n WݿA&_ ۺ/u}gpDwK#z?ϼhf?q >6޿X_?{In?Eo_xU#jP>CkIۨPn5~@O3@uAPn4￳9 \W~Ķ/H+U?7(_P|)? W;c{Kw޷mnwQܛunrmnwQɷQF,?v袊4?¸N|U`MGIڸMW`MGIܻSG>M7WXIFuAcu&u ~?Iu~?5/ >%Ȗ_#5ϩ(u?e ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (?(((((((((((((((cu nu n QFu n W& ۺu}ipDwK#z?Ͻ袊f?r >8x?޿[k;?||KnCo_U#jP>CkI[P567T;M3@nuC_Eq_0^!_SkJ.+#OmC?+~8/i_AۿJ'F4ϙ'F4}nsI'F4(3`+$şJ+$şԿJ˿?9=~=nUR̛u.꯺uMuWK&K@nᶥaڿ8wWsRMm_We(_4^(S`((((((((((((((((((((((((((((((((((((((3u Ի0g&Fu.u Իmn7R W?& ۺ_~G?+n7T;~~@M3@nuCۨP4k]k^?}<3oCq_U6^3]?&!EWGܟ~Wm+qWҾ_>ȃor? OuCg̓PuOuC>M7PQ_gW CI4 GI4ۗ4scz?nF꯺u^Xs'F꯺u }nwQ`'F꯺u }?4;?Z$~kZ"Q>*/F}_EW8QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE(((((((((((((((unun QFun W& __& AM7o,++8opz~ڔ? ~W׷@o?]&GnuC67T;@nuC67T;@C~ˇ/Hn+?e?7_x#jS?_EbQE~d}qOҾ_}~[l530#1owIDۨP5g̓nuCۨP467T;@QE\'/&^.Ww\O&/Wn[KQ͍w#u7WXF꯺cu7Pn@7WGrsSZ~-N~jkZĿKQ>ÁhQ_gEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP((((((((| il hZ;)FF\hk/?vZ> BG ̲sL$,&>x6[> ސM7@R- Yu3ol.r4 |<= ^uZ-~8t6}jiw-ԶIhbU(X>gO 5߄ m>>^ik.6tw8fR!kV/ÿ gӼ[/WVԭ得ivy}t-y,jlꅛ=+ڣO|k?d{/P3fnmW1,h㐩h5xQ~5 g?}>qo{_VwCM ѵk[b-vkh`I;hAg޼bCoOHOKӴFP [PI*-Fr#8`so|m%ះ7p&M[T: Iitmn"O~ذ9f g}"5j~4o/]G%܊bxuydi=UFvq~#"m>ömz͗'6ڊ1`62n'@iAGA|?i"M%3\"rC ~|7៊!:if5[h&\1GXI#YOFR9]x7ǡY h/|g3nK^n$ú4ko }Z*7W;X^Zwacq}ʹ|N>gnvm@Ϧ7TwWermn7RM]X QK64k7pCw{X$VYi<$3^[h8u~?'o+oGYu7}j7~w|_gϛcyx;o|Qko }Z*7W;X^E3&~Ūiac}>o۝_|'k3߷;{_xn?bln?W1ھϟ7w+#OgTu{/j:E֓lysHM_n۴~|AۿJ&Fuϙ&FumnwQ&Fuص[?;>Uov<s(7-VOs||/~ۢص[?;>Uov<s+o |/ص[=YsN>gnvzp?x]o/GG67ާ=Ի7WOuWFu.꯺>]_u}Km˭:nϲ$ZZ)m_{/9]~Imkgnv&~Ūiac}>o۝[tWAko }Z*7W;X^&TZg%EuzqN),K8imc#ŸQjCZgO5yپ'jVgK+O[mYfdF(9g CDxMc^z ~UUVD \nև esRygeF/љqԭ[n/{쯱iXK(c ]@Sn)y\GU2O-o7sh,IY@N] H 8?0s>)ohZdZwSBF q.sʀ<9VKZj4Is5ʚ˕쩘ftөSe+_܆2/{ڝ1v˜#ԟ֣_5<{3>x#H+v"!?0,0©5}Y>i6Я43ELsD"ƬU -'@x| Uս_K+mh{=!= 7K']z_v|HJM%ʹz%ibD1FKl,B8H_xn?bln?W1ھϟ7weGPJ-/6_>_ CH.+Be# mO*gȺLB(̏?=oA-uAo3A/u庿=_.Gc#zQF;2O7Q`'FuuAXf(`+$??J,+]o/GG67ާ}n_cu7Pn@7QuX_aS %,`[JI/DgQE9~FI||EH֣W~AK||G_Lu¿3?zȞjx PLCyPAݷnz]֋I𕗃.<9jz}.}n&9 2#'׏-X]ssuke.6ǬXOK>?uPYڿB+IlGԇA'ҋjJԿ ZaEW\QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE(((((((((((((((Fu@i>7T@Xu n,O7P'_?9'__!'ۿ\O %QE1~2Sp ٪aO_?H- ?oS*5uflM3@Xuf67T;c@?fkN?-q }_FҦ~/+o~w_~v?\øF%f7W4M7T;@f7P٣uCE^Kyů%^3TY+k~-)گ]o/GG67ާín7Q}n7Q'Fu}n7Q'_1­W %M)a[JI/DgشQE9~\~,~G2 ¿ oO*g"1 (1>?WV?W6I?C?o[Q6]7W2MuA6]7P۩wT@ѕQ_W|]QO_%ػ,ۖ4scz?-KuaXp'Ku}Ի7Q`'Ku}(տa[J__}[+%ϼL$8FџeE~E3ԿJϊo;Jg__}_qU7ѾrU{U7Ѿ{U7Ѿ{U7ѾϮc3SқZ$Oݳ;SқZ+?w/VXQEׅQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@(((((((((((((((F4nuѺ&F4n Qm;9{_''ۿ\O~E~[~О+wk ڿNF?Ҡ|GȾ_LwQFkuf&Fu QFh_ BxPGM5W_9k¿|W?7(s q?ʿ8W/~pn?\8F%nuCnuC67T;@nuCQE^Jy$6wVIkk~0$K]o/GG67ާ n_gUQcu7P,nuWFō %տbKJ_M_;$ϼM$#FџhE~UC_Jď^1RW^?¿3<<ʧIṣ̪{@<<ʧṣ̪{@b~O↨?q6e_kg▨?qVu_~&_Oȭz+Š((((((((((((((((((((((((?| %⿊GuF,qS_^MJ9.q{u7Ms~)7įr|+yOxN57\bf,Ix gcg|Ea{+hop.%;2w-2sٮ|𯂗þ-|sCkբZXieyu<Ivh8%ɯ,_H|W?oJu; ,izm"C vRv;vCougx?Uӎ욾"ڬ_M94$ a{ D_a7{z,bYWbVO}ExVi-?h >!5 jڡWNKKkui{oE$>nŅ1F~o?k;W_oaxSw|)y}m=1.Uh3#H` ?Ah#/ V6K6A2Od7% DxO_oۊ|_FҦ~?/+(9 _*_P@3UI?Co[Q.hQf4K7TY4.hQfuE3@MQ_WbG5o$/ط$ۖ4scz?Fu t'Fu}n7Q'Fu} #cK:_-_K$ϼM$#FkџkQE~}eS^ ?JOm[cWJּ&{~g!yS}#ߙGU7Ѿ-yS}ߙGU7Ѿ>?5QRZW ~[čگUi_g?׫ (?>((((((((((((((((((((((((l?8WյH-n,K>⑔1-!v(;? ~^/o~ E᷀5HԴ٤}bM zunY%,@*ٗ<K|Xj5x&}Lei㽥lH0J`6?Nhu?~%ᏄZ'-+i=5ZNY/y΄Ʈ-_:~̟R<Iömz͗'6ڊ1`62n'@iAGA|?i"M%3\"rC?tP~zş| mGpC9xQ$<6rJ;l>Ek ZUg*4/3;Ty~fN4Zgv?aco}ʶ>N_n7wm@vhEc4fF,57Q`%Q.ko w5nm +yd܍ɽFi_OO ^"?K7o,φ~-*3m}|<3'~n-|3J[FeF|'j/߷>ش;>Ui_gv̝qkCt4" H-XMQQ$I~W~qExo'O/#ѺFkDuE`%-f.hQn4Xd#1a/7 |7ciV6ٞw|hhϛQ;w|"%q/7=#zS?]oIk ZUg*4/3;Ty~fN4Zgv?aco}ʶ>N_n7wm_n~e~ZnY|<ӴH,m"ඍb75(N$_۫ @?qۿJ&F4nDۨPX QnuC7Q`?_ n?bҬmش;>Ui_gv̝qkn,? K_ n?bҬmoGdۍE|7ciV6ٞw|hhϛQ;w|~bZgv?aco}ʶ>N_n7w~|SK{{}{S(Pis"PW~_||YUҹk __}_pTѾtUTѾTѾTѾbK{kwH ̰cd,v\v ӻ_ n?bҬmmFjnC[n57P&Fjn,M;@Xw>9%q/7W%~~LJ?g%ɯoO*g|"1 (0>¿)¿~I?G+UO7Wڟ7b}n7Q>7T@Xu n,LQEA^kHZZOG|wb֯rn[KQ͌w#IFƱOuCX RnwQ>M7Q`'_?Ac[$}?e;:Q>?fQ___ocrU~c8&r~?¿3z7o{w]s}&}\I@n­zrJz&a\Էsvu_&_7ȱz+낊(((((((((((((((((((((((((((((((n#4nwQ&n Ful1wW/?'8GFԿ%QE0~~اwZͯxgk oS*5HuwQIQumfFuwQ>hKMU_tŏkJȾB(?3?55L?'55<or?UM7Wڟ6M7PۨPuM7PEWa xŝcHL2$oǟ,G-vtz?Ի7W1b}Ի7P'Kub}Ի7P'_gk#97uvU#}oS^(@/?2jW-~˫d焟xz^8 ԛ7?+-UwѾou&X {7]o}_?[һ:kXjJʿMܿn ZaEWQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@(((((((((((((((њ?ɳF4f&њ4nsFhl?/_NX?ۿ\OR~E~Sd~>/gkZ ?l%ֿPF?Ҡ|OȾ_QCR}n3Fh}n3Fh}n3FhOu_I/OMU_~,ޟ{_TָEQE~^}8{q]o8yq,Oa.G|]#jRnsFkO'I RnsFh}ԛњh+?gرxōgHܷSGú7W5}n7Q>7TEu nOa?g?ʿ7WGεc=W'/C}oz3(¿/^;3kW-A|j||dK_xG πKGo}S(+sR7?22.o}S((R7?22>?RYW~@??5RYW7x#'"Š(O ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (?(((((((((((((((FkPr&hG3@X4f,I3Q$~7bo59pOIG>_KYEWPW$ap7Z~?ZCooJ\v!5H4fFkę53@X4fFh f{cOu_;ҞnY?p'(Q_j~`HN?]olk5y#8wq?{Kگ\њuO.hEsFj-n,K3Qnuc+ E}brקחo-#r_lgOGΦ3Puc6&Fjn,M;@XuwQ6zֿh;*l_?O>~ k_4]~{w([Kף>++o?Y-Duno>Yk1_KGoUwѾw?/o}&{7]o,[I}c_'g6bYW=~9=[?5ʿckK1?b/VQE~z}hQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE(((((((((((>;|ZӾ%MNmM4;t0Xvyyu,v֖;|cv|2r/Vh hz=Ú֒Gi*ucqau#4R.H gOh~mG67Va`y&o| ʐ=\y?_<_I|1֭.OϣskoGZn,5rH$mO zGTN;M-żI4e>PH]ִFNxA--o.5#@,/^+qq#reH$X񿴙v}g^xO}6{Z 4HoN|w$x?%|}mG> }lX@!%CJ`Oo>Ӽ_ FVu{tp *GA AW0< ~$VNc"{ $gp@B +?ᓿe#dg%F4n';Y7 }/N?_Kj#BO_}Fᓿe#dg%F#B%4n';Y7 }/N?_Kj?0'OO_}Fᓿe#dg%F#B%59p?ᓿe#dg%FH`>mykI=Wn磔Աp{nn[m[{߲KG2wDo_#Wڞ_?y+ֿYᓿe#dg%F>$K^۴{>NjXuC5w?lѺdg%F;Y7 }// %4n';Y7 }/N?_Kj?0'OO_}Fᓿe#dg%F#B%4n';Y7 }/N?_Kj?0'OO_du_߲KG2wDo_#WYğx⽟%kfe̋'úw.W'~?F/5߲K_.{G_RSW _O2wDo_#Q ,}_{rϊ͸Cع⽷/5-϶7W ,'~?F/5{_?';@/l>ۨ_O2wDo_#Q ,`OnuA?߲KG2wDo_#Q??'~?F/5߲KGF@P?KEx2wDo_#Q ,1?}gHG;Y7 }/N?_Kj [օ[_;֧)ʟtuA߲KG2wDo_#W?'?}n#;Y7 }/N?_Kj?0'OCﺍ'~?F/5߲KGF@O_}Qdg%F;Y7 }/P?hKϾxֿh;*Odg%F;Y7 }/縟/ }_;_o.UK5n[og^ ,'~?F/5~l}|pl|iM_߲KG2wDo_#Wa֩Ws$+ZўiӅ>~^W}Fᓿe#dg%FP?h|C'~?F/5߲KGF@O_~wѾodg%F;Y7 }/P?hK7 ,'~?F/5?'!?c ӭدwU'^ ,'~?F/5~m9}%Vr2sjml+[MB}[ǁ<3K~=ΉK[olɹCm$z ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (?(((((((((((((((({{^@5u pAt#% w7i2KK$J^7m4b8#n.>{xZv@r0y7ş -i3|-Y-֩\ [f(*OW?w4:_ֺ=iCLl'H/u/m EX+^?A^k/ؾ֋{A/u R їSÐh ( ( ( wwkak5[48@Yو $*x7G|I~"'oSxΖH!p$7r@ɠ~Կ>0o |7񝎳 n<[dڴƗQpGsXf[ZGv:iZd_gfAcn_ a).F~ֹ|6^xEӼ9xmNkcť[˨X8# +1V?xm K5GYimxɕ&p@mi?oF;]vjd!_]N9-/:vfGVԉd˩6?y|uxC@k--R8$ Q]M`Ay-'ۊUď_ |asjbzv\]kF$ׁmM@-+dV# ?hF+Ҵo<&XGW5Pdmm&A5$ƌkRĊW6mY[>I4JDqs[*Ӿ?O @! ,Rk:0  0k(((OO|>(A%*\!^ieV"8ј$ z|Wlh:|:GA,z<7*[Nߥ}رn#ەI7q7YcLW_Mm<4W -rYN&kymѭgC|;o⠎ﴛNoqA>Er~a|n;`r yZ/wo_kgP 麂VYqw G2LKd'홠)(x{:uޯmHYePI>9|K9i?wx Wykm[^֯į.s\Y]gE$oŗiZA[<z׉|w[xMm_F%jh=FH±eE_!z)tY)fKOyܺ E6d_ ſe_%~4< hڌڮqo&nX&im-ъʛb>J~h mu{?鳥ս~&?n/,4uKH+V-fk9f80 c<{5O mdx7dӴb;ch) |E7^xVKb<|1wXAeaeiao r"䴖DZEh o/ |Ns!i(T2Ҽ+ _#b67l_ l>!մ#xþ&󇷓(m3pp_)ONJG9_QV_Ƌ]s[Ln-mVդkȌaD,'ɓ_׺Wu-WoJk}:Ỷӣ0VHH{N1@tQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE(((((((((((((((ƽsOz͗/u;abB_Lx 7Po)(\>,|77K>(xÚSLqxgpJ(/,)!Y 4#YxFy^YIRhZ)ȡ(ꭆ _ EO|<5G/^(>*p`cM. ȖsATCK?Ļm?F.q&_Y Pr#+;~8u J&牵HOyxbo*09IŒ`|H &xG}av*ˀD1QIW>xK>|\_>9\MGڵzO4Sݲgo0Y;RQӧ$ q$R +)H WC^|3gtmc>pN)6gJbx`׈|6=M(/dr>1spȠ 0+':^8`#[* >gց+b@d{@TQEQEQEQT ]WO-TvrVЫ 2GPA >u躜υu82Y5fkq'̑N:"(|`e[⟊#ޙ,m׎AvCI+=d?>QHҾi%e'`zC\L5̒ؖs ?jm|NxS8>gj}k-47J$$I@_ ?|>֬?eB6(ёVS`k%ῌ:6-C0w!%s#)ae(k2^5hvMăE; {LRщ xR@:ۊƱA'ck}5Vl"r %?Y!fn>6FCI ̹ Xfݞwoskר(((EI Ə ꗶzwSFrQg~8³,XY5=Yį,n_h=٤\N/*Œ@~ oskx'Xm26-1YHg s~8xƚNV+01}k:m$M;MI޼HDWiuP^<ϋ:$)|U+:ܬpA>-fpdhvxI|G[΍I'M* y3ćI,;O3:`WZ|C{#I[W٢s\$.r\ b#|9?(jXX_xO <{˷X \9 wp?f(((?hgG.tMCUn5;9++d7BpN)6gJbx`浏ϋ :a_ |_Cw{P}Fwo{ʊqҺK':^8`#[* >gց+b@d{@$x?|k#\hQeGy}v?u=e|-_G¯xLvk7;@&9cpDH;]TAȿ5;>VοJ+Y]D3gc kܴcKִ{Oiw1i[ܩܖ $d ڿ1Gn4vc(((((((((((((((((((((((((((((((((f>^߇5qye%I"X9P{(_q^/~{]zu-+\$Qȑ |Hc_q úUWgii&/5^ti:e1gF'}Wzߊ4GSѥLybtY?u+9@#>&_.x~1o5kxlwu}CKVb+;cT_L[h f/ ton ti?Ib[dqnDHxٔxi;#vlr\FugUp:((((>|m[)MCF,4BBʳFK(Ub20smjn.".,sZ7+yRDbp}5 5X3jbxŲjW`Ē,2ʎSMdO<7|0muKKm7N'k;Y%rD.sQEQEQEQE 3߉_0iǏoW)$ÅvI?9+vb O?|0>Bs5PKF~Q![⿉4(o|WॻMQi%V[Z:.WyY%kO@4A>|N>x~ maMhXjm%u {Ka /|W{qk^VW>m`$VGj@xd>XO[:;t?Bլot9#xZ!gPExqںM_Yx Oo6$JwkO+Nׂ;Ha*~?ta49 Kw,!ec37`Oe5_mz?/ōP:mr|#}'$P?68<7S̫ԣRM(RӼU 3i)ՄSc5-.(n-Xne0}%u L@]uCgq3_ׄ[^ŀ_)Yzzun7$'ȹb}+jiʮN|[pV]|Mt5#Od[eѫ:b+#) [s UGSW 4ϿM5t&8(}H#𯅾' O+Mj[<%( Μ2{WW겫}teTqJ)+w#¿[ 5՝xPGڇm$r)\'msg;lޟmegW6ր݌dĝn#s+$f^}>yo-ۑCe-5 46  : ~EiE|''hE((((PK9LLQ 8preview-web.jpgJFIFHHLExifMM*i8Photoshop 3.08BIM8BIM%ُ B~" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzC C   ?(((((((((((((}d q8_RVOLNtasǜlIXOSzwLD|* z4ާZiLyT 2+*yqO?Siz{eėV\vK(ñL66Ey SR .[! XtRçW<\pXW, ,]6_iG-xb'vST3z: %m3U0%ramlw 7Sqe%0Bg }׾./񔳙DѮoX` ^sY s5EkkQƘSع?Di] [G]L=ndeȢQcnqX_C{x\/19F%v1H%s?]6w@]Nwm#1^c/^]Kqimo,&FQx4a,U n35:h+-nƥEΟiYd۵e!//wH`p;ӥm 7w3\N]}5Xߟ8@ύ:Wہl[̨. eݒȰ)RKtBo_sKE̟BxL@MePAwa9B5rŅ櫠Ħ md`>jg/rWЊ"/"/<7VOtKLXH!i$VX{ݱ6h,wlcDb F)lslyw5 A@ EPEPEP(MŸmT 9 8SW|ypO*Fٌn+ʊ7s_z=С^eҭ'ˉ.,X;0#mX5/ mt7PWxfT?"G"㟵{Dž?Rr/ګ+‹<9ZZs~˼:ש~h|Wןo5s_d~Ů^V '?\zi|dW=!x-nڠZ+j9?׀!hm.gZ+#_%|Fc_%3'X״خ%:B$*rOJO%)`9 y_zד,Is1ȗEYN! Zx?tB+nchsxG9^O7q\HMr[V=q.vKn9v80`G7KUw}#Ju@I2}|++]AA$ϱs)cVrWY-EHŢ((((~n2:j߂/.4߫GrXHB+. #4I,RsAUvj~PРt^ЦҬˉ.Q$;0"`|j$PWxc%H#?ۿ\O=kJw!_jןmyF?j{j?ɟxq+ש~h\kro3LG_:ܟsdžqBuF.ߢ}qhŠ(((61$g~b3~^u kSKUQ/n&A*/ )L|ӕ<2b\~dC%__}|#6>][s9,H2aϏ(ӬvS'GAu`v[4^s,hT(((( A+6ڧm_‰ïjs2qo◁~z%ƹVhe,X j`⾓d<¤yZoS縧%mTS+z$CP?`V3'_[Ӣ|fK^qLM%!f' m ?|o7oEy-oVpCG䁳cr}x)Ѕ:>jzk+|iԬVdEo|RHq/E_axÏ Yi>olږ&imd >=/I|1z-=Əh*9 {=2K|Vfyel0򋚵Zjo# q9vcK:JI]/ۆ跶)x?OjCتrOdW)#YHf gqyG|o̥A[5/*Ѭ{;;bCx1G }}3Data/mt-C1125456-CB99-40E9-B950-F75BF800AE14-85.jpgPK>1GtO^^=X}Data/110809_familychineseoahu_en_02390_2880x1921-small-10.jpgPK>1GLtXX3`Data/mt-E8BE52CF-0FF7-46E7-BB78-0EDAABF659BE-83.jpgPK>1Gm?OpXpX35Data/mt-1D92F908-FFE8-436B-8459-224D94590240-76.jpgPK>1GMJSJS3aData/mt-DA150A6E-6AB1-416D-A055-09ACD9E13F6F-81.jpgPK>1GK.M.M=Data/110809_familychineseoahu_en_00317_2040x1360-small-14.jpgPK>1GI˛MM;/Data/110809_familychineseoahu_en_02016_981x654-small-12.jpgPK>1G(x GG3|Data/mt-5392479C-4C8A-48A5-BCB1-F280A815587C-82.jpgPK>1G?#*B*B3dData/mt-A755708F-7FAE-4394-A6A8-F317C0978966-80.jpgPK>1GFY8Y83Data/mt-D4D90C95-2A35-4D4F-ACBD-6EE33763DB0C-78.jpgPK>1LLQN@]']'4?Data/st-4200AB5F-6B58-4177-87A3-C525A84DA824-189.jpgPK>1G638gData/mt-2FE216DF-9BE6-4769-9976-A6A5D75FCDF5-75.jpgPK>d[Ja3~Data/mt-CB0B9C4B-E625-48A5-90C9-DBB6CBDBAA58-86.jpgPK>1G"3ڔData/mt-E29FEC89-CF69-4791-93FA-E3187A9FB759-79.jpgPK>1G㞉3Data/mt-193E61BB-74D9-4ED3-B8E9-13631E84744D-77.jpgPK>1G?3Bu3Data/st-615F7CD4-E262-41F7-8138-806EC6AB1FAB-74.jpgPK>9LLQ3R  Index/Document.iwaPK>KLQG24Index/MasterSlide-9.iwaPK>KLQGiIndex/MasterSlide-11.iwaPK>KLQuʤ  Index/MasterSlide-6.iwaPK>KLQ`++Index/MasterSlide-1.iwaPK>KLQGzsIndex/MasterSlide-2.iwaPK>KLQ߹A!!Index/MasterSlide-3.iwaPK>KLQ60Index/MasterSlide-5.iwaPK>KLQ>iJJdIndex/MasterSlide-8.iwaPK>KLQi3N Index/MasterSlide-7.iwaPK>KLQ>g~cc Index/MasterSlide-10.iwaPK>KLQx;Index/MasterSlide.iwaPK>KLQw KIndex/MasterSlide-4.iwaPK>9LLQ[aIndex/Slide-4207.iwaPK>GLLQŸAQ#Index/ViewState.iwaPK>KLQPm=PPD%Index/CalculationEngine.iwaPK>^0GN.!'Index/AnnotationAuthorStorage.iwaPK>GLLQA%ii"(Index/DocumentStylesheet.iwaPK>GLLQr44żIndex/ObjectContainer.iwaPK>GLLQMM0Index/DocumentMetadata.iwaPK>GLLQSYYIndex/Metadata.iwaPK>GLLQnBBqMetadata/Properties.plistPK>d[Jn=1$$Metadata/DocumentIdentifierPK>KLQ| JUU"oMetadata/BuildVersionHistory.plistPK>9LLQvRR preview.jpgPK>9LLQMmmpreview-micro.jpgPK>9LLQ 8Wpreview-web.jpgPK++r &hamlit-2.15.1/benchmark/graph/graph.png000066400000000000000000006166421407657076200177550ustar00rootroot00000000000000PNG  IHDRɺ_GiCCPICC Profile(c``I,(aa``+) rwRR`` \\TQk .Ȭ]m)X͇p'?@\PTd+@HQ@;b'AGjB@@rF" @Nx:j/8xYFp.$D;Teg(8C)U3/YOGȀ՟a(!DXm b*[*H,J;Kqcz N.@%\E_?ReXIfMM*>F(iNxASCIIScreenshotU i pHYs%%IR$iTXtXML:com.adobe.xmp 1304 Screenshot 916 `iDOT(@IDATx nS׽׽$S,CdhPk@C!PQ43B D*$(L4hؠ2?}y~yϹùkw=ϳuLD! B@! B@!D0! B@! B@!P Q A! B@! B@7t(B@! B@! F! B@! B@! F@c)B@! B@! "B@! B@! }CB@! B@! B@`TB@! B@! BoD0 " ! B@! B@! Qm@! B@! B@7t(B@! B@! F! B@! B@! F@c)B@! B@! "B@! B@! }CB@! B@! B@`TB@! B@! BoD0 " ! B@! B@! Qm@! B@! B@7t(B@! B@! F! B@! B@! F@c)B@! B@! "B@! B@! }CB@! B@! B@`TB@! B@! BoD0 " ! B@! B@! Qm@! B@! B@7t(dFK?"oL,Ly>gΜt)$~5\3mtp饗(Ҍ3!f͚58e937\iO{Z:KynkKoqyE஻J'pBYw1md9=ܲ8/}K _|A?m&Uzo/n|gU=cUzU_fΜnƴ "[UWMmݼt+uYeI\rɴmx.2 +vi?O:{yV[5XHOwqGWӦM+mG'fϞuUVIo}׵'x7ӧOO{w1:Ë<8∾IW'IG"@l ٱꪫji^tݟL'z׻zwOMxY6h̷e/+ -oe]糟lH⢋.*A4Y~c_-J&Ay{^w^>Lw"p}ϋ1-o45[몷-Uҳ>+<9e:կX+yы^TW\QO^򒗌HGk{&:,HS?϶Q'}4K ! @@cM("胛8c/;[1 Uisu]tт0 iZ*O0".`4M¾Z{! )~WnUId|**cF@!2 `2jT|{ԙ5>OV!]B`aL){D'"`4}Gc{#`ZFUIX>iJ<>Oež/>* O!Flko~s2Ҥ<"V3c/ a&҉wi_lJ7ي9׾򖷔3L|>MӦnZ@!P_e&馛n 6k\rIb-x?'߲:(x&lR}na|o|i]v)to~Su{uOLzֳǶPPy^'3k }k+U]y]%F0G]h?uL/um'/~> SZ&٩! 8ߠM#<ҡ. 0 #0U4hB`Z6B@/#ZOo@g7_Q>B/ƶn`$ͷIØݗ/ F ltl,u& `g>Q hN;ql28NL )sow(`^ו~;Il/ضƄb[i`\j?V:)/KeScuޡ n--e E0N2$g?+瞂x3P~ _8:?Nڜ's<]ttضʚZkd+#يlA@O>8]OJsIzZegb/&| PGV#lHw'2XF&1zk,`UW-ʵJ+~?!V\-bE2DgOEL̇I<_^yGStw퐶x'Ls[׌2t-v!K0{EѾOzaDo+_җ&ȍ7ޘg Ƙ<Ўyx\s̈́y 򔧌OClw={PFms,8Oo[[OzIOr;0)4oNkFFyN_u/'?I>hч:s^c~'xqG'?^7bFm 5kV< IqR&0bM<Ȓ_x.=59ߐk&2yힶ ]|__u9}!υIf;ûKw!C{=tۆGAmiM+6;Ҥ_3|衇}Ÿ碟}P +FĤck|U'큾vs\(#q͸w47pĻQW ;ثMZ} e5_1nB=I&0 2M06` r~mOo,2Uc^1ޢ(c6W[mNOG?IO*W+,G6(+RoM93^w'= Fu];AK/t }1ώqx [mUw[Bv޺<;1]\\|#/i2KiC3)兩v`/D  g8F5:2_sر4rF to6e$]9AP=yOK^N_tlrܱw ;;6xJ'DZAn&'e6A(̿G|&vlT};zhgiR&6 ;Zitt>ul@YY&0YA/f 1 i$wcλ q ό_;K.袎 k"=ֱ ZCױވtm 9ꨣ Σ1\c`nD6JbY#3t^WVK&ey ;+",0,uX4k]ۧ99+g}vW^6|u/݇rHN{T>C6۬chMmb^ĥ`hdLjY7CEX0IZyts_qWvUGqĈҤOrrl ^M^FUu`z۳OH/џFԶ-'pB>ַ{d䢸o>x;F|hF<vc & bBiIe޼_# fzץE?O(cŲ|NhP/]1__yïO.ejFZ-cw"ͻ&D|Wڈ-Zt[N uxOڈxE۬K_~6%KLx=~sw޹|W;2/h=S7c퀍e^F7&}u.3VӗoO>_bd[gwMt.^e^N߯38gŷ4HרyU%M4zUďOi 7ď/2O Ez*=-u#wM rem|[qLOU-ܲ lgXUP*R1hy4B,W.lL ʒ1@3WƇjpɿ wiJ0B]W9_H:bj4M+c6|#@ aZG ]}尽~P6Myz#5ͭ8묳F1 ׉G?Ѯk~$nUq_iT `_;luu-9uB\Eyd"2!)JL'9=D NDd0ł]>g27Z ;9K[ki||qת!yoY1k|IO4j4MmtnOmf71m  x v{]j>)/1ebdf* $Mx _cӎ*{['~gb_w T'LyK cƽĴG5b\ۄiU.z_H넅*bsdѷ.^ue>,8#wǐUfiӃk36`÷Ili;vnj-Yp1[S> fA c79N@">w~ݗ*"Sӹqq7jQqVVAI̋jбFc,Gyn ]9 F>+F}\QƋ`dմnQ9'ȱlm'9=[ạ:z>|s:LG*#Ϫn]=M?&UCGs\G0Ӱm"z8V/ 16$ZQfR&N &R?Xeb\G&! Ul$#&f5(N_G0Ɓ|G&g'AL&~ \f6XC0 ވL`Jh_afݹX]uP5I]G_e {G_V^BE-17RG020Cs|>}stCV9UI<&3j6tIJ 2AuĴ (OQm8` 8`ЅIᴕhp-)}|vQxL DP&f>,T|qD ]WSC:&&1u#0><ST4xh1@ƌۇ|,f])U~?sdQ2}~ 1d]ЪDkbro#>QphD#ig *ldL{͒.u*@0ˋ™@O❏ULO0ROVۘAfj04!IyGњa8<- LB>s䬩`gB4:~r=o__`sd&%6 Kh6z-²R%./}Fx6W>#"}x/| \W֤yx0EWFGڼk|X9L.{ ;9,|/$l_Uky|zh_CUY| ;&d&*,7B3Q|9f9Icd1\$ Yti壝 AVH*R`:C]aXeRhi ?툱Z뛱W|9sգ5O)H#,?0@ć"vF^Lh1TUQKyTMnyxL6}T/b>j*rU@,/CUkL9.'$1̙|}gb1E[+LDrLmViUL}9y4Ʉj$!# .0An D[|F0LU\&U³4>*m*o 5/K4lƶI*1eP%D }9FI3DtΟ-O|ypB,Ga0(˵*_1Mgb[%U~ ֫!QdD?hD,  ur޴)ȼׇ$ t'-:y{UN2/ë)ikq!`_4!|=uc5 w|ϨJƍ}f. cH22wDEا5U>c7zVrc(Q[IXdc.'wxǶlX=YY̏IpNbsvQls2Y\c_qfx|#:a%ybFzH\!WiDyy|!_wO"Q2 &R?j1[XŬ4zB^xfUf9<}I_cV-ZEM8O[0f}v$FHhZ8C^tA梱IX Xk B)Y";oFb 6Q"lDMHbaAԦqPU5V1U oM~D! &2='ybso\\4}^yF_vL}1H;h F^!y_ P~|C_5}x#֤/qh-5sYϡ5bVbۙ,"'˓P9V,} \/ljz/C F&M`Dm*H0֭^ *s;H82>~@qmJ0ƕ^lQ{YhK5NjKc4l2Jsn>_켗NdXQimįG1&˷*s62Da.c!b^<4uE;"f/4dYC*-F")Z>-a%i~&8ψz>jHMV26Bq &$G4K$@KI:,6ֹ=#DROB'%ҍ=zcaG{xtZMUxB'yk`j( Hgn"]wݵ!{oa&{e/~A6 L~c%26&HaXh9f8˘ݧƟ$Muf^_|UD_`dF8!}YXߟ8s8OƓ`d<ʢhK[%_7ǽh:{~#1,#. 6 ,>/~sJlqoeĹ+㕩("SST:.YmΙy3mH0FmF; WD伍)P/fO@M9 &k oaT}eޞ}Ry/i}'16q}`q.L`ӌ#|_&!(4o*;H~& DnWt!$K$Ky'#!LS#} ߛ?e#&-ȂL/[$}?E{UƜG'+ث?:vݛz&1.D@iC<~Rʆ_/3ڐ->MǞ`Tk#1҈ uOmdyca=a|=LP!Ѳ^D24ԝ0Q{)kFj\Wx=N`D_zHDڰq1@Nw#Q6!>{ 1T_h- #I֥Swa=O۴Ͽ ؖhAէ %UF :9M~}_{ߕ>x$V̻vlXKt纱?[}*}Ѿ SXyT*TE JcUzUWDE)׀c/H0Vm-Xi_VhI$MJ0Vf/?_]#&r~#L+q7H^45Z0F"9D ƽګl#yn1hRGf>H@f.hE\g -&Uv_^&9}Hh{c9j=)a/-佗"/s۔1Q7Y ^Q${wh"3co,XSShCdkh=XX&nC=7DVO&їh)Exh6pc9Ab_iկDKWD.D̗[^61dyLs.dc2<>?59_ubd.'p-<z2?3幑{&S幙H's^ddXyn;s& -iHm`ys6LIF\u{2m#py'ʒgb&4tTl2v,,ϛl#dn fld|ML ڭ—tlS6O,{wZi21?큙y%[n|D8̥AmLF*V"XUmJF^$$W==22$%,m̧\y^u`d~oFMۜ(va>*A _#:vťm#)Na^$eD^MbNiLA:dѦ7I0PIl\Y#iwVƈdZ=BK6<'؆]ђ-ۉw&y][SqtlnKmXdL?qlHTqg1dh>)L+}cf7 ◱+):`L[s@RfzFqy>ьÌ.Ukf̱0G4 ,|L81(UF3П[A̭N)*$[,~ʹ{Ě{ m>i˧CMGxNA\m猇yĹ4c21>ؘ㸜F3nv俬5mӍq"5qtԝձuc4KncWy7iC3D5T %Yۀ*j5/} &wuWy;m#>Z&+> ֙yh5Ƹ|Lxk0]mĈx^^kɮHݽ&"uovCD\>?m$[p]Z͎ql;T՜x^~" Fb/vaGܗxEEe@wN}`$I>r.~82!n请ScIrHb{iSuʼn#KfR>`~Ƶ丼˽$:\g"ӏ`=ش29״;ikuLXW!$.D'޾Em3\ w/S`3sN^"vUm[l?D-}{m|_&nWI6PFgĉm\/>=q4^>|ܿPfLw4M펣u?x7fkF+N |Z,y99#eooS3ޅF,_>c%!`ۖqLr|s׏ &mb,]+@*#Q_>ʧPOke4m^4I%چ`l㊇A0;~tnD0DPHQ!L1mXp.q2<a;2#)G;bfAeIXa$xl#a0fxc%Ĉ!>륭y 't!^c\5\_5٤&K$6ߪXQu>|hYW>`}m|?HNVny ~rM5FK0*ey~>WWf^oM0B68LW' нq3ϸ@ŧ@0F MB}Ab^ |˒LHe@WG"7HJx^+clhUIu]{`ZmEd?G^,L8a, >c& 4쀝}Zmvmo1xw*gơo|<M1c^» Dk C/a^&+$QQ ceIN/jn/<#2ako3=>A`V-R35}qTSS >$q`::aү\1Pf cn~Mb><³IF0*ߤ18+FfǮr1Ytcv F3C3`Ϩ&h3&Q*AÛꪠ=C02q!"Rҗj6/Fp 7uqЍyjtED͓K'u&&qHZELz÷ohzX F,U`db"]LכE$@FMS IW =yQ2<EI&lQ$~?*7_>$\\$}E7")D|\q19YF6 ".a&~ x[W8-m#2Bjgߏ9pUE=X_m4OFSe6#ec[U Y`w{qL&U{HF ]x=^MZpI _ :qd|,f!<ߎ3ea)'8bNBx^N6J3B|+DK- A0RyUWpo4;u2Nm~4Lx2v]A#mhe(mUfpNU8U=`¶tutx`%?>+QsyYpL/LF]q2j~e'#RU 'jN/Dy`uԐ# `עYє`p2zk  Ĩhꈶ^{RB2_Q9WU_~ē.=ӾD#j.FׄB.~r:S3fch62!8 FuA,AqNU!If2b;67aiO(+?QHlgf8;W,F#JT5HzfT!!zA2.L{F&B1FK+d')g4k>ې|&xV>Io~8eƂ.*/+Hy'by9{1!|c3euI,cGLw\嘴PtByp,㢴\?,@3FFwPG0o61&|zWE0Bƍ(#m,V_N"ް8߂(gAƲn~ Ɯh~)7)TSɩSLb!13YCئt=&'U 8zN&GqU|N}x̄ΤqFR,Gtu~u8Nuq/munTbisdEYM^s|+LY[@IDAT ۔/aBD;yE029f]t@sN`u8]vYe`Y₡\uNFͪ\xɸpVN^e t$rܪ_**N5heՉÍH^wo@N{A0FwX:d[w,^FM'U+h]Ҕ\_ 9b\%U$b!<&&NHl7卿,^DҖ+ # W|N1 x"7oFgܔ\0SUZ\c]MӟL#jF3X7&U批NE0L{ }XeN˕İ#fhM` Wi| X15\͠z#@J ׎#I6h\um\ֺ_6eՎs~~,/ٴ!hW?:W# &"{a:2t1)_I4HђI0Rwo4|b}9͚%~X쨽CS`8F"9:>kL*-m$j, F,%ع62pv"dE)yI0}/?A+(7Oʧ }L=1Yhz6Oɻעܘz?A0^s5]}dXl{i1RtEooU|1d, VUf>]4{oQRb} p6m8cH6l7cALUH7~cs=Kneo"I,# d2,Rү^LVh&3I.xLF$8'8$. F}ؓ,$`''H%`F%ӘVE4SM_K?n QLqc1odl[\F&$0̌H&:&=ɴuOl*fyV6))i\$kQSޯ:(mBy"i$3If̟VUkFR$4|m>*E6Hf8 EE޴CL6)!m!&,V“T+ m&"z44>6l7e3|F~4Yr6 *xnIX)+ϑwh<&ɴw:N6Hf"Xls=𮍦MLc7U HxܴEvRϫ~y3>ϐgY' Ӿ+m&&&E_dfjETqFzHo]Ў5SdCEduqc~9=M»c>: o#sFfyg1ަMQ 1͗oJ=[(GO|G]藌,(xϙ9vױO7&01W%%1[ ;Dٍ/!#uu1=1,C- {Tf942 .6*m+]xE_KB}+|.F `=*fͷx=c5ك=7ۢ1M]98(gIN/Eԥޮڢ}6i]o#\pAy7_3C. MAlLfq"㎦o0\÷O-M|OͅGѾ,K˱I!0MVڮiϞ4iG8mWcVԙ1mӈdnE>M`!<hf4{֓o3a8e">S"SQf6^׈d eSL{6&Z2L}3߭*a>f 孺1kGy@lgW,;Yl!=|:~E0NG C`ZFB`2JL6!Hq6ي9abxK8yL ّyTeA*;}Y Yh_]!;'m#ĝagXe!aBU2I2E! Yx LU8U-0U! &=ԛf'Vy^u`,o}O %yɼA-=4WG6A]2 mWj]g%~fM|F"[4xQJ"S` q0j!@tJL _w/^2eLpJ@@xN*"`甂sZkb 5` 1aMdバ׻s`"`\-*9ݸ"q*?=] "AB@L 0¯,hI&H] i;Z}sXM;`Z{0"b)38cg0(#'~gkM/.77_D[6ɗ;@ه'.p?3ET*D0CTR`cv `m8EyA`S/`! qj3`%6ai1?΃D0Aه+h̆nXKl7ˈm~ \|(*fJ,_NU!0%8% -FZ%Xs뭷nE"RQ'>:}C*!-}D0LZlsᇗCݽW_}XTt$=j4"b#! &B`FP'xb:] @CN:Iu uU'q7)q9;$;F0Hj=yoMto#pg]wݵr)SFs/q.:B`1;!B"9snhd[, Er-7 \& .G[Uf(AMpOd̙Sԓ#t?oOwygAN/iWLmYZwus;t:4{좆̣:("qP!B@! B@! &B@! B@! AyB@! B@! D0NR! B@! B@ "IB@! B@! B`8+K! B@! B@!0(`'z! B@! B@ @@,B@! B@!  qP!B@! B@! &B@! B@! AyB@! B@! D0NR! B@! B@ "IB@! B@! B`8+K! B@! B@!0(`'z! B@! B@ @@,B@! B@!  qP!B@! B@! &B@! B@! AyB@! B@! D0NR! B@! B@ "IB@! B@! B`8+K! B@! B@!0(`'z! B@! B@ @@,B@! B@!  qP!B@! B@! &B@! B@! >h?|jE]tB13gNzr̚5kN?xZ|Ӵi롇J{%; " [?oҡZ$KO?1ImRI/x ҇?)B@! B@!0y#I'^W>t饗˵y{V[mUyNHgqF[ ҏ+B~Ӿ[2(/NGW\׿Zhk{ zɏ~tQG믿>_*Cnmo{[z[ޒHI o;.-UFmg[4%x/N[neo o~3E|裏n B@! B@! F0Bnh>я^xDM6$]uU#]@|=Ǵo# }.o͗s=ٳk㯱vzs[L|}n@B-2 yfteUk GstgY'?I/zыr1+B@! B@!0/#&/yKFxh.q Qw˵U]wUo<ж{'_xi뭷䢋.*!1e΂&ys=R$Ӟ뜠x!t]GS?]_:͘1:Z{u4sg?Y7K=_{ 2:E[xmF!B@! B@!0O/#}{ <9I_ ^4;S? !0!#dز.=|/}iB; &zjy \;uw}{o{Iz xmO$3̂4#33@coK҉'EMoJ_˲qp뭷ZԀ_rlғ!YMP/hf[pp ^[h{wA |ey>^۱_BsˤB@! B@! Fu\[o[s5;+432 gni׽'-1L=vL{rDtY,mbiW[pDFu^זLs}u3si%vɽY}pF^z鎙ct'cae^r'nPsii/4M6EjB@! B@! "0IǥUsv^]v)uv.}3v.XguYE67̜9o## k;0m:Vދh1&9ex3.X^'3.Ń++1H㹙͜65\S3+ڕ淳OZ%B@! B@! 8ciՕĐi5yM~WxX޻K{=tMyX^:V:!UtPU'ʈ_//!m|e.cxy^$lPir2wܱn;U׫ljc V{D0b0ezgu-0 92B@! B@! /`|:_}g4:۴$W=7'.R58ȳ#8cŒ/KҪ1q-~/i][$hd n-oyK~6*1C^ >۠Wm 3-Ӱ jʲ." ciOfR^yӟޓ\.ׁB@! B@! "0 ƶ`݊K2,njuτYկܱ]adW,!8#˸d_j<3!ۖ_J=!+LG>6/2}wA}A?A?A?a2O(O|"}cK>hĚ,,v!!mS|VYeb7evjD5ݥL/}O3fH~j4 `8G?a@~viEЦsZo Md[NcM{SHE M~s:̎߈i&V^N׿U9}=:˻~_}mNx}}{P|{P|{P|{?v<&rd7*_b|=(`:ka0{ΆnXGF0a+FZV/zzxeuq?Q;)1U>tMg׎mvl9gv(iO/ivivd<~ ^ MD! B@! B`>oΦn:@Zi:sθ ?+?H4tc~sӧO/|[j ouQe<6.d;#C"o}y|.ïeW^^曗 uhZeڧrJW|bZe5[lс9IB@! B@! &J0uY]>C-HH[aJjv+5Sy_FobWk1/|kVI'T7߉e-kv/y[ZځheCJ؍;7}^K_Ң,CG:f#3 zY\&F+a! B@! B@`[&^ulcqOE/zQIJo.nESa4隄]sYӟmP&1ex۬ jחZjzmQ~=(jlIy_|2'XZi;"xbFя~A3y'Y-?O>MR #B@! B@!0f2h饗V lc\vm=.2e~9K6N)c~$sLvVk :^4>GV3:\ ЌW2X wvtvw{6ʴmމUx;hrBVKB@! B@! ?`` J"sW!yT53gN?j~.#)˲bu^<`CL`Nvso׆/B -TuWa!F3lrR'\pAݹˠ_}y:5rH|fFۃ&5yMvF(f`~#yu ^. ! B@! B@CNLL-`O6(Z2*n!-#f^23tus-$kXzxFo뭷Nf\8L0KFozᇋkMc}ӸLﰼ/~19F7 6)S^L g&_zqnaO~,spW4_}]aYgd;gז]vijɸ7|s2mt}L1{vߋ/8mE%X"1i?[od#ҳݳ/_^71M?ҫ^tW{ŗMi4yu؄úk@aa>;1V ~maD! B@! @k9h;'#X,r ?lÓ2뮛;i宻JKff /$UC=4(-/ʸ&EX̳(kFA^rZk]DyV]ud%󡘾/",RxCsstG$.KaKy|4&3/Ed&̽~%ɗ#}6lɧf>^}\4?i+NmstM7V[RG0~k_K!KmL g}vZs5?NlM]\7D[[ds#hvfgp"42qx>!`>&ƑۏơB ! B@! @{9;o~KBz-7>ȯ.ȅHiVJzA4,4s3-4g͚/f>"Dh%-ã1F(" '*|D`&1Ohf&&>xq뮻&uC2h{fHGI/~<W\ A/J!:#_0_=yIs9Vgi&#@(i;|5˛x ƂU%\q\qX_ L@_r_!UI! B@! yN0_b{aݐ8 ů ?~d"!B@! B@ 0 faB;S:^vNh De4KE6t?)R~=yq3i̓G%HqmB;̤_D0_} ea|æ1hC.cAz"1p GXzU|\vԇMC0[d=Gh(ځB@! B@!P&k4_/+_J:3ZiM)DyةVvRgJq܌§OO՞2=4{>I?[H`) L2a2El3lPQLg}"]k띴Ғ/[(oU{NQ9G´nI{Yң;3?=vG7YsFZi)=jU⋤3WV\bZzʓ,vm>ntREyZ3#pe-Կ칝{e4Dڃc! B@! h6(Մg}ݭՈ]Ě,Bc76Dx WUd3MSPȩKcndݐ skI>Hp0#^PzZ3#f7 k>-+nԔLO\'4YA4|L

mz:i\L(#׻c*K??>z~ -lxûm|C+>B@! lD0U!DTA "1D5ν?ve"$h'~s?xm9 g=8w<r$w%274E (=upn!@}:qSp<;0T#Kb–kHz^4g{Ma{LH/Y,OD:bpi׏$nV8i*]:g}0~GWegD -NbׇDFbл3CC- !/o C D ! B@B@@=NUfA@0.*:Lr^Ѐd]56[v]|7InOyg6#$ɐ4`/<\hլur句naEaӔpZUOwYm2BSoa{bm7d.8z>?[GLZM .05@TFds{}@o~IqMѿB@! A~@"/֠WEC Gf:^72)`ce<-q@FYi;JK;3n{.͖fE;74CS)f2βsY/3r]kOa_.v.+ZL ġ _(2Vm륞ZCNorh'[5[Gjڞ]wMsI Ia('㶞v$;Z'ͨHMҽ< FZ0tؽw%!b>xw% 4~ "iO#B@! X`=ov@K&>) BP;XzCXSR#頍fMf0~NfN]0'0$6U,u{X:z Y`2?M_ԔEs褽}|6ض9EzfZsi>xZY1Y4 EN,l.̽sΣ#ߒM]u;Z ?Mg)F|0x9Nl?,&҅_S&sD,U ,k>;c翩G8.t319t÷?Y/i `RXtC{{o> hI~ǫ/ȴbQvK?Єb֟ESZ26 '6X~̎7zFyYNd=,0<߻pn/_?;}aDrl9kHq$1[Jq$i3̡.YJi?9:Dy!L `ղM_rnAy;l u!ã>.?☓'$gӶBB3Sl0C>~g;S,y~0p' /2'q-^Q5zo$[(XM֘^t(/[;R$ݚmiW{6XiDy717Cf4?G#OD"B@!0`' C&s9.qxB]Tڎ ;'&uN1OG9׳ӗf0Cwr|HEŕ\BC 4N㐉4HpY8,eW0rc}" ֌jF?dO|(M9#EM^rrŧwvjvݹpVp|YY0+y3^v$IAFM^ yrdR<TEn8}DmҞSM/D:|nW rO>ͬ43y]v0|cƐs^v=tdl0\7>FWJ6'}˼|Z3z?iuŻ];}ߦy٦UD Y]B@! 4D0U}~n&>Ov ]3b;K$~|L#If#WyNfБf§ G<7dB`܎e憁`@g탖X:-KW{uY7]hztM4f`4?? 5^6צ؄9V=fϱ-mם޵a*܍wvX-G`9t).yRp;P0)K5/nfm`\kQW[wCOvf|a׳Mwv?&3 v~GlGcԿ4qzsf_i$DE~p z0]xW6alzaztiGo?s<3{)-sW{^:}]Y ?o?Gf;'|_Ÿ.y'7>H#IDN^Y/o<B@! \G@\aߜC<yW[1;6 -MF8 :޿+\o+ =H4ܒ_at AZ Zeܨȹ.=6X] mK^03*|I =߼hkD;p\Meai:MK8|s^yOQ;lqahzyw#]1k~M/Rv>Oni`;)`{C'PjԒ M"xls#x[~ᄽy1LvvUvU~0&V1y!B[?~(Zw4J_==iq[&6#wlʲ:vp<4x#[xdI~ż Ř}Bj]%?FԼ_3{ݛ_ͦqM<۰-IXzKsiB?/K$"]B@! sswuos`T=m|2#MAӹIL·֢kr:yN 򉋣KYjzQ^玁xmKzi'*3YX'yO7c}J!\e7XppI8c& H㤾c &,ӄsR@&t3&Yֺ`3U 6`q:P5uW6G6#JLya^p[^!^[i??c{?qa?TÌ(Nλ}1c^y^8VB@! A@c9};#po.H0N6ns>h3:x̱p~3@IDATqwg7Ҽ){_- 74skG6HBa xYش$l<|0fH5z5VrchM$Ys'fN%/`L](_s8Z͋.$”{@#`$o[S+*Zq"~M)~\ ]q[#uXrUȩ蜖~-B<rj=s** XW:.8r[c.ʟ`d+! B@uD09m{(hFCИPx%kۗ`}ESӰ?$˖klNL eM2t7pXH~gG5Iej8|þOB5d$j{6奨8?Akײ6rуko%MJ%sL@QzU^V)wlDdwuQLsO`MV 1^猇_\;N}e+l^ #ƏFGUB@! \F@\]ۜD`c X+3ē-$]7kwP$7vNq;uQ;'Gyzy;k h aҰ[)ʽ>ÿ=_O[qt$H}'d?+.6{n72&ߍ584:o,ɾ&Us|E29>l\-|7a";<΢p7KrZoOSR;[2#n1Lu{i FַΗ?ǯ=O1F8UΉ=cr .? vz޹ǮGC[dxȪS,5HrwxyT+o/ (<9y,k{f_x.JG gHm5~%8%^;(HPZ% ? `z8iosB+B@! hD0>= DF|eWdq3P۶fN†)6p0gs}vHwHޚ v{{SW/kwn"l|󖀼ct J2Ik_nWaC *wQ캽ٺᅏepuQmy=9 Kv%jE  wKJ1߄mmܯD?t+DƝA0/I.2#Sġ^ʔt}h! C@c:Dx1wÖY-0n7ʒ7Ҷ!y}2<7Xq9|߃bN򌍆qZ'gn?)715+km28<(O)n&`snsg ^Q)<5+7o'?Ra!@O 1]b}lyz?p6ɦɒCῶo fNCz_g+w}9h[d>'nm$/;yQ ^CD4}`w?<N{U*ྲg~nL7e8< \'3mꍸD~c!b?죤LDz#Gj3 yᗏ^=>V ! "8ue!Li'**+6Yܥq ^9V߭8\gϊg. }*˝"58LO G>{d_78dK$wBsw`CN]DgVk(\N/Drf;l:޲u}7l#k6z1tuyJ~.:.3;=P)8|=BiOh Dj ?CLMC)! B@c:CMAcYƘ9sFbMhJܔ?Ӈ N\ˎq޿ߥ`N?ө02J?6ݼ!8qy[mCߺ'mC0w05V8B-_zp6 K"܁D6.cTB@! nZ#"`Sa 1̈G.cZ[b:y9=q;o.ȿeMݘyec,F߷sK"u?8q+\p%LÇݑ]㶼@}HzކLsּeH;_x>[ wwCH~輸~~n4t3$+wiIGNUs~X Ŕai%;eazcjȥ8(c;1~_y)^n~ []^ؐGn{ɳDѧHW f Pĸ| <_ps8θOC:o:f=3q50Eg0 f@w.$(C{ 6C߶|`Ca6wq/p%ڽB\~_ aǮ3%7)`$8> ]:Ւꕱ < ɯ<k\h! }A{~ȑcgHwծ 8F xzhMMɳ&v{?aFx^>N|`"Ns-m;;K$@$`ÜK p' ;I&EH~pjADG'넀krM3=S$-ߋtʝ1Æa[T O.(7OTvd(֯$L AkW@Blۍ@BМΓM @gNI_{ȵcdʉRƥ >xXcW; 6*|WL{vIץ&>[:=xuY86oz8lIy>7w{AnG4b^+Y#o[צLG9J ! "jN06껼&*gǼc$Kv@(q Fn:jVSOR-P=u6m1ihyf4ɒvX1WK$٣&IPMSeyX?;6v4zsI^7`v|$)|~+z^VeF7cϯ];ʆՙX!Ǐ^L Uz6Wml< * _yX}><&$oψ+c鹻Lwp<ܓ 1b{&v= miiʙThc0߿How7>5C֋}:tfi Ʒ6k?gǑlgwkYLO?q"+dB@!)D0v;!g<OqnD3/iQQH I&`W#U/)z9EĜ_NNQv_{-_jOx;j6U^&M"#{uX tP^JᵴS5_EO k$a.h91 k.˃sa,׷SlXv-K`؅A!F5uJGviن%~Hr>])x/Kel&A}5H?=N`*IGR<H#=%74v6< e(=j<\ e|ͭ LZ#?D$jIr>#f&{htt,B`F?B` e[ HWFp:nX 7`x_c` BJswML`}^?3?&! ByoǛ?>K>:qaa܋`|'Fo'نv4nӟtl6^$kNdS,:;hsVz<[7oe\Gj}`hӏci+`vQeb">k^9_{@v 9=.vjRn$Q;u'w9ap'7 1xӫk`7$c7™{Ӑ9N&.ife{zM%W@'KMZkyD1 ,z86OrOSE^7z:|ed֘L!.ıph򍱁KE0NB@<`|`ՅR#`w~c?s'yUM ckwf! fܚQ{qvhǍY(;si4NܘOypxv$;mQ7C@}N$H0 XрCVDSFI3?Nu*)XG d:~x9~YyʞmU `>[$YLJN[q߅֮Ӹ i`xo+ ںX 焇8X^7M97YmȈa`m8nsgt4c%C:ۓٶuMw822ccr*۱OD>M9' c,a{p8N8%~CL#TbMx5vg`m~mxۼE8E04^v 1_^dcbw?9у=9_zvO~hcӡ)^$ z?̒*tFm'o"@f{QE0*-B;`N_%B`VLY%eF/ hY:}[W{2'< +`ljAmN u*;sIaFf]t#lLɹxi6_"8u uc*SzZӛCkׂ7Z+9&opf./4=~v-{&<]fd$zἰ.n= c.Woxq/bru/xwm?cQؾ~[~thIxm-LTo.GbJu$^#<\!s|ŵ& ]=y\q93GlM &›su^kҨ[gms%RB@t 5D >?AMjdq^_M<_5~JuMݨ@FnԭhdNSf˷w:7 6_1bo`>Pb2,E3?cA[* _r{|ua>#+W[n 6o٨j_N~Ƶqtaf0dzaIK3$ȿObntexuNJ=p {1vOѾ>ހ;~)|Wifb! B@cC}hO@㝁1TY^fcLF.;1`pJ+;kMB>~J$hJ^3Id2O:UY/y\Z|哆IN\iq9Nr>{c27\ OGzv+vf윚ns+9:,fRdENj=/oye~q~Noיt}M|<8&ϔ߮ú˗I0bbB :YnX(T{~=OIBQ|ca4FkNån^v0ܝD%O}7-oM[l;\ ޹3{v}6p#n*<gx`,\j2\ݿ_$2x7>)߅:'2w}d,]aeۿb̼ ܼL $0v>}_,Θ"2 x"B@! C ) = tƌkOΊ@~EaSwO-v^uLgIV%;acL)c\SiȎr&S6{Hcd3p̓+\ (# ߽=ؕXx0ɽ`>?Y\5O1oH^_䯓6Zx1ưo+mF֜Jr]\2κGڿllܼ$;ފCsF~2="3rwbLz 5MҒUB@|B`5]I=j̾Q3iKj HfJ>IW"b^Q]6š6/b##K2ːVFW/JD[\\78lynv-Gö+p-` Ļ@ V?=ߏ`kڻ ;C[Lrcp{fyt(Hcwi&JJ˭RHxo&mBpM}_+X+ "02> r;s率 1?3Zi UBLSsԕB@!D0v/!0+v8 kmJ`Ȳ@dy2WFe%/sy0p46yJxj&mK }?8aS/٦8%H77ywT"r/Y???cB@! :t"fMΈ 6+fEV,A2r|óp"acڕM)J`D4Q/8bl٩fd.!mӑ$OEn2R\y!|ly]:5p?D>mI,=}4 A~n6 /z@cFWR^;Sowiϯ=uQx4sr9vyFҮ<d+Y a ci~WA_kEx_x3 h>`^m#ѐяB@! s] 0FVed# ļ՝xt\I`tz$a:t%;qu%/HH#~WxGY^E|!yƴ\qZ~~vZՄ^z'd~X$j yq$4?5vlBxlZr6©o 9vیZ\#߆c>;xDރ"õ- aąq,|s^q |E,+kG7o'l цXwq z]0:Nٻy{ 'MwgSyt3mYk0"B@!9D0vK !03`do N|YnxgCӽbOW7Ns"=mgv*#+4JHa=X^eϛ+ߑ |=U:J~]e7!+`fLT t>x>y$ccn2rʯ':«oOμHv8컋oq}w oPIȺ$΀'#w38:Ez=:t<k:}4a|9GB1[돀\ XrNYnCo?ʦkSq'¯@|:^ءƂ&ܵ 8_E "A mXqyPޖE>~؀TB@! :t"f@NDÿ{M=ZƫI>ZAO#%9NpV-hǍxnKh8$ UYՃ8l<޹]:,?3uyr N]p'ÇΡ_01}{iKLr "w>|0xob9ʼ4h}16e#+d^qX8$US ߔE$8/Ŕ15,AbGcB@! Z"f@c* NvGDJ̭$_<~vYùTMNZ: xTXz:O7imF#aSc[ju}p+^6}̺CmR5~_vz+aa̿a=v<6>߯#^UJ! @wݾQ˄@Oltx Y~)QE/ 7,_8 ƣ:A0C6ƕNbÊgpB!0<)u Ɯ(c DT)=FL &wOc ?#X! @حPk@_|tERI VBUUy+9?¯H1U ԍdUuuJ _ U'{8iqSM@4,ys㸎=/֖k y0b(B@!-D0v?!H0&Ұ"8jKΌ[#DEb[mĔ<ϧוY4W# F% Y#*00hS$=_ؘƨWVaMV8"JSB@!)D0v;!"]yQ%W#A*##1 E~O_4O)i%W$Pw5aLWɉ$M0E<)+"M=C&Uv3lE^`$ B@! Z$fDTx VgcϮF;U]),WvEҩ! XPfSYD@gM8EzkZ+s;?8o<ƎM [4~g H! "j\ n1yB3Zd*OD6~J$̓H$IɈ ~+s/+ya"DJǯDk0z3')"'E:'-6[*.1Al;9V<kZgDf'|9a1)R F)g:G).5%uHES^k0Z}f똞1i\<=ȎUB@!=D0vO"!0#~jbGbn*;,%^E䉗WH?E$97S#* C,GNB[>{ OcTH-S}?PT,XtN/I ! ";!j=ʈG4 8|m <|D"Z#t*N68pEBPzACX H5JE(Ʈ_UݤN ?8nc(J ! ";j q FLD?ݨG2r,K!y@?Ez0y'5"DL6Ũ1Qq8dxNTyﴉi+y F'\E,]KUt /U^~gA<]~`Bi! A@cwB-BScB#iy#Μ쀑Vաȯ2M[ê0;h4ʉlgv #R]Ol&+ga2ɗ_=`4UzI&15G=媎%?; B@! @رQs@?<Ɯ`2( .'I2VoKt"eHm8 ;`B͖r7:/bg`!˚k8EzD7F1v/Qxމu\yqc|Qx˙ie] O@IDATiB@! {} #9*nY"Z`LX!:~iԴz0MhNG J:J5AHoe('2"$_5NCč B@! :w(i|`WdMNʘ~ ǔqbRD(?XiSJUzK(&SPJǯ)ctthaT@"ȚI{Ģ]s_{s>rB@! c~`4 Y#vAOlR3r4\@i# [|䠽âNC],H1c{+҃cE|tm^4~NJ`LX(B@!1D0vC!8EV A`uR9LKb_S3]N0bc9]]ׯ/ " F̮=)z>$sh5EX*! "'jm> "foMqiK>b-=Ԅ.5uډŦHޞ*~\R8 rr2>L^uVI1+?y0G! @ع.QcV%'˜MF6ˉhǓH>&JůdshQңq#/מ-BZ\qzUG\%AWIGށ_,5J!䁄Gv׊b! C@c:DdsͰ!l |DLq$0H $CVPr+31?N~)v4!iJHT^eljl0#|x+ҷ> ! "j=`M,=TDle4*,f^GF5$"!}\@EZgg) U~FOmKȰϩ+H99_Qu<*f=u*|;+r(! C@c:D&/ #nŲhaDk$#Gx%ԓ AeTӚZ%B}dP^%On5KzBècƣZw<ߊf>_/v8L+B@t 5FG`n#ȡX#6LJ1<=/`dV}mQO W%2^YcdqI06`l* o{s+T=17IZ/?ՏB@! s] :M6 Us<(Nd@cGj J8vfU´½HCdG6aR0WeR+rka$I7,Y P1' Hޞ%5TUB@!=D0vO"!0#`ubE&(+CՍժJ>H5Ok0:(Tf УQ\ #iVcRġ '/*WFgTg R|*! "'j_m03QF"?(㪜ǒ!0>W|ӗ8q|ҬZ7KW&`;Jq/^4vo&%>Ӌ~)ұ+Bk`Z=B"PZɮbYFvL['|<2]9E9ry kM˟)ߎSkESqbV#@T*Gr:P9@"m! C@c:D5QͰ@Z'Џ{sH+&hpGIM" "iHo=8$jr޴-SN{JJDQs<3FB@! :Ǝu#!S؀*]>bYmU$]$Kޑq;ERi"̲c2!wބ%!8h/wfi"`(!A.UUR]G L4E B{`^EB`F`4k VX#X"=4w IoS#y7J%9BjQ%?iW)+`^TaTR"~%z0F=8)M-f*S{lTN],W˽L:~`45ЏB@! s] aXYd T:H3f G'K$uOvZRRbCbn\4‰G);r +DG={SIH0`bMBu%O_>&D0FЯB@! k=>Dr2NF=3?"f'|r/|'gW"XoĎ*CcּqM{yӔK^)`|P{?e6ʉWa[R¯?"9B@tḦ@E0F 1_.zˠa[ѐS`42$fiHFQs Ka䍨%8O\VP7y>OlZb<@5*ґ!?ktNy<L?Zʢ B{`^EB`F.ҩF4pn8S7rl) ]hi1# d Gw"R~%k-=rA":],t|Ă8jwJDA! ";!j臀!R`GLF-e-W ,3$A~i *`sUzS_"Tr"js)s%OƯ)EҠEc] MuXm'PAaU(~"~B@t ]GA<{m7?MeD^Y}"y1pmBH.#=Nϋ^UThO4U~Vק𑔔|6r+7F;t|XjL$}[e_sA`(! "#j d}&?i19\&ֈfI>a!lI08N4Rcr}dƔ03,GNSdCiq%*Uz|'5@B@N! SݡD149efGn O[a#y<3<ïLq5[FFlT!')]7,3i6~ֵbvoUWP(NSeeE@s? B@! Z$fD`)Yf4-Jtfc$+ h5~Jwf%R0Bue*uMI>=zʇ5+`5SJ#rǐ=uXZK)?q W! @صQ{@̃ knzUV0֫T7֨HuhX|Ȯe ŀqzsU֭iWImlAI#.M}Ϡ H?q7x(ygcBk0F$+Bk`Z=B>Eډ@]h `jU䅟Sn5I_@*$0@"Tu\B>|jM^>{*fS8\l"*`ZаHjMbOJ`rUUׯZKIpt)\_ d1UO5%WW0H=oKbEY V32Qq0*_B@! @ءPSl3 A[Í r$7Xʌk2=0J5LmPT%ce*H+)ϛ9Es Jv-HZurԛ2(r)I ! ";!j w$ W*ws.jQ&OEz0'5h\U^s}|F]xp^ =ZTcDPy.T:<ϑ|:\A! @.R@`Dd󑑊0ی LXGVat`8%N5MVK364R:IԲm'k~Nf{wJ*=PE ;z9؅it=8B@!D0v/!0+H0 fzaY~Nx" 'bSY~I`Lfdk4$ycƊ͋ӱɎKïTѻ<1L_[/; P\Ο,Il#@A! @ؽ>QipŜR: +`̧HGob"-;'Iz)Ғ'/`6J$)i(## 4RL*g97r(!T#JAS^W! @صQ{@H0恶C,5͉:ߪUu|GN(E ljs " ƴqY֩Ĵ.T(24c0#~>~% 礫M7 JXT yvy~^咟;ɃZ B{`^EB`F`̍+'8,/tpD1*=}{$ǜ(ddyJ66,约q3h B|&iM(.yD8~"@B@! c~գ<,oEnJ>B!!Q"hH'6쇱 VD*12z$˗<%K9^^ŏE.S?cob鹄S?)ɮ7-Ev죠A*z)Ht.xFS%! ";!j臀y0mHVvXJgEn5K> 3$KƯDSt8i PFE/L<I0Xݓ@儢[qVH8lTPAV U\ccpJ # \Hxs?WB@!=D0vO"!0#>EƃdW4 7/d2y,FS~%N`Lz:Y %T0+,OWut?XDFE(ȼJ~$Py0VA ! B@cC<4 p 2c92f$ Om$< :owe"] ~wNݨo^# +aQ$i5jc<}|ϓŎgys wb! B@cCxnVtl&)70: @$/rH9E}n3 е*('6zq ֜8E`d&⽥16>|Y!Rˈ?\OS}(B@!-D0v?! 9CxY ʙfgubeI{ub8nHGЯB@! k=>`tb\N|X3abFs%(=U[7 >&bVMDc^Hg5^?1u#O}KrǘAǥ@D0!_! ]C@czD}H4hbm2͌61!%W"SԈDLM'=:HS"쑖O^"IBeN:%ygvgGS9B@tḦ5" 44| OctM - 五"9)yDFzŴ  V1uɖȈE= A?`b! B@cC}pѬdQ>fnĥ3礉kVDo+`LzmZ~;R=3g˧K{P s  L#"c^=d=D<Di`j_! ]C@czD} NRx{|u8guC#?ϗ|4r<܎B ??"CB@! Ʈ# 5e͔SLu{Փǯ)9sݰV!ʓ|$JD<)xwe~ƏƨSB@!5D0vG!"ݓėj< qi%_<~a Bc$']<&"L3N;y/I{_|RPL1#X8јwׯnWB@! :Ǝu#!`S{nx|'!\cg#I2+rorL!>2y+1t1s =H%W]: {>yܵ R\K$D0@B@! :Ǝt!fMʉHH.o;IȒ"HllpX]% SeGHIzNNNN_%?=F3a_$H:  ӳz'U9+K^?%T! ]G@c{H-5@dQe1|GIy=+K䅟 C%!#U yuS2J7%Qq\ǯ))w(0eBiN $czOI^Ǐ<M#Bs`\AB`f`DHtLvQ6%B+"=}$Nҗu~ԫny%k)@"4G ۽2x[od"LUhuS9dž_>~H4B@tḦ 4oHŤ CD`NXTF^fD Vzz) CV]Ýfa4(%Zo+z8&φՙ(%`J\p UY5#y^9HS7h%˄[_)vz0mB0qN[aVS$r\xcies F{=c=1ћDZ>#N +̓c$c{~ 3f\ϗ<( 3;^B@:?ȧHnn|Y:yLI>;AB5$? I.F#?۹’w('!BS# :N)yb '+Wq'5 }M} QܞǬYו?wjLj*D0x g||,8_ngM?H=&D7NQlxa$\]%ҳ>%W3z4*vL9[78YH4%_q㱋JU+c6*3Qw(ΕPDM/D0r<(!p_! BR`tk˯ yVƼyuvǯDd1SDD2 c,KuM$/lu#`d % dyy|ϒ5~J[ M}Q4+zxJǒ H(B@@}!GF~4-C7Zqjb~S"'eux\{=nK>ozqy0dFb9xz?5Nc|~6&`\He1`!fǿp|qL4rdZprI%/7Qc=?(~lr!l`XK.a1nHNn*"X u=Ko & :8 滗ж|c;`/F } JH?8«9aN>2@CFP)I>~J$+$7)uu/~ߛI^?h*ßS9n ˼tux$?'/`LQ(3UPUrGL|D-iՆ@Z8o |W_jY+TdG 7 k?jq8qlP HpwuCY«86Y=QmN?̓߯H]1dH/t"fd>?{Ca uAX sI8O÷~;X,?#"{!&z&7C"'>%<>hXs쀹ޢ8kѰ`fh[g 3?^("hSWu$ҁBͧdyg`L}H:#]Ee% #I#% Fו4,ٷ.vs<]Uh't8K%mflz}N62%oX_ycZц@| ?'Swjqj)QpӚϺZ~x/uAko[.zqkr m0m=UZqn7^>/&[c[W8;&ȯuG׼ͺFr̾nQe'/ kq.\5imZ~d lvzEwʢ@{F6loXbS7D?fpTG~Qn=3{F9 ! fZB38OЈ 1eGF;?֗|D@Gâ3)~H ب*|X`M^Mk@$,qs$JfI^S s'NeW;atC+4#8<7LZ}pȱǖp+7ci#"%_#P*~HCnK_.T2WxH#Ae=A0yD664/i}^x` CN ؎?ya>ɹ[yXnt e·8qpZ~$߭ ^ x%vC;dDaԄ',D؞' W`S$_xp@}^U0"f $1"f ʮ*b%#*p_ETTdL JDICwN}y3n}pN߾_Su{zf0?9,PR4O J}syxo܃aL`EރL;f![C,\'H.CF,\'Qcj^"]fQ Ģ^'y}/kۨ+bvck^z]ӣ!ͯkį%jKQHos{ u( i\(Y`xi @JOD٦t8<M@q pCn 4zB{O}߿B5/}S󙳌 Ōާ) KX K*KcsdFgprmCF{zG-jv_~=77R]~Nyrh0&D`H0"A&@{WY4- 5<^w6bL;e O~ߕfNjlj-eyiږ~ϳ3VeX3~5 /9oB'| :] (OM)S۶:Q"i٧s#`HNO2[N6oӍ?6AoAZ-NϺ'ǷIuC9DGl+|^HK :ƪΫ4w 'M_.z6ﲯ_S L"0WH0A #D$tsYJtq\G\Fy<ǯF2D5M^_$ q {K=mP@@"PF!X`P9~5`|ׁvIӒg&)eNv՛eM>Hđ>id:τ#|^`Tlpܿʉӯˈ{,]aˈ[󽋅s78x_d$5߀%7'7ߏ}&\ٻ0o}⦲3d᛾-can5$wifyufm6W9Yy$1}r#~"0 $w!C`C'xUp?fVi$IS2׺Y5jIIɓrZ["KZ{IEjǯF~;!gOAM@$X yS(|uF̞r\\ԟRژzC^q Xc_Ҽ;7-G[#j,-؜v-vO5/1|थ7a˚%?7(ߜ_Λ}wޤ c\H̪|B8'Q+7I-/}"=bOwpc/~y}6;?x-jh}@¿*'tHaxNtyj["㩧h^{f7_r7\pAY}՛~wrgUk. 6ؠyЃܿ{_⋛W^p 7޸YeR?A;]r}֙q%4l'5_f^}.g Nz:XRsQwgiIFRJ4U!rp@ J}Ͳ4å/ҨIcF@Ӎ_i}0H#$=?S,D偂)]֎_3S_hۤL?$:3waXZ u<1?e~Մ\IJGp,3>KkR.n({zշ6 XLy<5 %ot홁nڣ@ic$ 띥y߿1,_z{7~֩|g r?\"2&D`nS+Pr즛njjNo[ߚ<*! ۮ9KރYˀ,sk>r!_VV[ypisqe5z׻}c͍7ʟBXgu[V%mCѬO~_s5zF}C{u{^QTb \3qP7%\( g0Iy@ v{ WDdi@CyF3X S7`%Jaĸhh~P/ʡOڮ8E,|T# eVR;Ȍ:^bܬ,$NA~Vn˚cCtc pIeKkw{"=y9͉IC_{lyk=9Y (Cio;~i{f|jnmZ{*>9NfX^%ʭj,>ϿL9fR?f ƥ diY77W]K0~+B( F@Pܦa[fK0~ q@qol~R9e}OB9![NFiVuVϯNrJN$6̔!&rxp,~}к- :6z~ܗD F,c9Ax29cmÞO}oۼMouge%o6x;ŋ|#%*k_|Լ|#ypR8!٘|.1=N|އd]svj:$#|BGyd.>f]wmoӥكɔ F沴`h+jͣcױNuS?wt_Ձi]` \ 2L0Z*;S'(??d%)iSt(# fzf0bƞU1dkŧ=pal!B$3M͗ιyێ4K*dPi<>S*QoYQ>ƒgǘ-n60?^F#7J͋\@IDAT4]tfa/E,g83s&|>?nWSwؑ EuuoY|UDZNfO#uh;шEjhA2+|7Vj%M 䳘G\%RSHE7ZrUD3T X1TF5V6 G0~|!2q[N2Bԭ/E_/^[KEFh W͏=wMKL޾OrR(s 0})+,j @=MfqZ4~x.o<^E @hE+$6\zͭ?)x̒o/13S +&,scDi"@!A\dI l={,ufJc0C}Z `݊lS1`i8ey5\K q}{Ϳ˿hny{^mt^{e-%8 znC^?^Q̘lM}Xa)N 8.S_W-sFhߴ1AJ*Wo\~vt(i\|ǯJQN!]"O n_9e@yAr8`qjN:: S_qzWo\>i\~[lg[oWG0PO*Y=]؏B< yM ;)3=J}@OوK򭗮]LJ$7F>+@x衇s8 g?^.k#W)}_bg_җ42'tR|Yo~ Aӟ^t"{^cO龘Y7/`ߝ|gkX.D+N9 .l?i]|X~m^vj!/S3g7tG7 4{R0w%BPq-iqsAK ۂ3}&ǰV?Qt<I{=%F!^mIH&(Ӑ|=gLjh(3(?2QƯtOmv-P-RW}z?auhO<{G>=fIz—梫}toB.]lrHYq7"ؕI{2V\ { rMܫ51$+Dvn`<›w3fHt;嫋  D`&F0={|CҢe8 Wg=Y͗eu25#}uY6l`4>v]iE AL3Z=XoK?_\u&#Ȱӝ\yJjFc$$3|0L\fY'xbea b_uUr10[{/PN $i,OWb7n ɸgg3 LqBg00(c!DyguArj$CpKXL|Fr:QI ~#S㾦 Wk;T0>h] ޸4j-?om_u3e1I:K*GZ81YEW!0.ϟuSٳns{_Mȷ참y؆-bZ vk ^eƻ|A8Oeο ٛ.l/Dy!5Q/GE'S?x|?a߃JBYZz ɢ Wr~ߺuxΦy5{n߮ɟ,m}VZggaxȉ7r%MU{.g,mpv)|N/L"@F7#5yM,ir c@zõ*4\pAdɒ_ޓbmӨQ"Fهm ˈAp،ٟU7b™K_擟VϏaK^}SDjf: { p"Uw83?q(C58)߃="LMQoFsPGh⴨8wfPJ0=E `@h*iMQŪ:`|@!ͤX5&桎R%PްX &5W]})X3Bur΍_ܞ]1YlrF.{ܼIbrE77cO|wh78;˻1츯!6H|*[Ǖ2 _z=˶Zvy裏bm Gq3==`&#`9`6j7|Sj.rlA?=yO]LY<6AHq `NjRG)m`S/~b_|ܞ*/R>(p@LǬW%Gѩgɑ>סd=e3oJBOΈjD짟~5?ۛ}S2Bf)mg@5|m}_MLZqUe&[vgI2ߟoiӒ#gzCeCdO)(=$?J0#3+K}g`|W~}UݵKom>~Mͱsؾ|E7nB{A|75>F9Mׇ>>{0훿IP/կ~u^`cn!'1,YDg=Aٽxfш^C,K1`_|eX34B"fi3f/b"8{U#}/LQGU&$nᆺ%ľ @=/o>oI~1TV,!9x2fK?fRV HcӍ}k\=$̪MP?S@N{c8,Nk{GOwNsN@!<,.~e'8:kR+rb9!o*ه+rW_*_"ur YK8<_=:~l^"qԸr]p-L8?.3 d >L48yzpe4G޹ ;by1ʺ3o onnfj3&U6oFނ%ľ$vWo7*o 1{88?3Ч~xի^g ̢#{\Kb@9q< l O,}2^Zc,FpA(Q~yLuf*!0F3GNi%e糂U?*ifj'ݖf#F3|oP՚Lewն`}5H :ŨS&崯C1r?u[<"w"l;Ԭ".V%.!b rO9Ce他;&iARSe_-3^#+oVPقsoZ`fL(\CA\%c1?OzX{3Z[TėwuVjqg@F}շ69=1*t: m DyC0b"tyғ;T8c&!-?O-/' OZݘxq<+u@jV4og;Мp Z`?نeox:Ho%X npseu5NGӈ=7k x \'`eJz=2KJy'%҆E$w-iU3"P~>+xFPP`CM\,m?EyRsb6 `=Ʉ2$ } a,8eWQ~VU[zaD +!A ?9cfψՈqhlNjwfp_Wwf=l;05fp,q UA"`&ϊrc,)o~_kq_Rt,ʾ-X= /lz M-Ho}yq1H$"<8O8.;qc>8ɍEl`F$#:'~ENpV,H'H KCw?B f0p?mkLʯK =h߱f{ (72e+a $? ˉ A,E|g>dž~` 'zy5mY.>^ΘP"ĉ묳NsdrtW_ 03bg*Q4jqH{1]wݵn_L#ľ"q@ fhġ0'tRkC/jDkt0DƐuuJyW#fĠ4C~Jϳ 5_6 p3DKC ;$Gjߏ 'jx )fx≺!,X\zͺɲze|D0Fq ^4sT{ ԧ>5ϲĞ> 4)G>:C,A/1kRDy8 K|ǯVQdBb}FvtЦo:pS=s(0{fadG]'q@yuF@MFP̜3q<ʗ~ FD C#a}>p8S?O }u!*8I˓Sq2]|l{K6q K}E]lF:L˞Aa"B$_>B@}#߂KGZ kX"3>kc9΃1Ӕt)ƯJ'V?)<޳€,APD ?՟ZHOs;jT]OZ8?6QHAuɭHFbT3ڇP::AQ[p~"0`mZ˜:(=WG?\t΄l9s"b,k_1pvʢ8PxxK_τ𶷽u f?{ws衇K=/_#|g=YD2/Cf7nA:8g({ʲ#/Oo$9pp /l"03[7 N=NDV{g=?;oc&}P^D QkM@I!:fj&][3AtlE(6361RjO*Ư=(P~FuP&ZՓ+aR7?  0oFZ0c=fño ȹ^W&΀[kt;?eXV[5]&3B,FπL x`v{w(QWg?[ɹӞ=8gP ̾ ZpY}՛͕W^dF9, mk[aw4"R`JhRވ!gNg=կ>'᷻8~]j04J!הn=HIEm5e卬SZǛ*01xp0 z!<JyCv'-?`t`L+?o@;K7h⾎8 e,^q&cw<1i4z'`95L"d˵|\XuUu6H#_}qOGt_?cZg3 LAa;?37DقˠA=Snj736;8u 9[~̬ĩ˦{yf3}R"Qb0r!(S%i/{0~JAe)Զ` -~'whj$ m)};bw+o+,)~"@ pciLv&q_˘y`žCryx/@^i@,}8p|0\;~>S;Ih6N:H'Mb_}`SK>Y#};"~/5rSid2f'~m+iuyIXq`\?7I8ӐO:ci톔&@ 8ꊍ+1M6㰉1ݖncYXqe1?`삈F["_ԟ F`3Tȯ}߲$5Lǀc4m׺ՐxGslVy[o/EyIH0Њ7!@qXXIX&z:(:|#nTAEsN':zW1cte 7v#FgrηZ;G]g8(?~W#iy5%6NEr6htHN(ni0B_#{P*]S <,SnSەj _ПSihۑf+Ie35 Ly8S aJp44 8 u`.._~1G=[˛޷#B|JcFD !P=%]rFH>c1:Oywه#}xH0%Ҫ 3| 4U$  u}KLI `FބL%CdvOꐈh6Ki2FEԄ_dHރQkj mL3byN],^|Ȋ9MyktW F=EU/ՂR7Fy$+Ӎ]i $b4 չD$۵ߧ\9պyGMV@8u1 C @qy"0ADJ#tה'~{8`4+ Μ NeQ>d#F7!a $Y"CAeBQӔ Hwߌ!vSgzt"-GQCq)C9+I}Rl21_Kjf$$D`H0"A& 'jf[%|4~hՍ剟QR3P |p۱D!35ׁZ1CйAyy;\`l;mJ)Mxe<@ ~ھֶc`n_: n:'}iG:Jg0BA 8 Dڽ;ό7ǑAu<}+Y"gC:*Z6P~Ԧ)Gm3Dm$ skr+ Fs"@BPH>D`Bi2 =/#1Ot%Ұ >P4t4 gxןID:ل*|  Ni՛dSJ:V2+5WK)xNDbqG-)Z#7@P` IއL%Ccp oMH>_Пɐ|pҰ#؊fO_yrp~KVw<8Kf;bMQMOGl2#Fݐ^fCy7VH0H C! !3]6^ HjJq$'~`APPF Ayc W)jtfQ"1Em '9Hy]`i<m|HšXZGY1 jh02B^ejT r^$IJO3~$(A@`HކL `D@cYPqf38P|{)c4 zkï%z2{4r]Hfo>։cnYޏ6Fb4HIn< 1}WiE }`RL7q<Rt43ƺ6kQ~,; gV4A!8)!\Z]ʗevI'ĕW#iڗ+t+竚H[LygOm ƼayԦœr# 2(m 38q`Y0"0 $w!C@HA:1mW;eb@N$ec`dqĖ4d0 :u,BPkǰ"j%$=h3}22(oDQZmcd4LMi2|ѽ֊.$F-*$a D Ɓm8)vF#1ݺӬ* ƞ=hNЩtNi*:0A#H9W=MI3 6JZN_ݾ<#ЇU_^(m F0(0?&nm%:LL{Ŕ7]?x D ơ}x{䐗H{h tlJIH{!PvjmLmId[JВh,u 'lھ ڗ`&1W#{0*~\׍ KQOy3q2+nfN 6)Iyk_ >fj["N{ףliC󒓘 C{%Gs#l 8}Яf4CI< @U8! s־NHo?_Nrڃ1_lȰћBBzR>Sߙ VQ^_ZR1Eo! eQ^AuW F# ےllIbs6fJ\d*|¤@r)?ț!2ĆZE> |&%D UAUF2ėH'V$;2j# @n$D_Kj%NΆ-bbbvUnMvpMy ]~g~}}|u&( %p2#By7?5~p!]$I#/f&)81Ԅ_3D߽lAjH)NE9}O| `NFe~]A_D9(ovWc4<`6`D@P` IއL`DHCQrxJxFJsl~?Cjme؇DSҊjuM c; f,0 `Lv)# tY'A#P^a o`6ddN Gw"ѠzOM7~$."0$@ D@g0 fG.|ġykTGRUįGޗEb,~|-wikLUIdQmDaꃜَ:6Eyڔ1_vx*G Fi'Z?uR^įO~TAC{ "3+LI $ܻeFbFo)2Bj$uczm_{"ΨI2܂`pk):`K(dCv\(yfvh^@7m)?7*lPtE5b8v '~A8LD ap]=݇/N#'> ݺ}yw?_LÔwm~h=$/8}Peߙ-~,6˰.iz̠צ!ocAD,)?ț!0|uqY"x&s2*Q^Qpǽn${0&ZNqXS9ukC@4}F@5G8vEAk3rI <"C=UàeMf?![z{Q~z#hD ap] *x:*䣞 &ؽqm;DU l+|k{bMؒI #ΦI _N0:K4%weQ'SecY+S`8vhS-x1%fu^Q'ñFH0&#bD `FބL_"c3ipb|DnU;`: Smėv*\PL J68Gߋ4W#i);.Su=0mLR`J9L(}QhT9~܃e( D``#'FH;I7><8l;xf>į?u CDJ03Vō(LIBHJ:M zj\"` u+HbCtD s#g8i85֘J}y^8Ǵ2[H0F%f"@qRL,`FkKA:Q^PԑvӀ{$-'r^1b ~ΕrTN!?`T`=ڄZT2Q厗YzMQIg ]m3:4+QfS[EF+Ccff[~$tI0`GޅL 'Kf\,é4'cXNzqn; 6dd06 A%5@6RgП`hC~r)3),8khX07UG0鑐B͏Xq\>IJ|A`.S ʙ"D``;({>x-9R' #>+xՍ_3aF̼BȢ5LF#P>a ~54tSvKmEͥcn[\ҹ,eb9SYnjTEٌf?nNpLyׯ?$a% D ơ}=wYqj6p UJh_џ* w_vVR AGs̆K5*u!ϕ`SSDsF$؏ZU(nQG}ոO$ XtlA[ĞLuI{S~*#Ř! 8 gih Ë4gUu#互ҐG;MT=N~yI+"Ht TwBD+S7JQU'1 .1('+șQzڶDa!q&^&Se??kCyק?'P"@ `FބL]" %`ˆeeN0@N= yV뀌ـחsX'LBBM &mqwl6eIQ^p"~:?5 #z6*O6+kPGY֦rj["C^b̜S ]e(O$PI `FބL߃ќw+%dr.}RFMA$~+5ζ9XG6#5)<ڋWhZ&]~U={0Ѥwa7׏bTRɕ=A(͵bS#~yFQsgf3Bӏ F ~"0 $w!C`' [ iH8CҶlZ*  CQ0 ƲQ%]@$fヲQrl{'"~Aj܃q !͸ ~$tR=,vS7Ȉ_[j%1r{QJYh;&vHyEdqL#~$MI0`GޅL DE #*tBkǯ%҉TI(r3} /0.Q^IY7?` ifvEP0q/33$d:^AQa9]jj($eF6ˁSLaQ>cBM86R?Ȏ͘|T}}y>ƶ"(uRYͪEqO%@bޏ#aw5 sB0<saW6&~& cTʅ/=Zb<υ(_7~^}惓c`&1vU,NP:/<#~I%ΩpV0PBClvѦ,)y]OJm\¯6 F'ĭ&6dD*jsQ@.93UA0`GޅL !j%A$ oȠ|APRvj$CढPc8'yi$HR?W``mbB#ZRd 7|"#Er vL21YX;N6"2&-*ľ:y?e*ďK /$D$w019#4X(BL%rl@hwsťV܃0  5HAl)槪I&ա<艫O؃ vM:OiS:(nD0^|!dLE7GO?.(Cv83?Ȼ!Ksn#F5'$#SszݸʨƔ f6ơO2SL#ᤱㄋ`%Gh dhZ'깭 SdCfrtRwZr2|'--&ll.W3%3-S06ǖ7#D Ɓm]W#zVFɍ)jzxh?QݓItzp0=H iRD'~P?58]HG,#Pj#?Qk6q]v.a[:H0_f"`\a(HntcjtFT5BNb9 #VW6io[ Dzc+)&.OJdn*؋+џ p:BYO*m_}X]h:q:)< F C!@q($y"0! I_, Gy@`4'  @qy"01|ѿḦ4_JR _1!N9wf{&˷/*'@؈/n&tLuQS=F mjsvbӧjU x){Z~:}58uT> [Ɯ]GyџS^7% sF! d'$9%T+@V'%k$CpK !@q y"0)c:An`v1Qޞ1#jm݃1hɛOL'tE3zXn_tW'ރq6FXGQy=Ӯ3l t )MmE:Ya9`4['  @qy"016}ׅAOӄGN'o>rMy`R7~U2+g,'fDKR/i]K#$v) `Ĭ`d"zyt6Dy!Ǔ5n rJ՟Dy'~"@@ D`iw 웝82CrZQ>WNH:Q )Ո̸(OTypN(|T5ؐMZ(։_mK1C5l#VP-O*1 N=}0E 8w y"0Q|46!6pĖR3uLyק?U`Sfwp#Rq6#{caSp U~U`SW&`xsMQ~qvGѫя (:ILV ƨL"0WH0A #)sYxLdIulLR^Wy-F_=l(hRn.O(G(OY+i/2K]ӊ9I H{KOX:2}gX .Ձ){n ? C @qy"0A6}煅TP9c)ԑbIIH1 9̦ RQ)P s͐Xq4Nf&”UM)m1[mR~-> UOj3.#)?X*<` v$ sF! dΥpc!`FR=ukƯ~p+YT1K +1ȧ!@L'18K\5q2M 6mbmjm6B0:Q#t%V*V&˯iQ930 C! !2D=JHFrℂF,{]rσE fj$j 0 6:)U)"+Z#3|rQI K&n&m EEY`7ݳSAjC$?ġoj+VĭTLDyW6V!){0&Ds7 E ~?kF \h&f8$?3G3dv L',61ZF~BZ.ͤl͚1Tįm`D&HN`hV6Ey %Uc"[-1{gzb>^ϯ=|Ĕ7"?`7ɘ! 8 DZPGeݳEi:R"cU_/+ 03R04CVd(O?U NKK7ն ؔlm]f4UDZ#A[kEf1.fO>ȏƥ)oL ~$]"0$@ D!8E8r!n !=MyX?UA6 d8K0r?ןg0&t&wb٦¦(/SE6qEbyo_`T !@q y"0)`4|%|*%㱔np!V"@B@@6D`Rle]baZL$9WߨTI0dvπr$@x@u`$5W%3aA׻6kG }Ыe/m K"'^|f0j#a&ҬU(/ ?$+iH3 8!5D`(0Tc6|8RRb RoRys_"b2HlRRGGHG"A>Rc`T+~T|bfkSAgbq6W۶[ 㡁m~)^;B u)O:q멞"0$@ D{0ڨ_jN%6#ZkX8LLSFPlsڍzQ&> ǣ2j 1ۇo%c'~LPןs+ +ԞZt "LLS^"~8JQD ap]hC8d«BHCR>GO/~5ζ]e 43+K3SYb9.;ܫMy蕬iVQ_@Mk,gR)gyLڔTW3}6Rfj06UPW^+P "@ `FބLw/{ گ#LVϖM|{}GH0m "%=@K!Q3^' Pyӌ_㦲rS((lmtW+Q-/3m'KSE! b D`(H0$C&`L>z@6HN< l&剟>j݃gN؈Vfgv,/Y (FqG I{["c,˦ #{0…@ӥ,?(OF2ėHc|'a*q졶ʵ,<ӟg0!/ll̬lElhį!/xӹSNGba`!i7"D !P=53}'|B$) ମ:.8L?~?}˽f僓|X 1?ƼY=PDKj$uہHԻ;)T~`J8Ngkb:~[jWlmdB03g?W[fD9#@qD` |L1tzbY;~5!(*Ҍ 78%L!D:7L_֍ZQU) =MrÄ7wޛҡ)%}𙊐qbOUGD0"0$B!Bjehu#bZ.mxBy5џZ`43e۴d؀2|\0*cKTO\Hgѱ؍u%]ٔf[opwf0:g9aW^y1_(o8?`tM`L`EރL_"mL|sB:&%0 <%j@0(5R>jZtFՒ!Uy*T_;/&mtҳv3ɧA?c4`%BH zHiC8eX45ڔ6Pԏ)K]7~{g PGs<lI"@ 9C"c;[ ~ǥ9/Ʊ*0LӈOZ)-^ ƨ`Qi`gz 3}Hת24=suW`=8ɩҺfj#bWv=&)h ?% [a#$Q ęNմSym?Ȼ!V>` '2:<(c!g!/O{0T$:t/3J\X>偄cq8qSY"ݶ)ӊv^GORpKjݚ@F% D5U% ~9 a@0\`@E9HQ HRAdaתzu>8 fWժz{TWfZ1c1+5DDH&g_X# @ 0`q@`pZY6 /RDe /K{~WԸD˛9/"R "aW``TBl21[R|Sa_~ѿ4bE%A9nk4[>EYn) P`C+KcIzrG$?^?VG?H4=?KIbE<_sՄ6arU0"ASX.YY[~P_jwRH۟%joj=]TCr&auYP#@ _ #+HM6Y9]ݼOOֵcOOFnާ'ڱާ'~7uXQɺvɨͽn#̮"ae&Hzm :i!>3P~SXRI.#:¤4{#+S#iF 0{B{0p#;:I/-0[|}@ xp @` !Gȋ$H/vmsev~}S#=;#%Tڳ*63Ai\a_;~U`@$4NNL}7ԶdTq馓[tL>b#!@ A08F 0Bt9vĒ52#7J穫I(3V&$W>D?Z##s.JxQ]Hn1$RM#!GmK6+=2k\W0NkJ&HIk#9-t tʍ3Xb͡ѕX֡~7_xQC /#0R Ce$CLE2;#|7\UEHt5EDtSw".|DaE37-j]l٢D)="}e-\wDek>G0q(1"E*(9RKCϓ {Crj\HҞ!.qe,7]}I>@~8U`y,=ApXcH"[:'82sV_9ڱ7#Z ea}Rq?2F@9%|Ht KEzPz~cJBa#Hf:3aNڲVػ ZS F<"m1aђNL!,Ə'Jf$4_+uט%Cqq5^o)@ A08J 02tL 'I`r$ q]bʯ@laՍ ah<ɇU>3P1b"bb=0 :{ju{0#$}^ ,7B6rCwWcg}a_%~y   b#!i }HvhGN76x  F $DTZH@'h(6$>\| x>ŻV#,w/52ʍ| :ao,q &#x@ A0 8N 0"6K^8qa#OPSd9~* FkxL45d!z*tb2s{cW F}3{#&0{bm+=|=Eyx#9"Eja?A06@ X|`\| H /҆K6`:ȡ!UE $H^&jҦev[?xT_㘘 nj?NNbNOao!KUG0K^ ۊ;{CeT'Z#1e[Q7-`Ԁ@ A0 8N 0"6;:a(I&]@< d$_7%!8*+%t,W]䳍*cjpb!J14*6a?%I~sn|ruPg/WW8~)@B2݃1cN>Ԓ! QۨUeBX~u!];]aoԺchL^dzBꕘ#q}d eLn!ѽǠōukv}0q(1"|VU'_ m9!2RV:Rar65}I~ąaba#y96,fV{Jq_X(#1]Atrf%knzyq.~m;= a3&*?׸*/y鍏C']#Gw릕@l W#c/xyv1Pby_$B#@`q!E#'z$DCȲ:%Uv,#Gr㒘>a4~v\/| ]c*/UW#+sD0V1adʤՆA/Bcnj#Hklȇ4F,"0#hG >>>>>>>>>>>>>>>>e[3@1 B07{bue9'o]9T5}mH0$0'bn >* FYL`z)gAXYX$R?x~)G0YHCAݾ 'XORCB ! F2H$P*%ivP) xE{0z`> _Ake#2D񫑴 F7U';FRW#OCI")_)ާO}ն#V0^IcFzI 99椅e yQ¾ZbF !!㐀B{0_ʱ#'^#6iBcH~6 bR..9r5}?5`",rbm⯑e} uW FW=EBT,a"m[5J1'/p'w F)@B2QǒB ٛ1TdNN$ς2zal??WUi\mG!]d&:y-¾:j]߉nrʘS׷Q6HgP[0Զ𫍴?ezpVKn}Bd?;){!GmK$'۬@.yEy ,>A0.>q@`lzue/Xt:/{p"F=M6_dHBcV4ʓgmaoDb)ݝ]LNQB=IVS_{D(!Otsx8V7y~|(:a`<6?GqQ"qXHq!P2_qK(X>8 C(#mlj95[/NGYf={[^eaF20GH̽?/{];*I{}ɋk E-yƏfa/@yL?uH}.XQ1`Cɜvyq9 ^q)N) pp#Cd8L f 1܍Z7*V"IĜ#qskO1g[.FРcjvה"N# șM'L)T!~="缌[Sto¾S@xDA)@B2%eG2NAǍ]|ٵӎyȼv܃QF4@4r G(kR+A(896mNm u,yW+s^.\Lƻ"v >vj$Aqƕ>Rx=+rs c y (JCA ơ FЀ"'`!Ne$9*:˳h {2F:` FN^^>^/%0qbH0Iz]d߂D岚D6aohMe|DZ"q}.h@90 ~{ps@9@ A0 8L 0*@0&21C& Ij9C=?u p/H08I LJ0 u#i}: F DR>VH~H'K$/ {mm+cD<z!n" 8}?=7V0H@ 0,`q@`D`,CEH2AS2퐋Ɋ !7@p#@؆eSF9r¾njׂHj>05r7 Vhh3WH@ 0,`q@`D(.r_nþ:Hp!>#pD>k-yv?G}W|#oTGQ;(RΩS৫r8=<+H"qXHq!Vk^>E-zz]u-7 ,#a\}tEBM=nW=T_+qkEU uCʒ4[~zOu>"R(-0jhYbMc ?H.[:a/ԅ_A G FW[cV4O/#?b0l>kՕ`tEL9H,b"G/"Oj\ GÌHQ.-!I"6!&҅NVik#"@ 0` q@`t`,HRΓr&z6Q,F9^,~5!,5$uSuzԩހm>Si v) 5qQ71 oUW#I"kR"&%@Bs2ꅽq,8I&j݃q_ r{C$E_'3(c>(:p,ʘD5 >b4mVii,d>HCP#MKD|pq88Q!GuoLf`D=Q<Ѱ?u?U`ofg0F A#ɷ ma_/~5`8(jv_Vm}/SOƶW` Ξz63ґ&~ +D@ A0 8N 0"tU`RWePdyHCAe_~:oHP'I{d:shHC2o0"&Ȼ6NEj\ _KyU>H關,D׌_m=.I|`^sF }~@ "A6#|# XO*Ưe_SݨM CNӂ`$RgWڦ(~5Ɣ5s>'DKovH5W ƭ1Y* -`ĨBnYey G}(iG+@`i@ Ca$J'sMƬb;6wn;_!>0A# ?ΰiEߐ/:1}/ k禭j"~zu]U籏}l?1Pw]zS:/{'O^N* *^җ~(;SӋ_bV+^o~Qx;ޑ=";Ӈ>RGN3}cKXiJXc&VqFF$JPuii։]~>`=GcUP61FYPlCQSث.FӦQ_1'lsKUji+>sjSfD0gůG (%3h yg9L2ao(P)~}kP |'@׃MٔIZ>s'nGS02o曅`K-3w}Ym/ҳ"?w:H6mHsLz{SچYKk/!WXap֬Yc嵯}mȄՊ/+ю݄;8n`&{*Io}HnPƩ Iv7'?ɭ/HӟtEꫧ7߼7MB k>Odl;`9a3 A- 2j)t;F7dn[S4߭X| #%/Mnv@(I7v(X F`e kHQ}u1a3 l_W??w1xd_!Lxʧ>)bW3}X9Ȳ[oU7秕W^9w}5HxIOz|(u_oc?n0E/*xQRxUA>ǣmX?]x}o!W}N%}ֽ}T/c#Y ]ɵ0LsCM袇 {@`R;~|xBc~`lR!ef85CW>sWᷳ\NSSmN`%=i F?UW0ʕĸN/hSVp_c {Ar~{`+O)M$Hi:<ɨM}'?gaYxIid+A:aO''ZbTt1_/xA^9jL99ֹM zsïb0a??U!S ~Rmi@ 1RmSO 2Kpl3jQߦ" cE22vuWg=Y#ʻ{ŠAɯy͙3gzm#H/ɉ>4&ú&JL@Ҙn|T4V0"18DM9Z6a 7ux1z F W) *ku2oJ?NOm|OOm|OOm|OOm|OOm|OOm|OOm|OOm|HwB0>SË[j&(#qd{ "ؗX7J r&{;b2`4}qWA/kvؗ/Jozӛ>9U'1_ʡ5(Hݟg&C0s=HxW\QGy~XBd0UHk-I0R@PCGި97>"fxд:r ` (ܦ)ԗz_.eEþ$eUD:c)i>'fQԊLOHMj#<&?z';™2naod#`|ssL? n'|l-ݕ+/7--f]/\~ڴEiKMK'nAݘlZKigu7-cS_]~yӃ7.L lWOQ>~3={΃8 } Xai{L^)74_ui獦5k ]Z.eQ:_7o|ȑVM춉`ڊ)xuEvqA_AO3kFZyNٱy=#Fa)zh:ʯr-%%$C}$#Hz_9?;$xw4c/ˋ'JƝw9uY*Ǟ;qPy}ѪZk RP^T=IΩcvJszE!|h&RVO o矟S:WQݚі'&zQD! :ԺuF tr0rJdIq}gwHc1]L\,?'똘 {U_HB>J;DF>Jlv>`DT@(iXa h:F{n>33y7 ?C 3+e-)do~埌?ei]?c=mބ?n1#=oikdiW/H'zB !ϟ/'?O[*=Bo[@Y+rIkNOGŷ<<xAgF=|#Gsc/ڿ[2Loʼ;6Hŋ.(dddX%NJ&l ȯ .& Mg?Km]MTN8AH6d@cŠ>*K.D{キ:}9EXK_, /NHx3~d/c^餓NCgg< /z뭗@l.W^^e¾>w]܃1}T~hyLTUoZ4Ͱ(K$C]K|$:$D.%nH"*!JhGҨ \WƷu+|-0G;{0JL('uKW|O7> _DM|s<4/ S>y>"_z@c$:|*"IԘ򞳅`|`3H,soK1Udʼ9_*m 9;O?FrC!q_ZNݖN>.L-珮n=?? }ߒa75ˁNll`c5˲a#1>efNK}A{ ҧ.//:RÝWҨ߻$G5}M<|뭷0e]t^%G-b#VauٳP&|V!b5dC z֬YRAvV歸 E}jUwF_f×`ɫZw-c#HAɿ,UzU Avhoic= ^bs !^ۗ=#U1`)V;%r ^Cy#'?4>'mc>Ю*Ʈry ,f""6hQ L*28C}jUe$%[ה\^^ kIOa/&+-[~&rM,U1&aeI['39v*W#;~ X1 kcHc 2K[O_{FO)O]eiiW4)w@c D͓#_4[qa ~Y9쳅tw˸o^ Xm7MWy{/bƅ⃋cv6֒}<'&e/h<7M-ݹ瞫C=;#>ݷ-m8l+/t~Ut޶}޻}*׾=A+^tgLt=N8%tعݒ%K*qHrW%y͡%'s;[ENgDY4+0@,Td*R⤘`Et;xKmΉ6wmS1Id*]rU;&}L?6] $;BT#ZR1E谭i%A)=7t^y~2!=`Q7unŒ\{1kw]O\jyӹK?s}w^^}iԽ+$9R~cw{ln}:s~¹7u v.N|ʊnugnޠO۲kZ\{2\(g~7d1ddzjWW/~z6x׀ 6nhoY:CYOG?=O׶K. ۭo}멺G}t]z.нon֝uYZvxғ}jZY~}_WO*zw@0mARPqժU[l76l?ylٲ{EiU<暉~;vy牺y,uetغ7Z J I-`(P\T/ASFĶQMԥ.~9x[OkD O&=svF&)qH(%Rh;iX\1a,wa[eG:{0: "|f˺|։y*C͜'=}E٭HVwu|C?cnӍZA ?{Lm~wiU跸r4Gﰴ{qCpcO zw]Ųn-鶾η]7vW\ڂVw`\q{o{#92u}`#wbq{4i]W0^~RR=yOw;~^{m Wa%3̵;!|{CӉxF|DzԣZFpAF$+N8%N\|+׽uZFAOwܱ;|`pꪫM7ݴV}ӅX,? 65Hܑ`CP2ΑRZ]\`$G4/ Fb5i}# S/ F@J$#rrŗq$2|ǥ+`Ī@I d}яڠj;Hq]{՗n4)[m$~sw$_|qYwЏ~SXP 闿m$?J㿹y7wq5/՝*Oiv֓G |SKg,ƾV_"AsA۵N'K 0T,2y`}oWkm|\UqgV?G?Qot)`3VZ|_?Ҳ@]r*P۞qvO{W} {^z-1!X[S' ۵+96-`|K_Z<15|TV8>oԕ_җTt޷k-ҵ+p՗)G)4N}!'~ #wX AfWc60BV蛈y?bE?6o|\R5ۤ 1" #w>Z.H e |TBIAW$3"n~<`̜2f 5dwto-!-/2 2$m=胿IP;@NM݉?kZHr#+.0^=_n\UⳠ?SN8dպM m^wZ#T>/۟"ɉU>N/x.X(m߳%ze ;VE2a!_V˺'VV|lF}թ߫QUV>Ⱦ~3J>3[C|ӛt"}k^կ~Vlw]ko0}s޼V[?|cUl&ʹ^{u?OR˗y@;N~3鐌Hx"_?)OwVb!@kqX(ȭ׷m:q#.V[g-ˇX>N? ~W0>=׺~p }㽵oꗤiX`]y|B /axf9Ւ>˻gݣp-~?.DtQk~[/^6$p]|jYueY&QF<>cMtXyx%pvi^zk=Q+z[¡ԙ+wD*R|H~Zx+7%cp[o|P5B_As1 N3}W=a"lzVIB`$_†{}U^TsP|W5c _†*|<>*@ ` {F&gp i=yO՞6hP\;ÄMb%sP KRNJVC$4~"yD K^ SF / e {53 ?ODN`\&W3ԭS xKT>sn1R?~e`ga$"0Q=S<~ᡮ`t ?"[~_8M߾XxeZPwlS~lSZIsgHв}~Je7tdU?=Itn=|*[ڂL E|ėο{mc#Ztm_n%TLӶ%*H'Mм__W~x6!9LXA"o%$Hxy_sU o=jE$Z~w}q V>c+ ϻ?4ZN T[{A{w3,RgC`+Q[*~ iX>T;P%T%-Kl# o4NU9X8"K̿T PGq%A]R'~Ev)/ꁔ*<\(r %qm1Vçb+1V>Uުg37.Z]>Wa([OW{l` `^=bM'ȗVK|i߉+%/C] o|旟CyK3E/6*u ت' m p;A]x#Xk 0b{BokF0 [Y:2ѷoay7N9[5M 0b9眣MMMz,Կ6A/9餓>j.e;v2B,˄G^[|X"GO:OIE 0j%XHXn݉'.k6Fa#9B ۯ_ zrAWy`pFw^ y/ArvVXV4U|zjU_-㷺խ|\ʖiR7[͊~G[\%/p(dE`T&6suo&.Q:RV1XjRnA9%?1O}Cx GsJ"I˃UHh?mиS4YT!~(x6z# FIr}NP*' ƿ?U*w.r}) 4s{)LNL\GI}%[7v;[sL?{c7ߩWewx< Fó#/ф,x>"^Ls6m\vm;U/bm>bjD׈m_|ʰu{M7B\+0l=馛nt8h  qޏ[;K}AIb> i&ˈ1VUܽJ__'ٍٛH_f,eΗф̝Z-:_N/bF ~\#UF-?<==fQ=/ü#U,ux%&|w[oZW@\%g߇4-9w>iEm%+WwOuuPm֤ϩ,jH ;%";姫ףǑT>~xN揞.19K~8ye"cUO)+["-gZm(Ϫ݆Kvnl}_#ew4-FNЗ,x*&# ~I M\uR2_ 078QPa!U)R+u^ǗA7jG4$~À^aԩrmNDr/&V]"-wѼdhu|YzmSd$~Q"`d"l|(:,n{H?UwXڽ/`߽VVo_jA}{ϟ{Sw7n!} ?onYu˳ 3unn&}Oٰ jLF̟ª{j [֔%Ϻt?o?fK`M!Rd/ɩ_p bH"ſj0 cݤM}xJ;G()[iX X:c@!GJJ0;m`"}@8ʙV\꠆el~ w'_'`}m:*w?iCo/eBVABg,{/w4|w}Ǿ?V$_>}ԕگ}ٮӾ5n0_&>Abc{l{o>7v;?j}•3H_`O>y'JD!-q":dˉtR)=g:$OQIg0!ЈM)jBI`NĠq)U9+џS`Ɍd!N㈜_~ΖA Řzʭ-șOlgvO\ -2E\#) HW~QN!wmV0"x{;o=a~gW/ ԗ5_*cҏ?ks,'xmwDv{`V[Y>_],,:٪_/vòn;lge6=G˺7e? ȈvnK8-ɱgUCx~wCI",Vg<#-kdk<;p6Pi B 7 Qfb=:ohE e@\-@˾*Zoj>Eiف؄4& UڎR!0G 0q\2^^HN1^;G<Ϩ 0-dBkТ2J'>mޛ }rF|*d;Vu~ےEzwxmRFVj[H_]sskVw-{Fg fXuh\|s*s۪Ū+"=%$8=Րh|U6_FQ}k _x6o_꛲K37kE7uXi~* K^p7೔$l^΢2!%7zWTzWoxv5% 6(+,T$\߰\|yJ OO-~Vbf ,IO8I°EzXWa,X0R?)#Wm++=]I\ i ”RgYouvk6X=~sݧd_ӏ@nk { mW Nƾ~w=$YmiFVGVw͡"ݨv(S/J]'~-(ݷh7eGy3{ " 6%Ru+WtOS"r Ag䎗{[ 7ey sA(># 6 _{b'ԗRƓF j5aoǩBRhG+B%'eiYwliO\](7)'=}n۠g|W-HzԊ>d^%_%7wo_9=TOk;&k/ Fɀ =0hB?'C)??)E䔮 .]{K#A;M>i+uXʛ݆~`Ad>h$5 zcDSx_񋸂a,Jx,hR>c@s%QwvdFoϖW+3%?m9g}UY K="^ߠ{-8?aMe*AA '~nFA=Ezǵ=l;k¹+7ɛٍN zmܶg0 W,F 5u;tl4 t]u(#wP H6JTI<&JOȗ->qWs3J9e|,m@+iWV ~H}_lY}!p*tsPgUm#R?<~?y嶰PaE]|Q(2A[ Kp1߽A|G~ `c y&GxxƇ7:Ww[viw3]%k]*s'/P$;>p}AZ6j|7.6>K^2rxI #؝|ȵZwc7T}۽6[ς5D Xg0Jw'v-59΋K,uȚF'~D+ F 6H*eS S?vD g#P1T &Z]IUxF/fk"m0~n&)-~V0JN:\=`5h_C1+`BAYI3 Z}ywݗ[]ɗUÒnĴ}ݍVwE$r/]m$Zѝx ];~G~w[E/+BS@|lFz}9+~TzCa;dDL^`R⫿Ƌa{[OU۴\߃[!ظK%0[v@oؾϮZ%/`Y%UY `P.K (>qs~`#-%D`&m^7 ({>$g_#Hc,a+`G𤔵H<*SCDT"0ѧ09gh2L:Oꛦas_nhBRRgT S_q_lpd $\y6ⱏo8ٶXj|}s4nwD v8/y~5 ~`rPϾ-S?D LT%#%u.uP9XXmS?D\'X\1#H柔1&z*o} 13|"-^Rxܑ!uvN%VO(D 0>%`,]Kfl !g^o k DS?b?q:hC Lo&wo+$~19uwSe}9TR`˹G#%eH+/xt  ]/r%; YT JOzWm ( P]ƟMr*?L~[u"dJY@Ee,򅂎ךv:gCzSi= :9l[biOq\i8MSvc>4E>GJL:W+ER蓙Rߐp0F `3%?@zfRO(-X'O# yYՔMR2Uz䁝\L|\D`V Fb" WmH/EWo+ F:)\v+IyѠY)hEIEu6a4vKQ"D`FK^d߶ bs~rf,'%'ˀ+x2:~1!BtXi45R_`4^2 ,ƅ3rA'EqʩoÆoI58Z8S1L0k;&|혌X1Pm`,s5;J%UKPsDSRO_b+a ;+],^Ǘ]Է.]pԾ 9/b!x#n{n%RU-\4 JS$~ 0fl! cŋK'_C6srHS+f_wQsbUps`iEA2VZi~,4~1Wȃ wdNڕ@d'~)h`]HؤZ(ropfk}uz^r"L}Y-~g*釼zoЁb+?G٠O~!Ox2fyLŋ+6t]{YK:u~C/3u(4Sl(vQyZ+bLoI⧶a1hg07mnF0@/D~eOlwQ&F-Ұ~O}6홌hb)MCD9v \(@ 1 Cu ظ3AO۪D=3E`~Q{+ SGY_ 'iDCQd,6ƴɌA3>*xѲ({^y ;~!W03qgB;W5$T5aD̗u0֠s!S[ XɁl"b`iay3<˴O&Б˒|ɋt"S"~ ZB z3mM6RDkۨ'@t" >e֫,,p\e֧bs9/Hg>ˉG)DJ]&sBdYO}BZƠ] P(g%8%FCPƠI5H**dj>Q̎ITr%% ZQXW@J}&c EzW_r%@)&$SWo*? 0b?gf{QAo FIB;KZ%8 TIsQx%~_)"(XmU<_q!p{ [cklq4̮w #EƐ4&kR:] tR?O as`L*?U#hG kldN6Q"MVMN)jB`H[ s}kB#٤q~Âx'/"`؄= ^ΰ7@ʩI0FQ'\QV0VސC+{'6 ɟۗ6FS`Q/Ǜ9bExrX9DB] DĐVG2+ `/s\Fa1 u YcLXRGFt76tl8BLY >v k葌‰/[V;I}cTCc˭̗ţ.8 FqHAU&z oJ=m"GJ(~HU@vm-K`&@cI 0t'}WmE4QdQ2R_p\0 &<N 55c6[8/bѿ}*)9d O}!3+1l'Nɺ"i<>W٤K}3 0we/0Zsz#1)G(wR?.&0 0K^Md -6.jϓAƒe)S?7.n00X-7\?fv]DNig`Em*vmDOD 0~@Gssp*sCʘox*O*Cbn#n*k 2)ް zc=pt{@u*NXo2sS>?ZjA:~[kӗRE\/yQU`0y>(:73G 0aG'״Rrwi",T>aWhjb| nN)}P }][MN smYR@_f񋶂qW]$7}(Ky>| ' FG8$rJQU,cN\躏,& ty6܆upHD A{C@,B!qqfc*(KKDN#y~l0?aFa2Ȝ ɡ9U#Əz܁E+=4AqJ|-() :}6e!o{^,#`[9YۡqeS/rNZOr; '[@r1M(N ˣ-{7?%)T|k#G?~ah5-I) _:olle~n&oХ/>rNնl=g_n?c'bF94dom#4J[Ü-RbT{N۷V3H1S[-bAJ}pAF$~1 FnLɵlZi/X?Zоiq˵m9Q4 p0Lrl6S}bQY?<>DR4r1H=m4k1x5vo/b[|ˆBW(;l"H>&3){qƌ{\Ji ).ah `g0 JI|!QJ9q9qce< E 0>@H`M{.PGs{j!=p+DaVn<&F`W%/^+7d6gR˧{L}bwɠ} 5n{dʙxNQr>/ Ƴ`.XَvZSELDz,9Ķ/wK^dX[k)/1D/j6RùEaO=+OajA>J9a@\HT<ۈ/^U"gd!w,GϛmYi;O}`f[^f?qIu6JGdoL`3D?&R'iY&1'y"]!Q}vj^O`qo+쭿T&C\^tl<[Ig+6+L@"03d 'X7$f+Q!Iل)gz3|9yΜaz9sʇ9뙳)gz3|9yΜaz9sʇ9뙳)<" F[Y&$ycuZ_FOZA[>[{?es`խ`,tJ{'9{S$"uc>XtLu]1 ¥v$cX"FX@D  Fˈr_E<)'q=g /g0S6'65+sIď;=X:3Aq3ԺpOwy:cgAAAI+Fƈ  tC [QVPhORCaUOhKf?~rbfK `y njMRNUhX${mN?Uҷ~'ڋhdjD1SmYNO~}ݎP Fܷs_>Ϸas_3H~gg0+MKܖmsZi kwpo/jLb>w Rߐ!n!e9 ~!e#rA݈8MI?#A \ +E+A3Bt2^Ǘn3/~7~jDipK:zSă 0Ѹ"AwTmO*.Ry~r'~f>~_>#Nf@"i ai =OS?3 9S`x%Jq ia4,Eo>n<_x9pϙHz*1R}KCJ_-;i MFPރԺWp~q4S{H.~j[o)~mb|&"E` 0  Vg1վ%\r#VgZN>cmd3ZP-3h4G~9}[ g(?OVQh7ԩoAįyG y#bՈjR_I&"~yf#rcĻ<iˆ8\&H㤃V~lDmbC=vN :(D&97V#Ӻu&~9+Ϥގc :Okm4V01 Mxx\AlBߘ"AxcԁhRP'P7f?E ʔ$3A$:8rhr\3Wp?ѸQ[Pr9#J`q+c.k %pN|Fg aE6R߰h8N%:~V0j)(I~OP*+{0vL}z(!;-ɰEArHJ3c\dJA[u%ߚD9dH~XۢN[X[0c[ !f UeMOUo~xqR3biNذOJK `i%9<F(P[$!ñqd49G%y͋cYS2iV|$miB)ٸ:.mSߐdPAk`$ࢗ+'R!B#0U +:>f?7GvNM|YN/WݡNh /~`cϞ$Xl}l.=2|[Q5Ȉ3ul9R Eгf5LN,(7DSCoIm;'{nJ} zs@@㥬ۤ G'dͿPq˳RLz~=6Hb9e1YHf`cJ|ga`^C7m]9i7&6ÀDVk'2-~sivsU0~&4?d2h.ƌJ;ieR WS~2G}ٺ9LIl߸`ۤ}T )=P`')d$n:toZE~0o"w2 */fof_HArw B'+\EqIC-3Bl~VXݐRIO8A/(`=*0hy,Ե$T7Lzc_g0mוt!(Z\d>*+n'ulɔ$3H#əX{tԴ::2A ,)g9@]}E:0h׬TPrykõaE6)Α&`sk$G Rnfv[PgzvMh?g0.B>G*x"CAMP.`4^s 2lG cix)94^6d}v_}<3s|)"*[p5'GO_T.ޯOm~5%OG$cD0L}č9;~9YsL8aFB] @Nԏ_;zK~&V殪?Gčo}<q4PW5IK?ѡ|2h4oYNŋ-r`b?I7.1򝻕DS?kD\Ƞ=Q w*OlLǒ_}=OH}3M{a:j1zg&6Ns4N c8C0IL*\+LZ\k3VL}C`]yky/\X;wzN"{JED XF[H/4A$tGԗ@fE +kh z"r3 wȹAKY'~'Z0t["p^ ))~*B_bt j30sXL}&OJ"ex`rD*%~W0bU]!{:QCie{!n_[^b`Tr Y3:kS%*v#~.kL- W }T<;SQ6yf xij9 ߴq?]p.ӡHmr# c=v #Dz ۥoI+L@"03-CqP:y:-`9v᩟`H HfqFf+fMkԏ_#^F QJm!gs7Hz~"mS6ڻZ~ɗxN ʩ/P$~H[HqቐBw%ЮbK?4)~?8` Nؔ/y {g?CxAe%窃O3(A&^~2,Ie-R?O`?A?UЄoȐR@H" ҉AHie~@'~^6!W+" FՕfN:+6F.GYLŋV0ZjHsh^rl|$~o?!)ВLg ƕ$~e. v81Nܥ E{#V0Z"9D*F|oC~J]pd-X8Q(c ZMYN:"+AL@"0#l%+y&\rN7ȵ.tR?b?qW0D@"IdF_WBOٶM[D:%)CA-z/ iA9cd!Tb hI"%~W0?NDzo>ʶ+R?N\dJA`,E|s$oGsTY^E5+V=5R @I3 @6XtmlcÈ86Z]~WILSt=j;R hƶy* ;Vya)sê9_E\>kx>E 0 r3{dՀm>3Xcb"2!.˚_{4@2o`?o-SHUfJb4 _gBҗ) zIKIeRN;A$t?[sp!ѻ0GyctRDz@~£wCg* FC#-`>D6u`aCx'^z<_E2xDL@<)BԥS_ᔘ-&űy_O>Q SfvxS׷yw4=6|YN/;N/#>3_f3_JˋI?`c$?׹ZBQPK[{ؖR%~D 0#g\&Un\ď}.'f/#Xi6 wJMR?3`<%X*WuI>2ڧ'P z_ `ױ\Aᄍ&=orja'(#rP$~/`y@)H3Lp6;G4/f?E|^>vƊ$l2k!|S]S0CϰE ڷ-Ҡ2)3 H/~^I=V0i* ADz&Զr'~C F#Rh"aNPR!K[t IdJE=Qf6+JҶMR? AzQF%W?~GO3d?&oO* *UrsԤ~,­`g0Ε(H*,|Uִ:UuaHI5dj|BJ z® 2++s#l>S"03`%eeFkT{xco_'dS?񛴟ˎi &O@~Ѷ!X-6/X!0_7P|RCCی̄+3/a;r6Pr{RTQyۀك+y&[޷cZ+ʘЩ,)cζ,T?w [CYF`KO6z3>h w$~HO>$b4Z=Z7OL5J{)%2zL.~*1*x{ 0+K(dT+|'>=?w)sR$Z`̸YԷ>% 7-e,'C`D|&GARU6*jrߖelb9? F}\(yp9pj1Ya5&BrJ~tXZ333h> ͐MƩh?m0^bTP: z16fڴJm}<6xa{AV0:NcQR7]s(JzҦ|W0gzP`-m79K@"h-Ҟ:tpNƶlW̺7Dq;g{ ,ġ (Õ?S~"rj\S7O3zA$u?(J18ddZV<E[-j:LҡRBed^*u'[3:~W0_G)ArJdQɛN7,/ >KYNH S3:WΩRqW 5J}& `U'`~" |18~ K#? 'd0DW0* t 6" "BؑrO #.@T^)UQi<E{#y֘5PvI6T *z"iթO`܇FR*Εo.Aϣ 0k< RYy=L;&V(~ߋNˏ{8qLI-CH o i;~R} fOc*B ozPV>'IZ_o4V0Z@ܟ6-"X[պLSób;A+9_%8S ܹo߰pxE3}D XX`M͆J8káџzc/~a!U@'VkNB(R߀DL)y$hGՊ&[Žy\'Wiɇ14y4y_=P:]>l9#ucscySF >1M+_ZIHgtɔ$@{Q3ͅκ \10 YN}L.?~Y{*$H|сd -`r)El~c~.?.31TJsO gIcMO=HxEhڠ\\)tR?-f.zCX;Gy=b3e˩oUt~tȖrbf=ze#I]dΏέۗ_k}-K]+. /C/b05wFڎ^ҽ[JwSЎ_i^tH ;*x^2C穯/sM`Ծf.ɗ\ 5*RH؛MU &/]P} l$lc1.xڪ''rR1Lrr/CD\ZMW0aWߤл؅[PIY"e? sw˖1gpR_6quYxs1F1Q_do6BrTĬG E:apG)joďh-HN9Bb&4jS4#n( 0vkbA5nw9 j! GD`q#Hax7ΊZG JmS.3?33+W*Mp\Υ*`H%yL삨w{P8,aTxD֖>L*xK胘W U-֦}eSҗ5`x+.72vǍCz&7XB)d4O+5fJYA|P>'ars yGD/vN>vK%OʠQmd)uubsITI}Fׅl6F֟F;B &?ˏ;"Ls*grTY{s4R(*v[QRDfR_0TڰKIԨrt>Q;<$:O{n\6R޳V*AOdD]q#V[rKMfm `6RЦ&K|3LK+֧BƠ}"Ϩ?n6wn~ZDPk$J4\ f]U^@m h+`TЗ͠}},+h"_;_D#">\^+Xe*[i=ZGm\)HfnC47gM(;3L6ed``-eU0*)e\qg.T,%2L-Hœ>w.r1O `ib+(ҾԐDQMfL(K"}+cvɭue%Mo!֤K}"[ݝvV.bf=zrcR.8< 5ځs-ڪ*z8vOoFyq *d\)SsPV5J`~>񋸂/NRdJ8_~J*+_wO4X&FO[lE Q\kzl¥~Ұ^y?d-M7M C0T>]KF/]@L@"0`#N8;+cG?CA۰O>I`W&H@#@ J֎2@;?t("ȩ`HIuA8pX ڥ~sQ`/\(*veWÃ2GįL-wgp 1Ie4krH}av@rtyLf]Z|Zz9gB e>_\,6!DHJVаkdyk9/$0_$-QaMՑ_hAm_>tLX*}qꗉ#F1Ɯus_zg 13&&iɩ|Zir1nz̧&iɩ|Zir1nz̧&ޒ.bQW0I~*d~j}s6< XT& |#~`BL 0 FڥRǩs9;}m[1t3-Pf䙾GՂKO,?tWd> NFM29"[k( f?~(X.c;RNR:n "Œ8y|y>{By@CrMZGY7"ö%/ao}^"`|"mfqQɫr'~eF RLJtBrǻ^'*__`n/?cV?9hgQЎVPJN FPt8 yk'jVO> c#%/zKa.ԧ pH}Au'X42 Dɔ$3K7W!58h CX,Ȱļ28 ƉlNo(T"NWڎ?Vc/bѿ8mGjd(M+ʐh<oj:(>Je Xmdc8cXƵ 0^Z-௉"D8C22(>qX/`421d _ؼ'Eq F'~:XX Gc\YSܧau95@eu#A*KOT훥Ǎ``qLusHӰ a'~ 'dKmVvu9,:E>V ݈}dJE@otaf0G*F;3y[`-\]F0`BJp2\TޚYcwL}#Si&$Sp5HNI O}" Jя)Rg: @rG>Pl8 j[荂wqg0J)2O_t!g=۳m؞uFXfP%^+C2ϗ~-{6[:rO')R` !̧/W0 Ft AF7[W {tɫ#l㥁#~E!=$Bn A)I EB (PB64)SB'^C:""gf9{Bwfٙ9sDO-i`Lw0q2xLʸc~͙R ֤&:=l<ᘣTl'pg;SI2-V&x}#XfdH>e}v0^S"pA5ɌRW6~P;+#~)/bB)%p%B4b){äS_c%PB`#>3Lp2kiu}_Rčxo~w0ٙ,dG9L&.sk03(2&Sh &]M%w'h2%LS˞L0#By~1 J;oRa{Ɍ_c3c+Hc~(eo dƯ8U B`mhHO֣}p$mz[uM^zW)˘`H;GLlQ!mMޔ7-SrJvk\蔘o{̉ E8P;p?9/֯o/c ʌ|43Yϋ_K)P=(HTRُ=ssυ_G`~K/R P 6]M5~w0# FG FG(19BDGI51~9naN1>cu,):^h8<Έ_=v0Z@*g]L,b+\l e_u95SQv0NB PkJ ;vxާ! ?'?G [T1Y-@%?D6!.e_'R&CdR nĄQ ю5 I;SxzȩqzM:42I(hbDnA"&čR'~v0Bb &g^yǣ#.Fx8cKV\z8+Ob+%`mF!1Y6̅g\@tw17PVpB|_e;wg\X/S6fQ*Z;&"Dͦ7lI{D!ExV)b;y(O9I$ w0O=B;3ƾE]`TlUGcVNyƬg"H{`>G|.@58mfud@3CzM(I/c2$v@ʞXln]٩qT,%X$/#xہN 9X~xb \[ ?qt ƇC^l(:=)¼O)WmlQ`bR&( FI8>O4hP_S?Syo4~`#(^X%򉧉8%<NuX9kC٧/F$QbBf&!ʯ`S2)Ecpv@XaΖ=cB|@,jIƮ'onVk/!mdЄB^5f&e/h~)G=*@!&`g&3"s}"i%"΢D$+'0QύIH.p.ɨ6Q^ȃD78`F gl%CpxF&xxvmu qoRFK'7t;%1A}qK8ة?q{S,BvK`|`ϱV`!MK^ހS:>𫇼茾Q@!%ңYOe(lz\9lqvg|tiU"K5fк>7oD}(bB<&mWq 1k-|e;UO' |*%R'ڧYw2nJQ;ͦ[QW{-鴧" F__exz-`빮g[.ה8BN;2'm2Ө˸+xz_S[jLcǓ=@q)j~Ȣδ?mGlOb S!8?(1Pʾs_{u /cix 9b *{Rx%ҵQ)P/ YX,&X!ɸ WbbmAw17\*\`I0\x8#Z mL'Pï(sXLLڎϸI{BĘ/rCkץNԣﰯ le&1Pc)ȡR?,)bL;\7 )w0JQ2rU/K9C9ts1^sl} q{T( τM)gs?=滔}&˶p9&L8gԚKkײ&)~9켰FYL6D!sQFZ=K5v0i&e!d8 D +}xג`+Z Dpt,(ڐS}vi"I]$C}u炏6rDB+{Zeo 5dqt!31B= 8H^ ZOA 醄yз/ +e㔣TC|`bzA'A~S zُen\A>K $}M%#~*@!6K-Jw-Y@bG1Hh$ z:]EQ=^ne˘`D>ń CMm69-\i8\K)~8u?D|Pe^~xJɘ`6H3xkcM 6sze}.f vG`\,.P҅F! /O8¤M|ڨ2uTmN/[:oIiS6j}߲2rJwKéկ[r1sy폺./\v0' F:pn*O!0*-o-c8=EH]5=^C%m#N9g8m&mQ ?O#題rRca Z6CoAD6`k!&`FEXĬ&L?nѲ/dDZ9>(0Naʐc[*#~3sf'GCfg<-Qel e/[~?9QO@@GctcZ3CF1=:%k<#Jrm`: ~~)]$)ӻ߿t!vsGl2)'mcawLرM/ F{ȋ-n_&Pd9F*{T ?IPl8c)f cд{|zeoC2/bl\·MaJ5PQ-}7?)Oc$  D1I!Ʃ ʊ_%jPB=}Ǣ|<صc~(L^K:} N:4S&%{On4NYCwA4}'79K .q2wS \lʾ0`xb509zD _뤩%;^PIAUЙqI{~רR@DM]oюNVk 2&Cf9%Vi xzG^AL\6O\([fԝ޲elsu[֞lMSwzsv-rQoYvv0!/\3yhʸeXZꐸX=PT-dL0ihœN;$> #viM~sS Fez- @K6yaMlަ31>(%8$'֐vKLeO&VmNqDڼ@_5!-&8Xc5aK`eo qc| =-Q~%#v0ĩ@ 6ΓhecO3W J0Q/ bSEMmeo~)aȜ`B&rIOp~8Z` F$4$Gxxj""YHαK0>L!C9pYǼW >!!tbb;U'mAVq}mqqKI_݃m\F!F>f.{,.:Å̎54PAŐɄ_#O8ip>l]K'#adf8~&y$5Dd*e@~6FɖקH;NX#A8N.gd7)ʚ o0"Avx`d I0H& U D괺 Kv>Eʺ"ח^gx46N-)"sseIdeL-Ofǂ*|クMƺmM}oȖ %Қ}q I_|΄ާ`>"#/#Fy RcuDtjS2I`%H)%$cl38-&xD|b{KuFFT]Dk0X=0/C[~D?~;.Ǥ=ޘIqS&NNJolGό&'=8*xi:L4]KdebZ[ڷe!l?\""I4[%`u*1 es>EZv0*O-b<tjGuZTU l:~QU B`]VۃѾ'cɩ/Dd/ l 7侦=) |bZ1ֽ<-ea/ep@6 j`3 lU4h2=w7(U'63!U>ϱڗs>Y@OX\mO(wN 7H,\Lw˾kSuDڢ Tu!Pls`P(;PC*i@()CKd9ePq.)`Z^)6e/#tWp3nHl]mMelI{M0*!5Fiȡ &EPqGde/%g]FQ&#}OK@'ʾg|4\u9TJVlcpt\3r$<.^[Jx&+~g%S\k8R)95`V>.ԏ?a.voca=G*U}eohU߅_#.IAXg@edfCeo;-%C^`*Zn@r})[7.uʾPwpKaGB@3^;]2{|q'p;Þ<$.kY@xI&/{$!~Yw[1Yk%F2>)W T{\  !=1$ 4-赯}7?Y=YqHc4q,ƪ&;~9w0)6X4qx>u}n eO\WN7?? _o}[?7~oV~Û oxg=\Rqk ׼5C=t]=vñ# Cv8)-5瓍[2UKn~D(Y\B_&‘u^|Rr&ic)rc\G HVΛb_%0~p=9|+_YJ+^k_77gu>{|s~4^{QS>f7ٖmcsΙ_?<oczYK_IYw6xG$IۍdȨ(k<*U!SNiQBã'&՗I'$_!_!gcNmϾNK0q.C&K<;f>ᥗ}ep."#@dL0^qxȋQy[@-p~Pz {Ixφ_%,O}Jw(bb,??:(/˺H`}> ؍Uzܪݲ#vwQy/rx=׵ N]޼`$I0|+Q?ù;ۖh`!Pj}fl ?Od)Pa`>deo!FlLTn_0EWXd _?_Q++_ Fc"c:l.{a`"m(諺DK|JJ/i({kJ0Q_Z˙0M]z x3~~ӝ4oָ{Mnrb؀ xiQe.<9x:JwBjWJS\=mˬ 2j}/}Ko~ۿO(%$h\}Hv L^}HZbl MG##zXl}stޠpjyٔ;tT1>-`s](F!j;jaca~%$;Bs2ֈ]2JV#2XRwڐplz} F:-d wLBW@z(eoX~&?;"MOk^^W}l;f~?_1 ad p1w[Rw]~ w˰CvRi jnJK5U# vX7ITX|;='!y[2*z?ʻ.MG>r!:/__;{{n[5m 95}cb3=^&C[9܊N>;~9e`cL 'IGb]Ƣ CKar4uyawk͏L-g·+\ͺiعBRbK.FN=I;ְE)sO#Ye_KOO8@Geѿ__ zԣIE<V+;;7=󐠼ҕo{hPnu[ z׻fM9}EȄ(vc^*WI=.+x .F ui9Eö;1 v~ˢqy4~{ޣVC4[F.4ٶE~}C9sD;E_+&I;*$q9OGm/9)M(ΌSYbb]e Y˖c;hCIZw0 )'@5|q٥@5/Ks_t! e1Q+pxJ4 /%FIy _ַj{_>}H19IَjҭC '07*+[#v]^9;1'eF++zIulC: р c8䗖 )bL0Ml=„K-pSmBiSJ[`z'ebS<׈;i2iúX}Ǧ3Ʃ}i`vX;X8&wƬʾ[?Y/"cF2-y('CHLK>W FN.0 BA^C"oϑG9?ozӛv'wm77u7E;؄犋au7_Xa199Y99Y99YmƷ0d0OEl\2Q{.2dTL.p((9ge߱XJ$fBg,5lґԢrFzqmH5c&iS˘`cB08 <\C2C*U#+Kd۾b's\|>Kk_uBN9_:ѧL6.HZ}_ԾC=T2(B;I:\KZpi4.FArO/?"9=he.x"r$]d, ނ =\la*O%gg>;xjDĥx` w$q$}q ?яT1M^͈_g!㚸rGXcm-H4hbS2FftXݾ/x"2/%7tWXneQOty?pA]'YNX~Z3{@yD -Zd?ޣ e?.~ZKNM?Vv|^jOw\}"CA"ś4:B#^joowus+ Ƙ8WOb)Ʊw/ةuFߒ.%&)ʦC=7M˾#0T6=>Eobsaggy#T6=6Llsϒ|yD{&m$qD=sVYx-y}/R9?Œ?Yn_F=MΪ>*U}eohUE9UM?_;59Ӥs:F#aEAkc!) ~s$nrA}/zmx0 .Qf?SӇ!}x;?&+yA*x{_Ăt#.}qF<𲗽l> ۏOs=>{n?UU\ˤWx ϫз#"φυ*}[tJ6\B-oyKM_z' lR `U9 2^{0bbcO=qhcr0򀲲<(+GYJTt 63I&!w^ُȋ_6N* 4F9:Mʾ#P)/>15:4&&cRJ^TF+N =1ZPՒ_]"Uöl~'o^_!?8rk]%Ԟ'=<`;؉3 Kdy {\*vħ^a'vμ> O<@O6z$Sя~{^n%gG F$Iq_G'?h>?r{n:;IoteչSM8!xԗ֬oKydel3wq7Β܏:Quf.N&𱽉qW0g#c<԰ER#n?3YL*{L3Ʃ}QLRĝ҇\b7ӃGn*~g>[^zg|^qF![u?s9kAS}l SM_umv0KI;|.~)Hpikg_җ?qC)e/?ӟ=}3sw+?ʃ}j~~I/F%] xx:7ʲ .QwC#w{.N ֩q0<'K-yH;BשC%7~n8 R_s IkQƺp"%tVV+{C`Fvj#Ť>*sfs;Iz (n&e'x @C2ѤvKbzG۸$@jTH ;,LIţ$865ݲ'|DȍZyqh>-w 'g} O<ĕ3&,iA#\$.Da>7\W '$ vq~k_lw&];N0;~8K܊%2BYǤb{2Q0!F5e|˝`]ԼY;h\bFH^>~e }{%/y~8`򗿼S#Y׽NuoإȲ{n9\|As=3n9W5#.v,xh .fAe%&\"~dNНyB#  9D9v635y [?eS^%1ln02tz_9욑?]U6Ql>~ْ!8H( 't.@LqaVя~t oؾX}o|؈IM`|9 [y 7cUyk_sᓟGÆ;Nuw뵧msljǃ? /&thQNnL8pK0   _iCw}t#k'@ _hM,=.1xGdL8eS=Oe?W!v ub 9c?hGo'#5PO}0>vǎ}mojxcXmGxo}[wB6M;|3u{ݰE/zQSO0@ciē򖷨5 Y~Pú[:q 3ExETa{Ylw3!:v >tAo" 7~n9I'І~/6e߱ء{# eM(7"& ;91ش;Q;} DR.c]dD F%XspG&5kn,e$ ?+h "?u{^( {bO&cPpi/c$N94{m v{-oyQqkD@2?F} 夓Npi6Rޗ0^߽}fWjnPj$%_1^" pN1.G>CyzYxGKa4}oO㗸%ڀϊ(sΦ`# @ NXdЄƶ+{bhʌ_KmWJc}%'D\6GbC]6x&/g;Hd1=4[AGzƽW&S18Xĉ弥W:AXʾ9 %O;#%0JXxIUL/ŵ$i|~.*awGC}nzӛnKv щ\{{R}c 8OYD}^zξ{x?^]zp[݊jTr\b΂d0 s1v>C9&]LJX DCPpgM &}cKorrN >$&}Q&e_ɖ GNoTU}_ Uew0*8=(=DesգeoH~m͙` !uH.A0gmW$ΐl?*HfwozH!Yu~&w= wT)Oyn=~ _cd\U|+Ӣ+H.wrUŷ\77`=$gYKӱ+H"q/ӣiO{G>_1a  #ۯ؎'#FHH){ۑqB6~_^SF !Bq6mQ剮j"+eTXcT}/9Z`I;_W݊CЇvEN= ~g5Y6aSvURdqZy v; ?>}Z?w_gO[JNcYĬaFzA裏np mvƬt ͺm gC@>нS͂"u3ƃOןӟ?8  ÂM-@S_?//j%G*U}eohU:mW0.FH"ggO*9 8 diֱ"}UDfv~Egz<4.(-{ 1y~/CHYSS҅#ǃ>Lk3)< Z<2(0)% | 09;,VFQ<+{ʲ:~99 #E(3N"WH'(Lh[^Tl>\(]8P t_;ȟߙK0(܃~0-crs |J9(!KE_ni‹S&;Iڈt˾YQ 0pc /,:I2֢h8(OW/9wK|ѺN#}%`l$QeOJcMC^F|:2+Yw-m3~w0S|-e'}qlE.uh주s9V^_t@A]# r6CbpMfeoӀeÐmn;Iq/)]r*HI*DŽ)+vSvytˁ{CDB=SDW&7jb])M0d`=G*U}eohU3Km896Hŵ]5M$=8|iut!B؆ 2t \3ʇv[/ɐF~62ɹj)e0jӕ|(T+*=}5𑅤3|^˙`4u(~g:SBؘk]Ie:6} 0dD556@ %-J>2r?LX,pHI$#(o,H%:0]??W 3, ?A cG`H9cSv벲X~LP Fr #%k-/ :e-{ÅqnDeL0K!$&NaM*{0Ġӓ9˖ oOfǁUKIlqhtr5#7?^prCL7lpI0OO&fG|2?1X+{ dCCa1x$/8|cKXW F0J!P ?(n<\^رnǣ>9AGB&bbC'e@Xp n'IUx4CL"$ EmG*~>?+<s3.ʬaڲFiM~Aƒ*Z|~0tpv~ps#y y@cPTZdz/|+u]8Iڲ]Z넀^i/fәFkz8ͲOd[iX +Ĉ5f&i:MS˞hYl?~9ŝ8{-ڙY:>@Ȏ_]i吼8W7BQ$;YwG:55Ϛ`K!9zNW[mⶮ6 ZMf`TK!.O-M]qH3 ZT۬ʾ_ɘ =mHN&WXC$mɢMlۻЎug/+4ȋR^'Z;fS0LeK`sXxc^4tIylo~Y 0 qG!#eǯ`\6Lؖ@y -M"_١ L.R@QLSH"(3.1,{+y@UDY&/{ Pq̅{ˇإ<lAo?s,1c"mKrQuK u.]mb_%+H낀`l'2Q*ށ/β'Hv ?Y7=+@$΀T"jVʾ3?ɚ`4|%T#޷ 腬*p lK2,Bz]>UdQv2&cc*,Mgcmj#D*{gPj>Rk/ |h{0dA;զG `tEl 7b̩tjQo,oZʩo\rq'US;vnua5u;6 JN^"mq S:;z?4N:B˂tuB/e`iEq~cwe}8~HU B`mKi=)hx$Tc7CUNod|4.^ `.is meO=ɋ_JN%ҭ4Scʌ'(#X3@UXhi{rM: H8=c7E}1M>9t4zI!1e?߅"է_oDzt3^wM!27 $ B[+|봠,De<˸eD8e xC6,͈@+{^Yq^*e-CbƪOƩ=@`h I? zPzC/! F.HS,P 24>XiW.i_T(- .;jL6Q8L;쉄˸jĩzuyù%TQ /-pYZrcː1u˞uL ?K`TjPj!(glڑ;;jngxI0NB΅%&-tPʾtC$'~>v0:%UvF;C"i5@\xD@|ϲ lf/ X)''DMw:x?H>(,D7޳TbϨ&-\#XI5~teK֡qYQ/7Q/F܃q0o#\KK*F]X H[B`#99:& GjB;~!;)x ga+Q5C){e f8"a L\/DD]A$/[1^"M*,Iu y&ˬ3%)>2i+⢝K^޺gL0^ˤ`(Y9'p4.=ڔ=Eɉߩ%Y_!/Y|}E`-(tٌFO~*-̐}֭-C?F/-2&CF%#@%gG*o?)9a\QtLjY~ MP2_'_Š(2eY4˨q_L0>F)C5S6sӲ ?8 ;+hH(R( 6 =ާHTYhL&~n8gKԨ)K6GxS{ ]$dp$u;PeTeoO{L ;RcԢ،e FhŃrB^|5NAG:8@ 0Yc~< #l&~u4P(mO18Wi:xOxuEƗ}tKpM7^+kÅ vN@)C-:ݒα-)¯O ] pHy}eOdP/x}.ZN5b;& p_ߢdL0^Yv0vُʩ14Pt`FGeƤO}v0Vч @v[UYUș"S3DDzPQFmᆯhl.OՉsJcؠD<+OrS'٩GaLsM}"FXqu b'R+”#@ ˾8~>8 h=e$-ɇԀf 6#g3LDn#eO(39~n8cN 'IaWD&e_k8m+d YSTʾlK7=,)2oX\Oβ eM0v~XP[1)A1G}Gk*˸F+{U#k?* m@_|H0or_m1⬓P1?֐S2'k}UN8ȏmb)8^Ȉ_JN-{pxAȜ*ʠK!GFb{˖`Xs<[zPfrn6S*I3ȎګNV]n=׉h%J0Vq:$q!U!pc-3pW 4ã3T|a)9梬Wc 9cC81ɔZr|FKHyz[blDN)lP6 Flx){ acN"x1C0Kfٟs\K~K)f?˝=Dw"MW J0F*T.OQKm'Fl8Z'&8Q>no*~)w[Mn;0MGwc:cF|+{az n'G˖.S)!JĐalI{`d'H2=Ĉ*u<@HqTA݁ZJ/pvRLX3~8 kϬ{0*@!&i6y,XC#ȬrWDJd_" Ե{,}2נPɦᗒSzxw8Cʃ@i&a Tez!-LFϠtTPm X5lK{hZN2t݅Qʾ#qcDm&jf&Rk.D[&;dIN~'6v[Yd,{,hS .؏8Lf^vHN}痪|82,C<#e<>x){`UEdv豆s;$- ׄi){40:&́ןSipg:>:J?E.X}Gc24Ʋ=IتH'<]m^=h2,(.V ˸j?&m}5\拓x;9܈Ӧ㗓Sr`9 |;i_~K'xDdV20z`ԚKyާIڲ !%ɉB'd- SH+2J!PH0M>UY pJݒX@#cSW7J,{ r# Z 'cJI)OcD<(=(]gXLu]>uo6~v. Fr&Agn(ʾv?f2xA qFC&{%hTC ifN{V`tF_k!Plorl8dn}ӉDL5!O69v`H ~g8a <(N9&eO.x/B,h  e<.{Cd/F9<-ɡ 6CJcF2EL~5';3^"- F獓G6^7;Bhjͧ\RDRiRB'8hE:KHAsxv'Pq:Q^1jآwAc8X[Lr~ `ؔ[elI=$h6& mticƤlÔ}E ?!r\"mXyDLX JQA8U17Y6j*@!K52'nIQQ+A112:NBњOds>Uc:~)9ꃨ%DC'U4X[v%i;Ű{,{ħLeL0+Hs.FCB\MN$Bxުe/1> ~%ҘU) uA@"(IDU4//OdkEy&mU({!Q)i9b(m"|cLq ?H#enCѲv 0DL0~@ЕP$Romd[PT*@WrK!PlZ1,4.2P'{KbrvQ<~l 7@rd'K8#'5aRrJAt޸LhӶ/r ?Nm5vF`pD<ȐcwU;&7QfEbziz;=C^}%sq&F=ƒcsL)T X'g)gkΖڱ]Ǻ džq,Ѩx"G闽 B}bpfCȩ7xIKAO߃Ǭ> ~8O1 'mHX#Enfُ))w0 FKȁX):cq"NHڲLH / p#y5.h̗Tugɶp7r*iʙwPfDRr$&T0S϶ 2c}ᇁY|;4h  $*qBP>tKR2d%/eQw0:+(ݟ5lOk@RX)n4i?JghLbhcFcAPVĂ0:6Y;Cdhv+>Zpr5:͙ nne_`TJ%ЫqB4^k4Zek¯ 3}H&:-|I nZ'!捾'6eo?n *Ne[pSP.8%O޴6dMx}pNg~M7lA'~.>I %^eNFb}7?>?g7h1D,)SD7\h,g%KU B`Mn+|F^U%?)eo8pJXeRje[DN9 b7 cN=ǖS 8D~FYl$ssG`9ټ>?8xFAXSH!ƯI: ?8<ŧyC;ME*m|0({K!/Wz$u"A0Bq AbJO864p)RT^ B`#V:{ 5yCvهIg/=}EJX'*W$)401m:}6yK{Pk8Cml@eʔ=s ?l F`PwpR)C=Q]GMpƠHRŹ:8i A"+i{0US(;z8|H.E| (ԍ :ʾ m\e/#r6 7tG2`FB٦gTv9?tc\dyl7/641['qJ/LG4>_9ʾ_]_I`O<#D8tD^>1ōJڙ#vBXp9xBdlNs}Sqw氙ʦ?FrqnT6=Vղ6SxK)촗 &Yg9@V\k6NƇd5;jE=c |Ǖ1Lʌ7^+)^p4&%0D>VCY-g>tu=E:i/hd ÃH>;'Qc61.sX6'8j`m3J1&"]4F8*eDzS%g K#M̘Se` ?sl;w{m኱qɠ6 :*2-o2`5N9S&Y~P}ӵ+^wLu*vWZ& eo(gQI0(N)k IɌ_V80!? H\.~yl''61&u>e/+~xa! F9ϣD)Q pt&Ѯ׈$r6Ͳ63SBXt2>NUɷW,,i|/hl 7NK[#Qp /%//d'6/.:ʾaȶ+X/n_ \'m:+^&'~H`k&Y3`Ejh1J;EThǺDZ2'B < 08[4>e": C]sK =oK3|qC:ʾC\ a-fľN%pƐ䰀КKn @e_ J?dTK0 )H@p1  Vı ?3,nr#ьM@QtbDO,Le߱TMƿv0UU B`m^"揓ol+e"q}wG=-FXE@>IR9Ʃ] 4Um<m|[(G)LxG| s@P@o6P&tJ1ڢ.{0u wk":D*@!&L :. lҟ:_*ul 7'`q"@Ay/~9>bks$Hԛ+?Fqt.)vCyXE!QuI`Kb$p1;HWބhe J0r5eԨBiRWLz} jLx$Gʲ'GV},/:o \Q0ɨ,o)9:t2˘ QNɚ%5Gpo'ʾt}#ğؐ36jvt=b5I,td&td&td&n Gi!z"SQ L0~[ZAA\PZBh9R\>R FFlBN|J.HvdZ3B 0&"ϥmqqW oOfG"W ن"ZZ]C"=:\v0:?GPvc"䗱/o=V/@!`qgssevNwNVa5'Iu~Zn r9''ķad*U}|U:XѪ H=f_ȉ?ǺDu+F_]#lF%d=bk}{">;#hs-@(eO ?z VU B`m`Ii=8ޮ ?XeDN=4>'~)rt,_,|V f‚sᗍSq#H%"=bZϩoŸv$O%ҽӬ"%<8~){ϸN1ˉϽ1%e]ONyK3p]en@7͹d{Mg$5 Y_-p`$7 ;?s^`̩-Hg7g){ ;yƩ+%Җ0֑̏IC(s^ސ4S^"}؇.v>W&=u]"qBX`&1k IG.xc ,{ ?;55TN~e_EIɩa-!9lɨ?tdS;ɨ?tdS;ɨ?tdS;ɨ?tdS;FYm߷7`VKiWN7;x*{1!'x$Ģp=WlQg󕼗H7W;h :i?ʩ#Y_wYlɢMlɢMlOu+Cd. m!`<8N ?'c2D@H5[e9qjYr˖ ye>sq'99߇|o]?$'3~8xc&茫emI~ s&?8#0N Sd6kHe_*T@!`1.,[4Qf%:rHW6l 7M&Cbd^S% ?b]@7TV`R#_Q;(5eelj F+X%FmP4}Yz>Q1p*4+6o%h]HD6O:$˼v,]K'~eǃ?xL|k:xeLŭJ7p 4y;縛;Җ]dR U) 5A`.cIH^˘ v@; :yeri8L>N=|CKɩ&oX?l}Ǻ(JY!kT_ Laڒ=i% Fhg(9*bb mZ[idF R 3#}~^6B$8쨌ltmrGri?Mr#T/&$hexZhEb{;Sɚ&ysĢe\eKs#"88.7Ƨݲ/;-aqSw0z_bR̦}6֢ ETGӉSE)7~_^`{ν{{g{Z ^{>mYtJ@@2AJ~ȊWd_n7<%(4eEG?ЫB״/۞V"$?M5f_4T ~f0¦ hMm kF"(?ӏQuFSgX:Ø)[¯g|W/% P *^ٓ?d"_~E:_t9gƮ0*t$JCyFqnІNAg  "M:eΓ{Wd*wSDu$X4ueZcG]êlMxp"3QcΠ:iyN #s/фg0~_$L2/l"{8"@, v\ސv Y)wJXYв{%ǯHS&H^ǽlS)D::ϣ-pFIdW_\MDmlY)2oos/s`_QPWUTDOS8FD#8L~&yIRYg)n3C t 78=t*<:]0u$U=Ƥ◛NTWmC, [CDhzpB!ИVʪuiqbURDևAY:Cc D_X5iu lNkc1SNb<ϠS^6-WY }dpR s/[ˆuD׼-+:e&lv3 U!i$h*L&SG[WfX*:ں ֕Jd2uue+0Lm]a$hmY~)ic16}>mo`J}k'~" ESS2Y>vt?#g 䈆DKCL_!Eԉu!?RN??Py9mNA?B]ATtj3T ,~04E;ZAKJz^ғHކv1CXC@!Q;{\*(&41"L~I<`7Wrv0Vt#jtӤ֧iXX\iitZ44V:-|k}+k>>N5ZJOcOcr֧ͧeS2J>0E'|R̀#_jNXPOӾ+i=X(n_F .g4K~IQdOU mb DoK]HWöHPMё6\\] Iڞڲ +6]G[Wfyltm]:ں2cuueǦh,M֕YNiթx V4eIpiU4V:_n:.8~tkZuHg t$I_: OV-f% {P&*q$)-K?: c0vrcFgL=Z{Sߖo?3rAgwA)EB9%EGw Rҭ< Җ.ՑW/?r)u0:uV04/0NNrPs:GL 8qvq0vGmk iJA/'|Gˀ#x\ jʃ*? D pM N"og^STy G{81_!?9CSv i/Gd 8~F!`^P&F1OKs/gWO:Uli? @C)?t0Q aLF`F`oKmӖNbѱTzĪVm8!Xi-Wrt@|RzL%iT|N(zT̠(O:8> [=Pt;g(!\M`L7<ͣ4.}mLh?aB*|1{*?`<" ` D_Й!^8:ccW"]bn&BFIB4 <ɟ~(IyUueZ֥yg_n:5 >$r(k_P)b 58EHt0bF 1/WhZN/_"?t0h(V'פNmhGSU;{lbSuz:htVϔ#r)zPZ8 u@|Xh3~.Ƴ"?Q@_i~l'_š;e`3{GbS1/܍X{Ѵﵪ }6%٥'!6*;xD%wH&NH)jW΅y۰C }6g!b2+8 Φɟ/~9fkR8т"NyPL# W6/.*^7eǦi^W`(+ ~:K3Sk~~p#tOjjc"@*R&c)][ <6M?GgHЩr6oaϲ"Ut7앫"A:EuRw`N4T&h[,VuXltm]:ں2cӖ6K#h gMi键)oyl>-<65-M7ѧǦS&tJה<6D`L`zi :M#Mޟ+# (~t06I"@.X\"ho }E[9B ?3U4N5iG( rT㗫N#LA٭n85:e`aJ[mj[78g^㔞OdF OٶUB^lm,)ʼզ_=L\"W0uNRϢj)u`@IDATFmVw0C-聆-ز>V+~9:gx (EGgʽ*.Z,טOd3` " {[!qZJ/co"M,C~AE!u (:%$,!FuQ卵#~32WQH.$'"~^>rө$yO};4&:) Q[iD_#vtboފ蔈*LtTG@':!~/^u1"cM33lySaAGsSs)'? ~@r}p:a't <iy F:iZ y0t b(YA/7W\IL9?{xP2T~rR H,D8_f,V*it00"'̰~ej$pX`ϋCU~Ɵ*$R:\tJzc!~SڐVFmOMS. įh]v3" QGT9XJqSY#:7g0[DOC6F4 egZ2p铟eR"g0@@ H{LPYX'#OBܖAtBc_.t*+N@)+~9 t!-IDeNS\r/*XabϏ` F;K:'Xc+\X$ڔ2 HpX`1@p0J-0?51?*.5)M F(!"Wvm}M h7^P?Jd`YQa(TExe*Ocr/7 FKkʵ=.5" md_Z(}@VPQۤ1HO8F q;S;;YᗥQڄ^cHha ABb◧NLRxɳBUd"4%#!~}LNÊ &W`>/Giyc𿜼gtx,#dc+R~^-`Ė tx }x^r]:Yy}lK㗫0ߋSЭ $N6<-@Qp:À 6.4f(4m$'~^\ mtIy;'~& dS IQ֮Ss:E~E)1Mw:JIUiA ?d`T{@4HKA\ZF~oJpi2`iSԼ6(^Z{5ïH:fkI;DeǗA%J;W|g脯:%z'㭙 !x2h~i(ty~[#?ZM*Ft߸Wn/K{}GuAOJIq.r&~g Dol+5L7ty00 < ܴVEܜ!xP[c:R`i+'~V~rv{0Z=>@7TG|lJ痧u;k (bF J J:檫 ~օÏFg<6M~깫v:e!:GhZ5|k=^ *DSsȧi$!?K'7%qVIi/Uy''_I~ގ;{Rf2Iߗ6 A_1%**ڣZ(7҇yLÏy}_Ή #!N/tRm :%&d/J@H~\V i]i*(4ZSX'vw#&͠NhMLL$餾6G[qZ{,:K v¿VCi۩c > @A;Cꮶ Ĵ%zb}U30)sa6>i?6bcشw-MwzcZ-<6ݍO-Mk}t7><6]uκV[NǦrc)]St}Znyl:k[nO-MtMycMiiKNA18-D5?(n_ё\I鄬TΤtBF~Mt0&, c鶸-5!:=)}ctZjWrM/:gn #.]‰l %+ R$?lN#ûlՑT :]#?3NaOXxkU1]Tߛ?oTfrv06XάZj!UX'`/ `wjζqʴ~M ġ#2E:&'b##lm)^uP4zm:'`OG=VlZʴi+:/~\frq gGVjOcc<6#cՕib[oJSWuO#, }H [͵Q4O~Ak+鶸QĢN_ʲ0+ZV @eUڢV"_18`SaV6lsN㲎L?tj-oZo1ECZy__LcEeiL~#sVO9|EZ[6hƠI4O$s埬Ta_݃t*>i;HR[s.!Ѐ6*XR ?ꏧ  Y hgv*Sjsj@&.DYo@֓?orө^/B6R=W5OKgfQrO@M#`P^t B-O a Do3+LWL[^)#Ɖ_E&63wuJꎤkG4&U3f6jj+'ѨOn:(lSX.eįhPL@^rsأs[: u嶬Nϔr[F ũ Fmee1@p0NcR,Xԑ_0( ~ $u*>[}c6C62*̫M9O'tAq~0BHubze!? ~) 2UTt:UԁP6?r)`LwVFƦ-]S9hlMD A/g>m2?BAq)(D(U3zgx:KL0!:<#T| AMQ]g Qu?FD@dquׁ 04d_:UYC3tFy O{}v'3Vfyѡ1lTaCc3ӊ8grt0,KNU{_Py K%k54z^kykZy<^c׼ZZk^c-OcX5kXX5zkFaLF ζ"J8DpzH miB~6gy?Ieѽ`m:/.O^R =pʌ)Ij}#? XMW%BT  eG'7={0*29v :ˊv7M`"c' >+gO8˘3|~Fy)ez{Ʈ0fҀ݄#tkn` zdd"(LPIv=")ytF~V06LpP=J1Iy!/ ۬`]"mtai) Mbhɏ`>|V4 ~'@@ жX>-,pc)V̑l?3LQK舣R%R="hCѦaUW ~9C xu4 cFFyl@SXAx c# `1/G[TwI_y [ o,힩<6mHB[qĚDAgHjHBxC$ ɗ9<"VcI ]1tcH)8 :bN;Q:E~W'?);Bмh9)ˤA)}'?{U 'R1ԟ Z:bu T'~LLƝr)>D:Ç[o zDk8PbTO{0~xNUSd],$ hd@I&ԉ/z@i/MIJ{pb*t~4 mȈ@_*GrOJGuc!F$ۣ:ci5yo?`_ "0=.QZ:FR7c|\"-Cɡ:NE (w?Co2, +h_n aF guZRR@l:AJ~WIMtAא@ ~`t׉Rvx:E~uiC Ǝ+6:u$81)u.Zt#t¨S]?㗳NsSG>cĩ@S $KR 㗛Ny>zQ}3M>( 4`*ؔX_n3!3`FiV}A _i _XLNCʧyԓN~{bMi"@qH1 ~rNUhΨӤs C3J͵_:US{~uue'~"~s`siQ[W @g_n3!3lypxmPuBuKc!OgnqhZ}_0@~(MZak [;FNUeNUX8G| ~A.rS&fN%v(Eyi})68TL y|_aE.lƕnᅡQ-NY_dVpiwmk쟷(P*LP7 hW>Xe^-CXG@!e~Q @|weapjL $]e;)lFMVPiR:L(=q98CD~WM^  Z&иlOxDp0$F?'` c W$ыn4BXG~tS]rN :<T\l#!ncLSu2T4Et&c*_x_n:~t6MnK*il~o]M-eDH^Ij>L pa DOzJ9kW_ Brm F48 Csg2/:ml,&R VΊighLI퀝maƹʄuUu(!@MQ~rUn'ϒ ?x c&[ x`B#XitҐ[>WHB;Q#ilSi7wmj:g=l*SeI _jS:+f2jY.Zi 3KrfcZF~:yKi#AtPt/CƸuT>K`h0M)77v(=E4ukW*:BJC؆fyS&2hSdC3?inGfȟ ~T'X&" Ѭʴ Cڰ/%v@>8LTT]4dDL~HͰ:4 cu[T0y_+*,&9(C8ۊ:6a4ļuJVonvV ؊*g"ZLO &UMH++Ro}<`#`򣉑@D`\n3KcPlP i&KA]"贇^i FE1&; dTvyMT:U=ۄ޷ԩux vKnv:-5Wrө!2taN dA~Qv$ی`ܻkqPoQO;RMIÐ8lb~\"T0"0FPgTaZyX5&p8*iiV/ƴS|5f,:O?V.&LNSek2&'_n:w +}p>8yp1TưsOimAB֗tU:8U1*?`4ex^}UO?}O/;fi&w9t<.οӒK.8W圅놅T4;ǖSS7X4{͟ Qkkc[nӴkJ<6c-}tM锇:U"b1R[֔+#ͨê_Mt$,f !?@f8"28VDY㗛>:; yҴ0,@ M_5p"Qʥ^~on޹gJ+~{kڭZgtJcp_=>?W;(H높'9( ^) cG:J4:ԉٜH՗XS#I=jKOTMR];GGSZ5On=AKe]^ԑ:y #[o^]wuo;餓ܔSNّr袋NKeiG0ָizѤNlz&P|Qz'Sv/<6]O^jylt=u{MFYǡ"dlM4ŝck8Ycr0g kuJ -A@(0?:`DE^oW\QiVT-oTwi'w 'TʆܦnIgew=4n9pƍsЇܿonMIyKl:9 N {R7i)`TB I`顆J;jMNURSK|M_._Tl>ҀI21XǦ#=s/7}N{Uu$6bվra@IZu!?+'GWK-cqu׍w N;-rszy<inf+|vH~<5N X7C>"2t0r'~ATAl1GENX`Js)""()'N0r)Jd2UJeȐj* V r'<5?$! 2g@Oį^~`T1 4ݽqfswq[h*׿/Qٌ[n;+4|tgq? 7V]u^~ *41wq,θQ>=%_!'7n:Um?&H61O-Ts bMv~MTMh O^!vaUW֟O'pګ#yˣ 5S:X4rWqGrtWtTBĖ2=pK,D/,}ƌ~/Sux603{}As724ï(+ zPJ<𣃑Nԝx~п/7|itMW^y0LC.{[n%.b-9#6ϲI0? urȾbu |X=^ iʚjcz eǖ/ƃMT%Ǧ &vM)Saϸ(J1a䧣LôӃ_n:!^AuK:]RM"uTBe OYHcS;1P_f",o7|<_F8#^{HV nc9ƳcuYǧe]$*0_4\6xc-X!);yVMc,7(C  8 d_Mȼ^L:6:Ueje`dsөN6ڿ~XBP!)MKe_YWz sm?b4_3;.w袋F:ꨎrX=cns=fiataꩧv?яꫯYdꫯ:ո뮻;GuSL1hM7opy7| Z `NUK>umBD`DꔷHNsi;M@㗛NMcn(d0>?, ~ԩbu Nfh1%ٷѐ|ڰd53Aǥ_nxGj~`4` rryqO=oq`=/nCqH ?}Sl믿~]8z_A{-䒱{LboB/]yo0PBWe8<_n3C )Am贩)h Loln:E%mԨ hh:U?}o1iex*iQc  3/|p;/to"hb49#},ތ:jZkb8q e2@ P(e2@t20ꎐ.' FAov+Н X]tϮo֪Pf0֘ueXUkElwv첋[hdǘ@ D"@ D&e8I8'M5Tw'<î7`w饗zu]]ve+uBG>##ݵWM k?ڂ%+[eUJ+䦟~z$ D"@ D"@@I$8'>O3i~Uk4n;;n#<2~SOume?~mZ6l[o=1&D"@ D"@x8񰞤gg>?kw~w] "8=Ўqs~w 3s5ei|cuW^y{饗byGhR~ D"@ D"@F#Ǯ8-׼ꪫn{"?ӜxnwlO+:9:|瀣QT}]w]wnx[nqo%q'|a*e"@ D"@ D>t0>c {8tӹW^yM>vO|p,HwKtr0bI:Tz=v^{a]wսˤu6"@ D"@ Dt0cw}[jEAFżMx?/Xz![5\wu˂ .X9f'b%N?}{_F3?я{ /?U D"@ D"@&t0N$i0 2s:LuY+'g?Y/v}n&#kk;3ك6vaq-nr0.B?p c,Ə~ޡx7'|21F D"@ D"@9t0ұ}@{/}뾊X}QG&l7T`|7?ʲ G}q13f]r%{;2"@ D"@ DL|`O37r!sΉˡ]vY^{u]WcY5c#x'A엸6t=gNJ3D"@ D"@ :'cLXO_|M>w aǻgy! D"@ D"@&=t0Ng+ D"@ D"@ }}xD"@ D"@ D`#@"@ D"@ D"зطN D"@ D"@&=t0Ng+ D"@ D"@ }}xD"@ D"@ D`#@"@ D"@@Z-7deqI"@@N#pǺK/_y{|yo7쳻38#^?k/r)_ 9"}tA`8Gϻ}k#:@`v=?nVXaxZm֭Z "0z /t>{g_uU}y?W^ye뮻}>rknn݃+D>a'$"@7ْ}[1鷿m9眳r cJ2/rG/B[= ! ŨsΈoo5ֈ͈CF"01'?5e]6uQrx"0Iik _$ 9~G^OȡK:"Rĉh.=.xDL`t:weh0e$yn<)81 t0'75Sľ%ȯF|~:G E0f8OO:sOku~x^H蕃qmuqǍRC&?g=Ѯ'"\O~zw'ťt0 J t0ED\5`h D Ν~YHN:id3뮻2%4[>='>r?OJ:"З.KE[lї&ASY(A-V\qx[20 1ߏva!5o{~"cz}rv/t A&l['X8y"@st0`z=`uq'wF}:Ga_F~`'$c:,vv~i ^ɦCR=\M6dnvЇW/ٽE?{w<;ট~zwe7>C׳馛V_Ĭ? ٢.Yf'p,H۹:`++қmOwy?Xt"P[o*?AEΙg-bnM6qK.d/W_|E'oqE]_י<@u:K8YR 7x{|RK-yXFzl'A>Ѕn뱐x5׸'|ҳ}s|U[uUd6 +ˇ51# +vZO =m.7ly;_DQE xDL,I|vVb{7hx ߗgy ,SO?W2,Nq̓׿fuVo;Sa=oV?%0Nؿ4"h!P`;\s~hl; lZWAw^|Ҳ4X3X^N5Tn_ Ӏ 6[|Ž~lts"ч[ "DoH`"}vIw}{{g[ѬЧȋ%8b* Q2{?M`La~H`k2R[n88[A^NWx|86+e׿}:蜖X?=U_no yT@;EIDATP"0Fk,::蠶f2L34-8ɛ @_z/}K7Ya~؞Ecf&"[2㰫lC~ᰇ! XMU4"h"pG|~ ,4.F٧Rݑ9昣+ D`b"0Vj6m}`5\m|Vп"Zi ;:'$}.`Ts1mT+[K1C҆(3qr c-[VZ2ߞ )'8SNiaVt\rILoiVhd QϷV[d) L_Z+JgK,ʱBƏ_f@,lR(+ȴ,?kҰ,gnk`T=@KQvm֥^yFc_W-6GYq6h`z4%y%j-8/x㍖mi '>f?1^ڙgY}dyVd ,yФ/R#ND>BON0d-<ǣ:*^ X2t0@`,D"eo +4cg>J؎c!Վpn31:0i˵WYeJHzF_bD+b@ew iT:;-:,F'5 `NOג*dtmѢh"`x;'E]=*$r0 hٻSO=BWrQ@/yUN1S.X}c=H%pؐ:12~z߉]6`?t_8ER&8}ާK:E[4ȗ=+du /B s!qٗBuޏz:+pUƾz\X"0F^ f,ʦƽ:k<1)`ʿ,B`Og@ZB81?p[|pc9vvmG懂feb@'u0bYLFg4,Sv?H<FӣaV8?@Ka6 a]a{0b&f-;;a漵w򑘺C*_(WYlæ`ޢ3{υs >l}ׄZ6h`z4c$؄q*WAJ1f XPHZhˈ"0#~`8vn&GG/ֱ䢃)X9ޣV]O6ر-io-9Mk6V>u~lѢ_i:yjB:eb'5Xp5[7`)V,g,GΒ8}Q`<R0[,{>c;->u[Ygx{`<χ cƎб`;Ju lmdu K腃3z]*u:TX6^ӿW\тK)89_|}ݺ9tEc 4LDˈ˰v {465\DĖS[f{,I=Mؿ.XJϐw@&_mn'x6۴<\3B`|*sc-D,lCҋ:6X#fF68O;]~:OAQb<1rb;[Jeưk4}Wu0KFED`?C`'cņ` `;t06FalunF|X /S=ws0bc]Fl`lB`ǫ'`ַZ:95t5xX^vv?n￿z`c~C Z,Rp0b=_'#v v t0*'Q唋-Xos5\-E\\_/p@ +Cq0:1/1#_uqYgmDFhX1F,:9tv[ncm\`C%2:yּS"sz`|g[pCGrjwq{キלxƞ?Np #뮻F |Gh8]tx}|._`P01 @ 3bs]m6h`:g9R1>&?fHC[oHKx腃oٗX 'tR 2^}%&DT腃olsϭ`409z23O86 }{:9N_D4H0 @V?V.q,<%^X@qmzv}5^?HKc#L z`}H,z뭣+: @cpXE@gz`w u ˜:` tjafPP 3ǏoW^ye}'#f:kM)? ̌"ǣl< /Pot0F(nF|WmFmԈEJKc#T z`jt`þct0 M[q"SAC:F> M/ N X:bci+BKǧq$jǘg @/`ĬKS~q4،_ez]vN!:tԔSN:je'ki^jk*6N#8%C{nM>̢vi@c"\uFjl{/z衭NmJ`w/@_e{Z[lB?3 qeWw7$@6ҩs2m&o_o|íJZj!Nf\9D[fe828} ę|A'?'Rw:E#/KQG8t3=NASL:X #Rp'˸}/31K/$@G gq!Yieyחwވ&v}w'˓}|~<-ꫯ>y{u'Nr'p{챇翻K|ZKhqikɬL_.tqu\-WJ|1Ǹ{ǗmNzf@x衇tDfX9Y]9<88jVCvr-zoV_}uƏ̄t|Î!o8Y~Cq7V3&/JL`Gw_#DE?Jf; [y=9cYdvdTo@$_v'pOЏ /)ݩ_CfH{'/}s=bDX9*num<٢Ǐb%c:=AO#= "x9feQk?h tLL Ǐ)bTOϻ^z7|}PE ![o~>ifnOI8TSM5j':'CvmNrկܫ)gqF 5Xb,pz5\o[`6lj+׋N믿N^CFx w 'ЩE]}u.V8FSOugy{Gs9[{};O~r'(! 3t  Z hIO3{キ xNq Tlt?1ġPs@ui5D#p7F9'xPG_W}e㎛s%3}k]s5|.nb؋öCkQ/~ߴՏ#\˃l%_Zr]'{%/{'LlA/odJOs1|ܣ>ԝey!p 7D9rݔ܈-k!>Ӓ#>M@AG|dE =GSN5 p@_u*1ޚi"^:׼2S%oGtL :e]6ie^:R9u!_YV'oG 6u7lP/D@@hlڊ|zWƳ:r\]MV0^ ㏷dV_^XYyLH|ƹ{.o摞OixhNʂ,D+#u06}cmz[ -P "s =XdEڎb8\0itqtpQ@፰t1IG\TXn" hwyX?}?O[*C^tr?:g?HZ=Bz~ YidȖ,9H<I-K[K-TR/p[8:GuTK8_A"=܈@_m*o%KadTn/K,ĈC&"+]w݊B>{@"-m #^YlтhM7n+xdM*[dGv3𳒴͇#$d9r<+re6.fXY!7Ow^|(udd)>pZ~&m<A|yѰ ?dV>^8eoX0(oe:eX׎ {=V U~'x{{X7;C .}m03tx@&,/~%{/R⍲Fӭ`v ?~!f:m1CIYH F+؉R9ú$8 ӟt,zL(;!+iu$]!"8~ƿ{mnal|S0ym|(r {<9qʃ[(J+w";c#?,Le*Y*z_#;So~ob͸u=3B]btv9~o'M.q/h#)J6!5F1^v +|ȓxQ0sЮ,%,WkzdyҴ:dKc/<1q$+Mq#&]0S\10YaţtYv2pe6؞ +Ț t0 c~4NoʬuASX9Y XOh$mYtA؏ni LIJC9vn25;?:ymvED~_bۊ4!%lv0XuAfGO[js`c:i=^x5w}'[oDG,VXc]z,_+R?z-TV13p[|I=>ꯝ8C?HWNur'?IEN$} u+Xg[mg*)vaƱ :'31WکNF.-l!`fFS#-x&dCo{J\r=L[ھ-[uU;HYXSSqxúF 酃l;FʨTģupFy7m7vTz"]VV)O6k/vXw}ؓDŽ:=uZwn}+_΃!_v( wzd8Þ@?ts?v|_KGweHt`V^pw zS>ڦ'ad2N窫3@z].l7JڝN+f @:0k{ذm,93 fm0?^ww߽r"bW'u\uUi"赃Ga?Nsύ dFX)p s=cY1+̦h {W+)Wu`1[mnb}#p-D.tI7=T_կz uݖ"c=-wWV|Y_ 8<"δ` i$t0|x(ȸ]lQ]z'jۏZs5[7^x ]<2m⁓Iqfv ?peo߉R/u#΀,}Ӟᕓ038Dlg 6kиdv}#ctۯ:&0`auZ6'olt; tt, .v0Y)Nw2j*#td{+ʁGθ¾t{xqdgζڧg9猲JK hbVWpGCX߿3`'$ߢt>)/X8xҺtv"5-nub|^9xB \N>H-?D3<3cեĖRu/;2YX_=t^tE6C,9t0R? Kፔ6'j8l,6|־]h'h}jcuעe`OV3H赃NueW50^(!^^c>NsCσ, GE mpe6q6YfBz70 pVMǼ~}_r`R~N9+DZ4\g:[b=f֪6}(oW4 g}b1nKx1<Xb wV0>׉x(`,Aa#@"0Hfկ*׈yC v[n vPՉn4fz6*tN_V^;s3*@@vJ1#m$ظ[;ug#@|hH:Q'~}k_kp( VF/T7#) 8`#N_l]R\M̢.e4`T+KCLm9O)lϟJkILcO`胤_LNds,v8,-hLNp뮻NI&8Ƌ'lG{ Cc(0_yp :'31mkD'Lst.|r7|ʏ7Ol u0s 8`n0jYj~5n(36=gF^;rZdE**:/!yꩧV΁ft 9@:!IlbI}J/0QLm_~s0hWȓk!o ЧQyAl8X&i 'KCM4mHq*^%}׺K[kF:gX#`)rC.>di? N|̂lSN9ŲVҘ(AR? ^Ba=6Ұ5qk([3<'o'}o78(D`38LV[m^[kctѩo`| @J0ƺk\i>l硇ΉVpySw, &`UmQFAˆV<pvWA"@: N 7tS[ҭa^87͊7N;i(KKZ` gqF!`~"(j \rXw@mt.|L>f?T:ŭ^3M7VOP / 70RK-UeY&ޕf<>!w>Zo߮**4S20HT WeQhbHAb$Q-Bv!)B"WBE|<=z{Ϝs̜ygΙy瑣tې]AǔD: 8wܘbH3cg !T ͧ 2j͒Ƿ~zeS9> nLh NC5Oݏ?'aYfw5Yn]=`SrΝWޮ.j+|iPLxt毿ʓ9իZ߷o_]ӭV}_]x: kY-h;m'/Q3Y&ѣGWr8+_r7y[V}!wG66PYZ=U}ߦ@gNu䳸F۸yfuC6# rS/b"mߘERL̅MnDZ) ?k0N%9A#gܛl\˛fc lyZmW^=ob {޽{!>l\۶m+zc!;Ќэ!0Kc她fjFd e>웬}ȋ%wOgJ4(s/]vȦ_fƨ}eis3OkI]_y[ i+V53n_ǘt.Em=-Z7GyQ}TyA7/C.~}G16Uԗ*ImOX ܳL1}Ń޻EhzK/p^d/PIE[mCKO>GMPF%`{%#`DF@JA!*]vmr̙믿'{^4K2SM9 {&$dnbNΌƙ%c,}L_ɯ.\_zwٯjxJ U\r`_L -dدՠWZ\]AڑVh#0mD{J,4kB4ȁgʊ9Q&@`,q{ɞ={z=z~Ҷ(`נ/t)Ǵ55|Gg_tjeN@q7mA6}/w[J!}ZuU_Zy3qZ$|4.!L" mNjKXy6Rt"QKR}S9giYKgb>TҬJqLB>3цXt j/hisܾ}{cᆱ@$P*``uOB>NwC[X^Vri zo[y6c Ȇ3 ֢Fo669N8QۧG(|/M<] X`tB99$ >|oPxoJA餩z/5uԯƹ=V_e˺sNWVs#`= GlSZ9I /V-K$@{ʕ+tQ\v=i1ݓ)/OvƑDҎ,QϛyB,q`/{m4T&~4ZMca!:y饗xQV=CСCLk\rggF6F4(Try?eETw4NYzA= qG#d;+`zQ04},q%o }Fә(TQ~r [iDI 7xcNQ H7*j(_ @}Ѧzxh\lS0$`u_}UNp^Fܗ]6v~ςLmz)5CA|>`!zmy96ҥKdV=C8?[S t?߿?z?F.G:|GLl":l?ұc$վ6[}{M#]O=Tufqwl"m`MzF3SE>d+P$}<8c({Aff d&oRȐlI-n˖L'3#Pk48ăڀ٧ݢW{?'[:8ȴ1yq6p}JW^y'ilH `~Gh@gY*)lH@2RGؖVeYEH7nܨ:xy3"ev9Iydc.%  0o Y]{M蚶R2IBY@&U|s1 kRX[b2qҊ+qҘI@X @ @@$1 @ @ @X @ @@$1 @ @ @X @ @@$1 @ @ @X @ @@$1 @ @ @X @ @@$1 @ @ @X @ @@$1 @ @ @X @ @@$1 @ @ @X @ @@$1 @ @ @X @ @@$1 @ @ @X @ @@$1 @ @ @X @ @@$1 @ @ @X @ @@$1 @ @ ?IKIENDB`hamlit-2.15.1/benchmark/id_attribute.haml000066400000000000000000000001101407657076200203400ustar00rootroot00000000000000#book{ id: 'content active' } - id = %w[content active] #book{ id: id } hamlit-2.15.1/benchmark/plain.haml000066400000000000000000000000761407657076200167770ustar00rootroot00000000000000- hello = 'world' %span aaa#{hello}bbb %span aaa#{hello}bbb hamlit-2.15.1/benchmark/script.haml000066400000000000000000000001421407657076200171720ustar00rootroot00000000000000- dynamic = 'dynamic' = "#{ dynamic } script" = "#{ 'static'} script" = ['&', '"', "'", '<', '>'] hamlit-2.15.1/benchmark/slim/000077500000000000000000000000001407657076200157725ustar00rootroot00000000000000hamlit-2.15.1/benchmark/slim/LICENSE000066400000000000000000000020651407657076200170020ustar00rootroot00000000000000The MIT License Copyright (c) 2010 - 2015 Slim Team 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. hamlit-2.15.1/benchmark/slim/context.rb000066400000000000000000000003551407657076200200060ustar00rootroot00000000000000class Context def header 'Colors' end def item [ { name: 'red', current: true, url: '#red' }, { name: 'green', current: false, url: '#green' }, { name: 'blue', current: false, url: '#blue' } ] end end hamlit-2.15.1/benchmark/slim/run-benchmarks.rb000066400000000000000000000060111407657076200212340ustar00rootroot00000000000000#!/usr/bin/env ruby =begin The MIT License Copyright (c) 2010 - 2015 Slim Team 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. =end # # Original: https://github.com/slim-template/slim/blob/v3.0.6/benchmarks/run-benchmarks.rb # # SlimBenchmarks with following modifications: # 1. Skipping slow engines, tilt and parsing benches. # 2. All Ruby script and attributes are escaped for fairness. # 3. Faml and Hamlit are added. # $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'), File.dirname(__FILE__)) require 'slim' require 'context' require 'benchmark/ips' require 'tilt' require 'erubi' require 'erb' require 'haml' require 'faml' require 'hamlit' class SlimBenchmarks def initialize(only_haml) @only_haml = only_haml @benches = [] @erb_code = File.read(File.dirname(__FILE__) + '/view.erb') @haml_code = File.read(File.dirname(__FILE__) + '/view.haml') @slim_code = File.read(File.dirname(__FILE__) + '/view.slim') init_compiled_benches end def init_compiled_benches context = Context.new haml_ugly = Haml::Engine.new(@haml_code, format: :html5, escape_html: true) haml_ugly.def_method(context, :run_haml_ugly) context.instance_eval %{ def run_erubi; #{Erubi::Engine.new(@erb_code).src}; end def run_slim_ugly; #{Slim::Engine.new.call @slim_code}; end def run_faml; #{Faml::Engine.new.call @haml_code}; end def run_hamlit; #{Hamlit::Engine.new.call @haml_code}; end } bench("erubi v#{Erubi::VERSION}") { context.run_erubi } unless @only_haml bench("slim v#{Slim::VERSION}") { context.run_slim_ugly } unless @only_haml bench("haml v#{Haml::VERSION}") { context.run_haml_ugly } bench("faml v#{Faml::VERSION}") { context.run_faml } bench("hamlit v#{Hamlit::VERSION}") { context.run_hamlit } end def run Benchmark.ips do |x| @benches.each do |name, block| x.report(name.to_s, &block) end x.compare! end end def bench(name, &block) @benches.push([name, block]) end end SlimBenchmarks.new(ENV['ONLY_HAML'] == '1').run hamlit-2.15.1/benchmark/slim/view.erb000066400000000000000000000007321407657076200174400ustar00rootroot00000000000000 Simple Benchmark

<%== header %>

<% unless item.empty? %>
<% else %>

The list is empty.

<% end %> hamlit-2.15.1/benchmark/slim/view.haml000066400000000000000000000005071407657076200176110ustar00rootroot00000000000000!!! html %html %head %title Simple Benchmark %body %h1= header - unless item.empty? %ul - for i in item - if i[:current] %li %strong= i[:name] - else %li %a{:href => i[:url]}= i[:name] - else %p The list is empty. hamlit-2.15.1/benchmark/slim/view.slim000066400000000000000000000004751407657076200176400ustar00rootroot00000000000000doctype html html head title Simple Benchmark body h1 = header - unless item.empty? ul - for i in item - if i[:current] li strong = i[:name] - else li a href=i[:url] = i[:name] - else p The list is empty. hamlit-2.15.1/benchmark/utils/000077500000000000000000000000001407657076200161665ustar00rootroot00000000000000hamlit-2.15.1/benchmark/utils/benchmark_ips_extension.rb000066400000000000000000000022001407657076200234060ustar00rootroot00000000000000# Monkey patch to show milliseconds module Benchmark module IPS class Report module EntryExtension def body return super if Benchmark::IPS.options[:format] != :human left = "%s i/s (%1.3fms)" % [Helpers.scale(ips), (1000.0 / ips)] iters = Helpers.scale(@iterations) if @show_total_time left.ljust(20) + (" - %s in %10.6fs" % [iters, runtime]) else left.ljust(20) + (" - %s" % iters) end end end Entry.prepend(EntryExtension) end end module CompareExtension def compare(*reports) return if reports.size < 2 sorted = reports.sort_by(&:ips).reverse best = sorted.shift $stdout.puts "\nComparison:" $stdout.printf "%20s: %10.1f i/s (%1.3fms)\n", best.label, best.ips, (1000.0 / best.ips) sorted.each do |report| name = report.label.to_s x = (best.ips.to_f / report.ips.to_f) $stdout.printf "%20s: %10.1f i/s (%1.3fms) - %.2fx slower\n", name, report.ips, (1000.0 / report.ips), x end $stdout.puts end end extend CompareExtension end hamlit-2.15.1/bin/000077500000000000000000000000001407657076200136445ustar00rootroot00000000000000hamlit-2.15.1/bin/bench000077500000000000000000000046351407657076200146610ustar00rootroot00000000000000#!/usr/bin/env ruby require 'bundler/setup' require 'hamlit' require 'faml' require 'thor' require 'benchmark/ips' require_relative '../benchmark/utils/benchmark_ips_extension' class Bench < Thor class_option :show_template, type: :boolean, aliases: ['-t'] desc 'bench HAML', 'Benchmark haml template' option :compile, type: :boolean, aliases: ['-c'] option :show_code, type: :boolean, aliases: ['-s'] def bench(*files) files.each { |file| render(file) } files.each { |file| compile(file) if options[:compile] } files.each { |file| code(file) if options[:show_code] } end desc 'compile HAML', 'Benchmark compilation' def compile(file) puts "#{?= * 49}\n Compilation: #{file}\n#{?= * 49}" haml = File.read(file) Benchmark.ips do |x| x.report("haml v#{Haml::VERSION}") { Haml::Engine.new(haml, escape_html: true, escape_attrs: true).precompiled } x.report("faml v#{Faml::VERSION}") { Faml::Engine.new.call(haml) } x.report("hamlit v#{Hamlit::VERSION}") { Hamlit::Engine.new.call(haml) } x.compare! end end desc 'render HAML', 'Benchmark rendering' def render(file) puts "#{?= * 49}\n Rendering: #{file}\n#{?= * 49}" haml = File.read(file) puts haml + "\n" if options[:show_template] object = Object.new ruby_file = file.gsub(/\.haml\z/, '.rb') if File.exist?(ruby_file) object.instance_eval(File.read(ruby_file)) end Haml::Engine.new(haml, escape_html: true, escape_attrs: true).def_method(object, :haml) object.instance_eval "def faml; #{Faml::Engine.new.call(haml)}; end" object.instance_eval "def hamlit; #{Hamlit::Engine.new.call(haml)}; end" Benchmark.ips do |x| x.report("haml v#{Haml::VERSION}") { object.haml } x.report("faml v#{Faml::VERSION}") { object.faml } x.report("hamlit v#{Hamlit::VERSION}") { object.hamlit } x.compare! end end desc 'code HAML', 'Show compiled code' def code(file) haml = File.read(file) puts "#{?= * 49}\n Haml Source: #{file}\n#{?= * 49}" puts Haml::Engine.new(haml, escape_html: true, escape_attrs: true).precompiled puts "\n#{?= * 49}\n Faml Source: #{file}\n#{?= * 49}" puts Faml::Engine.new.call(haml) puts "\n#{?= * 49}\n Hamlit Source: #{file}\n#{?= * 49}" puts Hamlit::Engine.new.call(haml) end private def method_missing(*args) return super if args.length > 1 render(args.first.to_s) end end Bench.start hamlit-2.15.1/bin/console000077500000000000000000000004561407657076200152410ustar00rootroot00000000000000#!/usr/bin/env ruby require 'bundler/setup' require 'hamlit' # You can add fixtures and/or initialization code here to make experimenting # with your gem easier. You can also use a different console, if you like. # (If you use this, don't forget to add pry to your Gemfile!) require 'pry' Pry.start hamlit-2.15.1/bin/ruby000077500000000000000000000000721407657076200145520ustar00rootroot00000000000000#!/bin/bash bundle exec ruby -Ilib:test -rtest_helper $@ hamlit-2.15.1/bin/setup000077500000000000000000000001631407657076200147320ustar00rootroot00000000000000#!/bin/bash set -euo pipefail IFS=$'\n\t' bundle install # Do any other automated setup that you need to do here hamlit-2.15.1/bin/stackprof000077500000000000000000000013011407657076200155610ustar00rootroot00000000000000#!/usr/bin/env ruby require 'bundler/setup' require 'hamlit' require 'stackprof' def open_flamegraph(report) temp = `mktemp /tmp/stackflame-XXXXXXXX`.strip data_path = "#{temp}.js" system("mv #{temp} #{data_path}") File.open(data_path, 'w') do |f| report.print_flamegraph(f) end viewer_path = File.join(`bundle show stackprof`.strip, 'lib/stackprof/flamegraph/viewer.html') url = "file://#{viewer_path}?data=#{data_path}" system(%Q[osascript -e 'open location "#{url}"']) end haml = File.read(ARGV.first) StackProf.start(mode: :wall, interval: 1, raw: false) Hamlit::Engine.new.call(haml) StackProf.stop report = StackProf::Report.new(StackProf.results) report.print_text(false) hamlit-2.15.1/bin/test000077500000000000000000000005051407657076200145510ustar00rootroot00000000000000#!/bin/bash VERSIONS=( 2.1.10 2.2.5 2.3.1 ) set -e trap 'echo "${VERSIONS[2]}" > .ruby-version' 0 function test_with() { version=$1 rbenv local $version if ! bundle check > /dev/null; then bundle install fi ruby -v bundle exec rake test } for version in ${VERSIONS[@]}; do test_with $version done hamlit-2.15.1/bin/update-haml000077500000000000000000000067421407657076200160040ustar00rootroot00000000000000#!/usr/bin/env ruby require 'fileutils' require 'tmpdir' HAML_REPO = 'haml/haml' HAML_VERSION = '5.2.1' module GitHubFetcher def self.fetch(repo, tag:, path:) Dir.mktmpdir do |dir| Dir.chdir(dir) do url = "https://github.com/#{repo}/archive/#{tag}.tar.gz" system("curl -L --fail --retry 3 --retry-delay 1 #{url} -o - | tar zxf -") FileUtils.mv("#{File.basename(repo)}-#{tag.sub(/\Av/, '')}", path) end end end end class LicenseBuilder DELIMITER = "\n===" def initialize(haml_license:, hamlit_license:) @haml_license = haml_license @hamlit_license = hamlit_license end def build license = [ File.read(@haml_license), File.read(@hamlit_license).split(DELIMITER, 2).last, ].join(DELIMITER) File.write(@hamlit_license, license) end end # Generate lib/hamlit/parser from haml class HamlitParserBuilder TARGET_FILES = [ 'attribute_builder.rb', 'buffer.rb', 'error.rb', 'helpers.rb', 'options.rb', 'temple_engine.rb', # TODO: make the upstream sharable first # 'parser.rb', 'util.rb', 'helpers/xss_mods.rb', ] # Classes which are just referenced by Options and not really used by the parser DUMMY_CLASSES = { 'compiler.rb' => 'Compiler', 'escapable.rb' => 'Escapable', 'generator.rb' => 'Generator', } def initialize(haml:, hamlit_parser:) @haml = haml @hamlit_parser = hamlit_parser end def build TARGET_FILES.each do |file| src_path = File.join(@haml, file) dest_path = File.join(@hamlit_parser, "haml_#{file}") FileUtils.mkdir_p(File.dirname(dest_path)) FileUtils.cp(src_path, dest_path) src = File.read(dest_path) patch_source!(src, file: file) File.write(dest_path, src) end DUMMY_CLASSES.each do |file, klass| dest_path = File.join(@hamlit_parser, "haml_#{file}") src = "class Hamlit::Haml#{klass}; end\n" File.write(dest_path, src) end end private def patch_source!(src, file:) # Use Hamlit::HamlFoo instead of Haml::Foo src.gsub!(/^module Haml\n((?: #[^\n]+\n)*) (module|class) ([^ ]+)/, "module Hamlit\n\\1 \\2 Haml\\3") src.gsub!(/\bHaml::/, 'Hamlit::Haml') # Prefix Haml to references without Haml:: src.gsub!(/\b(AttributeBuilder|Error|InvalidAttributeNameError|Options|Parser|SyntaxError)\./, 'Haml\0') src.gsub!(/\brescue SyntaxError /, 'rescue HamlSyntaxError ') # Hamlit should not rely on Haml src.gsub!(/^require 'haml\/([^']+)'/, "require 'hamlit/parser/haml_\\1'") case file when 'error.rb' src.gsub!(/^ class ([^ ]+) < ([^ ]+);/, ' class Haml\1 < Haml\2;') when 'helpers.rb' src.gsub!(/^ def is_haml\?\n false\n end/m) { |str| str.gsub(/^ /, ' # ') } # not needed for the parser when 'options.rb' src.gsub!(/\.is_a\?\(Options\)/, '.is_a?(HamlOptions)') when 'temple_engine.rb' src.gsub!(/\buse (Generator|Escapable)$/, 'use Haml\1') end end end FileUtils.rm_rf(haml = File.expand_path('../haml', __dir__)) GitHubFetcher.fetch(HAML_REPO, tag: HAML_VERSION, path: haml) hamlit = File.expand_path('..', __dir__) LicenseBuilder.new( haml_license: File.join(haml, 'MIT-LICENSE'), hamlit_license: File.join(hamlit, 'LICENSE.txt'), ).build hamlit_parser = File.join(hamlit, 'lib/hamlit/parser') # TODO: FileUtils.rm_rf(hamlit_parser = File.join(hamlit, 'lib/hamlit/parser')) HamlitParserBuilder.new( haml: File.join(haml, 'lib/haml'), hamlit_parser: hamlit_parser, ).build hamlit-2.15.1/exe/000077500000000000000000000000001407657076200136555ustar00rootroot00000000000000hamlit-2.15.1/exe/hamlit000077500000000000000000000001661407657076200150640ustar00rootroot00000000000000#!/usr/bin/env ruby $:.unshift File.expand_path('../../lib', __FILE__) require 'hamlit/cli' Hamlit::CLI.start(ARGV) hamlit-2.15.1/ext/000077500000000000000000000000001407657076200136745ustar00rootroot00000000000000hamlit-2.15.1/ext/hamlit/000077500000000000000000000000001407657076200151525ustar00rootroot00000000000000hamlit-2.15.1/ext/hamlit/extconf.rb000066400000000000000000000001641407657076200171460ustar00rootroot00000000000000require 'mkmf' $CFLAGS << ' -Wall -Wextra' $srcs = %w[ hamlit.c hescape.c ] create_makefile('hamlit/hamlit') hamlit-2.15.1/ext/hamlit/hamlit.c000066400000000000000000000325771407657076200166120ustar00rootroot00000000000000#include #include #ifndef TRUFFLERUBY #include "hescape.h" #include "string.h" VALUE mAttributeBuilder, mObjectRef; static ID id_flatten, id_keys, id_parse, id_prepend, id_tr, id_uniq_bang; static ID id_xhtml; static VALUE str_aria, str_data, str_equal, str_hyphen, str_space, str_underscore; static void delete_falsey_values(VALUE values) { VALUE value; long i; for (i = RARRAY_LEN(values) - 1; 0 <= i; i--) { value = rb_ary_entry(values, i); if (!RTEST(value)) { rb_ary_delete_at(values, i); } } } static int str_eq(VALUE str, const char *cstr, long n) { return RSTRING_LEN(str) == n && memcmp(RSTRING_PTR(str), cstr, n) == 0; } static VALUE to_s(VALUE value) { return rb_convert_type(value, T_STRING, "String", "to_s"); } static VALUE hyphenate(VALUE str) { long i; if (OBJ_FROZEN(str)) str = rb_str_dup(str); for (i = 0; i < RSTRING_LEN(str); i++) { if (RSTRING_PTR(str)[i] == '_') { rb_str_update(str, i, 1, str_hyphen); } } return str; } static VALUE escape_html(VALUE str) { char *buf; unsigned int size; Check_Type(str, T_STRING); size = hesc_escape_html(&buf, RSTRING_PTR(str), RSTRING_LEN(str)); if (size > RSTRING_LEN(str)) { str = rb_enc_str_new(buf, size, rb_utf8_encoding()); free((void *)buf); } return str; } static VALUE escape_attribute(VALUE escape_attrs, VALUE str) { if (RTEST(escape_attrs)) { return escape_html(str); } else { return str; } } static VALUE rb_escape_html(RB_UNUSED_VAR(VALUE self), VALUE value) { return escape_html(to_s(value)); } static VALUE hamlit_build_id(VALUE escape_attrs, VALUE values) { VALUE attr_value; values = rb_funcall(values, id_flatten, 0); delete_falsey_values(values); attr_value = rb_ary_join(values, str_underscore); return escape_attribute(escape_attrs, attr_value); } static VALUE hamlit_build_single_class(VALUE escape_attrs, VALUE value) { switch (TYPE(value)) { case T_STRING: break; case T_ARRAY: value = rb_funcall(value, id_flatten, 0); delete_falsey_values(value); value = rb_ary_join(value, str_space); break; default: if (RTEST(value)) { value = to_s(value); } else { return rb_str_new_cstr(""); } break; } return escape_attribute(escape_attrs, value); } static VALUE hamlit_build_multi_class(VALUE escape_attrs, VALUE values) { long i, j; VALUE value, buf; buf = rb_ary_new2(RARRAY_LEN(values)); for (i = 0; i < RARRAY_LEN(values); i++) { value = rb_ary_entry(values, i); switch (TYPE(value)) { case T_STRING: rb_ary_concat(buf, rb_str_split(value, " ")); break; case T_ARRAY: value = rb_funcall(value, id_flatten, 0); delete_falsey_values(value); for (j = 0; j < RARRAY_LEN(value); j++) { rb_ary_push(buf, to_s(rb_ary_entry(value, j))); } break; default: if (RTEST(value)) { rb_ary_push(buf, to_s(value)); } break; } } rb_funcall(buf, id_uniq_bang, 0); return escape_attribute(escape_attrs, rb_ary_join(buf, str_space)); } static VALUE hamlit_build_class(VALUE escape_attrs, VALUE array) { if (RARRAY_LEN(array) == 1) { return hamlit_build_single_class(escape_attrs, rb_ary_entry(array, 0)); } else { return hamlit_build_multi_class(escape_attrs, array); } } struct merge_data_attrs_var { VALUE merged; VALUE key_str; }; static int merge_data_attrs_i(VALUE key, VALUE value, VALUE ptr) { struct merge_data_attrs_var *arg = (struct merge_data_attrs_var *)ptr; VALUE merged = arg->merged; VALUE key_str = arg->key_str; if (NIL_P(key)) { rb_hash_aset(merged, key_str, value); } else { key = rb_str_concat(rb_str_concat(rb_str_dup(key_str), rb_str_new_cstr("-")), to_s(key)); rb_hash_aset(merged, key, value); } return ST_CONTINUE; } static VALUE merge_data_attrs(VALUE values, VALUE key_str) { long i; VALUE value, merged = rb_hash_new(); for (i = 0; i < RARRAY_LEN(values); i++) { struct merge_data_attrs_var arg; arg.merged = merged; arg.key_str = key_str; value = rb_ary_entry(values, i); switch (TYPE(value)) { case T_HASH: rb_hash_foreach(value, merge_data_attrs_i, (VALUE)&arg); break; default: rb_hash_aset(merged, key_str, value); break; } } return merged; } struct flatten_data_attrs_i2_arg { VALUE flattened; VALUE key; }; static int flatten_data_attrs_i2(VALUE k, VALUE v, VALUE ptr) { VALUE key; struct flatten_data_attrs_i2_arg *arg = (struct flatten_data_attrs_i2_arg *)ptr; if (!RTEST(v)) return ST_CONTINUE; if (k == Qnil) { rb_hash_aset(arg->flattened, arg->key, v); } else { key = rb_str_dup(arg->key); rb_str_cat(key, "-", 1); rb_str_concat(key, to_s(k)); rb_hash_aset(arg->flattened, key, v); } return ST_CONTINUE; } static VALUE flatten_data_attrs(VALUE attrs); static int flatten_data_attrs_i(VALUE key, VALUE value, VALUE flattened) { struct flatten_data_attrs_i2_arg arg; key = hyphenate(to_s(key)); switch (TYPE(value)) { case T_HASH: value = flatten_data_attrs(value); arg.key = key; arg.flattened = flattened; rb_hash_foreach(value, flatten_data_attrs_i2, (VALUE)(&arg)); break; default: if (RTEST(value)) rb_hash_aset(flattened, key, value); break; } return ST_CONTINUE; } static VALUE flatten_data_attrs(VALUE attrs) { VALUE flattened = rb_hash_new(); rb_hash_foreach(attrs, flatten_data_attrs_i, flattened); return flattened; } static VALUE hamlit_build_data(VALUE escape_attrs, VALUE quote, VALUE values, VALUE key_str) { long i; VALUE attrs, buf, keys, key, value; attrs = merge_data_attrs(values, key_str); attrs = flatten_data_attrs(attrs); keys = rb_ary_sort_bang(rb_funcall(attrs, id_keys, 0)); buf = rb_str_new("", 0); for (i = 0; i < RARRAY_LEN(keys); i++) { key = rb_ary_entry(keys, i); value = rb_hash_aref(attrs, key); switch (value) { case Qtrue: rb_str_concat(buf, str_space); rb_str_concat(buf, key); break; case Qnil: break; // noop case Qfalse: break; // noop default: rb_str_concat(buf, str_space); rb_str_concat(buf, key); rb_str_concat(buf, str_equal); rb_str_concat(buf, quote); rb_str_concat(buf, escape_attribute(escape_attrs, to_s(value))); rb_str_concat(buf, quote); break; } } return buf; } static VALUE parse_object_ref(VALUE object_ref) { return rb_funcall(mObjectRef, id_parse, 1, object_ref); } static int merge_all_attrs_i(VALUE key, VALUE value, VALUE merged) { VALUE array; key = to_s(key); if (str_eq(key, "id", 2) || str_eq(key, "class", 5) || str_eq(key, "data", 4) || str_eq(key, "aria", 4)) { array = rb_hash_aref(merged, key); if (NIL_P(array)) { array = rb_ary_new2(1); rb_hash_aset(merged, key, array); } rb_ary_push(array, value); } else { rb_hash_aset(merged, key, value); } return ST_CONTINUE; } static VALUE merge_all_attrs(VALUE hashes) { long i; VALUE hash, merged = rb_hash_new(); for (i = 0; i < RARRAY_LEN(hashes); i++) { hash = rb_ary_entry(hashes, i); if (!RB_TYPE_P(hash, T_HASH)) { rb_raise(rb_eArgError, "Non-hash object is given to attributes!"); } rb_hash_foreach(hash, merge_all_attrs_i, merged); } return merged; } int is_boolean_attribute(VALUE key, VALUE boolean_attributes) { if (str_eq(rb_str_substr(key, 0, 5), "data-", 5)) return 1; if (str_eq(rb_str_substr(key, 0, 5), "aria-", 5)) return 1; return RTEST(rb_ary_includes(boolean_attributes, key)); } void hamlit_build_for_id(VALUE escape_attrs, VALUE quote, VALUE buf, VALUE values) { rb_str_cat(buf, " id=", 4); rb_str_concat(buf, quote); rb_str_concat(buf, hamlit_build_id(escape_attrs, values)); rb_str_concat(buf, quote); } void hamlit_build_for_class(VALUE escape_attrs, VALUE quote, VALUE buf, VALUE values) { rb_str_cat(buf, " class=", 7); rb_str_concat(buf, quote); rb_str_concat(buf, hamlit_build_class(escape_attrs, values)); rb_str_concat(buf, quote); } void hamlit_build_for_data(VALUE escape_attrs, VALUE quote, VALUE buf, VALUE values) { rb_str_concat(buf, hamlit_build_data(escape_attrs, quote, values, str_data)); } void hamlit_build_for_aria(VALUE escape_attrs, VALUE quote, VALUE buf, VALUE values) { rb_str_concat(buf, hamlit_build_data(escape_attrs, quote, values, str_aria)); } void hamlit_build_for_others(VALUE escape_attrs, VALUE quote, VALUE buf, VALUE key, VALUE value) { rb_str_cat(buf, " ", 1); rb_str_concat(buf, key); rb_str_cat(buf, "=", 1); rb_str_concat(buf, quote); rb_str_concat(buf, escape_attribute(escape_attrs, to_s(value))); rb_str_concat(buf, quote); } void hamlit_build_for_boolean(VALUE escape_attrs, VALUE quote, VALUE format, VALUE buf, VALUE key, VALUE value) { switch (value) { case Qtrue: rb_str_cat(buf, " ", 1); rb_str_concat(buf, key); if ((TYPE(format) == T_SYMBOL || TYPE(format) == T_STRING) && rb_to_id(format) == id_xhtml) { rb_str_cat(buf, "=", 1); rb_str_concat(buf, quote); rb_str_concat(buf, key); rb_str_concat(buf, quote); } break; case Qfalse: break; // noop case Qnil: break; // noop default: hamlit_build_for_others(escape_attrs, quote, buf, key, value); break; } } static VALUE hamlit_build(VALUE escape_attrs, VALUE quote, VALUE format, VALUE boolean_attributes, VALUE object_ref, VALUE hashes) { long i; VALUE attrs, buf, key, keys, value; if (!NIL_P(object_ref)) rb_ary_push(hashes, parse_object_ref(object_ref)); attrs = merge_all_attrs(hashes); buf = rb_str_new("", 0); keys = rb_ary_sort_bang(rb_funcall(attrs, id_keys, 0)); for (i = 0; i < RARRAY_LEN(keys); i++) { key = rb_ary_entry(keys, i); value = rb_hash_aref(attrs, key); if (str_eq(key, "id", 2)) { hamlit_build_for_id(escape_attrs, quote, buf, value); } else if (str_eq(key, "class", 5)) { hamlit_build_for_class(escape_attrs, quote, buf, value); } else if (str_eq(key, "data", 4)) { hamlit_build_for_data(escape_attrs, quote, buf, value); } else if (str_eq(key, "aria", 4)) { hamlit_build_for_aria(escape_attrs, quote, buf, value); } else if (is_boolean_attribute(key, boolean_attributes)) { hamlit_build_for_boolean(escape_attrs, quote, format, buf, key, value); } else { hamlit_build_for_others(escape_attrs, quote, buf, key, value); } } return buf; } static VALUE rb_hamlit_build_id(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self)) { VALUE array; rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); rb_scan_args(argc - 1, argv + 1, "*", &array); return hamlit_build_id(argv[0], array); } static VALUE rb_hamlit_build_class(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self)) { VALUE array; rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); rb_scan_args(argc - 1, argv + 1, "*", &array); return hamlit_build_class(argv[0], array); } static VALUE rb_hamlit_build_aria(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self)) { VALUE array; rb_check_arity(argc, 2, UNLIMITED_ARGUMENTS); rb_scan_args(argc - 2, argv + 2, "*", &array); return hamlit_build_data(argv[0], argv[1], array, str_aria); } static VALUE rb_hamlit_build_data(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self)) { VALUE array; rb_check_arity(argc, 2, UNLIMITED_ARGUMENTS); rb_scan_args(argc - 2, argv + 2, "*", &array); return hamlit_build_data(argv[0], argv[1], array, str_data); } static VALUE rb_hamlit_build(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self)) { VALUE array; rb_check_arity(argc, 5, UNLIMITED_ARGUMENTS); rb_scan_args(argc - 5, argv + 5, "*", &array); return hamlit_build(argv[0], argv[1], argv[2], argv[3], argv[4], array); } void Init_hamlit(void) { VALUE mHamlit, mUtils; mHamlit = rb_define_module("Hamlit"); mObjectRef = rb_define_module_under(mHamlit, "ObjectRef"); mUtils = rb_define_module_under(mHamlit, "Utils"); mAttributeBuilder = rb_define_module_under(mHamlit, "AttributeBuilder"); rb_define_singleton_method(mUtils, "escape_html", rb_escape_html, 1); rb_define_singleton_method(mAttributeBuilder, "build", rb_hamlit_build, -1); rb_define_singleton_method(mAttributeBuilder, "build_id", rb_hamlit_build_id, -1); rb_define_singleton_method(mAttributeBuilder, "build_class", rb_hamlit_build_class, -1); rb_define_singleton_method(mAttributeBuilder, "build_aria", rb_hamlit_build_aria, -1); rb_define_singleton_method(mAttributeBuilder, "build_data", rb_hamlit_build_data, -1); id_flatten = rb_intern("flatten"); id_keys = rb_intern("keys"); id_parse = rb_intern("parse"); id_prepend = rb_intern("prepend"); id_tr = rb_intern("tr"); id_uniq_bang = rb_intern("uniq!"); id_xhtml = rb_intern("xhtml"); // Consider using rb_interned_str() once we stop supporting Ruby 2.7. rb_gc_register_mark_object(str_aria = rb_obj_freeze(rb_str_new_cstr("aria"))); rb_gc_register_mark_object(str_data = rb_obj_freeze(rb_str_new_cstr("data"))); rb_gc_register_mark_object(str_equal = rb_obj_freeze(rb_str_new_cstr("="))); rb_gc_register_mark_object(str_hyphen = rb_obj_freeze(rb_str_new_cstr("-"))); rb_gc_register_mark_object(str_space = rb_obj_freeze(rb_str_new_cstr(" "))); rb_gc_register_mark_object(str_underscore = rb_obj_freeze(rb_str_new_cstr("_"))); } #endif hamlit-2.15.1/ext/hamlit/hescape.c000066400000000000000000000056511407657076200167350ustar00rootroot00000000000000#include #include #include #include "hescape.h" static const char *ESCAPED_STRING[] = { "", """, "&", "'", "<", ">", }; // This is strlen(ESCAPED_STRING[x]) optimized specially. // Mapping: 1 => 6, 2 => 5, 3 => 5, 4 => 4, 5 => 4 #define ESC_LEN(x) ((13 - x) / 2) /* * Given ASCII-compatible character, return index of ESCAPED_STRING. * * " (34) => 1 (") * & (38) => 2 (&) * ' (39) => 3 (') * < (60) => 4 (<) * > (62) => 5 (>) */ static const char HTML_ESCAPE_TABLE[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static char* ensure_allocated(char *buf, size_t size, size_t *asize) { size_t new_size; if (size < *asize) return buf; if (*asize == 0) { new_size = size; } else { new_size = *asize; } // Increase buffer size by 1.5x if realloced multiple times. while (new_size < size) new_size = (new_size << 1) - (new_size >> 1); // Round allocation up to multiple of 8. new_size = (new_size + 7) & ~7; *asize = new_size; return realloc(buf, new_size); } size_t hesc_escape_html(char **dest, const char *buf, size_t size) { size_t asize = 0, esc_i = 0, esize = 0, i = 0, rbuf_end = 0; const char *esc; char *rbuf = NULL; while (i < size) { // Loop here to skip non-escaped characters fast. while (i < size && (esc_i = HTML_ESCAPE_TABLE[(unsigned char)buf[i]]) == 0) i++; if (i < size && esc_i) { esc = ESCAPED_STRING[esc_i]; rbuf = ensure_allocated(rbuf, sizeof(char) * (size + esize + ESC_LEN(esc_i) + 1), &asize); // Copy pending characters and escaped string. memmove(rbuf + rbuf_end, buf + (rbuf_end - esize), i - (rbuf_end - esize)); memmove(rbuf + i + esize, esc, ESC_LEN(esc_i)); rbuf_end = i + esize + ESC_LEN(esc_i); esize += ESC_LEN(esc_i) - 1; } i++; } if (rbuf_end == 0) { // Return given buf and size if there are no escaped characters. *dest = (char *)buf; return size; } else { // Copy pending characters including NULL character. memmove(rbuf + rbuf_end, buf + (rbuf_end - esize), (size + 1) - (rbuf_end - esize)); *dest = rbuf; return size + esize; } } hamlit-2.15.1/ext/hamlit/hescape.h000066400000000000000000000006561407657076200167420ustar00rootroot00000000000000#ifndef HESCAPE_H #define HESCAPE_H #include /* * Replace characters according to the following rules. * Note that this function can handle only ASCII-compatible string. * * " => " * & => & * ' => ' * < => < * > => > * * @return size of dest. If it's larger than len, dest is required to be freed. */ extern size_t hesc_escape_html(char **dest, const char *src, size_t size); #endif hamlit-2.15.1/hamlit.gemspec000066400000000000000000000033241407657076200157210ustar00rootroot00000000000000# coding: utf-8 lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'hamlit/version' Gem::Specification.new do |spec| spec.name = 'hamlit' spec.version = Hamlit::VERSION spec.authors = ['Takashi Kokubun'] spec.email = ['takashikkbn@gmail.com'] spec.summary = %q{High Performance Haml Implementation} spec.description = %q{High Performance Haml Implementation} spec.homepage = 'https://github.com/k0kubun/hamlit' spec.license = 'MIT' spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|sample|benchmark)/}) } spec.bindir = 'exe' spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } spec.require_paths = ['lib'] if /java/ === RUBY_PLATFORM spec.platform = 'java' else spec.extensions = ['ext/hamlit/extconf.rb'] spec.required_ruby_version = '>= 2.1.0' end spec.add_dependency 'temple', '>= 0.8.2' spec.add_dependency 'thor' spec.add_dependency 'tilt' spec.add_development_dependency 'benchmark_driver' spec.add_development_dependency 'bundler' spec.add_development_dependency 'coffee-script' spec.add_development_dependency 'erubi' spec.add_development_dependency 'haml', '>= 5' spec.add_development_dependency 'less' spec.add_development_dependency 'minitest-reporters', '~> 1.1' spec.add_development_dependency 'rails', '>= 4.0' spec.add_development_dependency 'rake' spec.add_development_dependency 'rake-compiler' spec.add_development_dependency 'sass' spec.add_development_dependency 'slim' spec.add_development_dependency 'string_template' spec.add_development_dependency 'unindent' end hamlit-2.15.1/lib/000077500000000000000000000000001407657076200136425ustar00rootroot00000000000000hamlit-2.15.1/lib/hamlit.rb000066400000000000000000000003701407657076200154450ustar00rootroot00000000000000# frozen_string_literal: true require 'hamlit/engine' require 'hamlit/error' require 'hamlit/version' require 'hamlit/template' if File.basename($0) != 'hamlit' begin require 'rails' require 'hamlit/railtie' rescue LoadError end end hamlit-2.15.1/lib/hamlit/000077500000000000000000000000001407657076200151205ustar00rootroot00000000000000hamlit-2.15.1/lib/hamlit/ambles.rb000066400000000000000000000006411407657076200167110ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit class Ambles < Temple::Filter define_options :preamble, :postamble def initialize(*) super @preamble = options[:preamble] @postamble = options[:postamble] end def call(ast) ret = [:multi] ret << [:static, @preamble] if @preamble ret << ast ret << [:static, @postamble] if @postamble ret end end end hamlit-2.15.1/lib/hamlit/attribute_builder.rb000066400000000000000000000121551407657076200211620ustar00rootroot00000000000000# frozen_string_literal: true require 'hamlit/object_ref' module Hamlit::AttributeBuilder BOOLEAN_ATTRIBUTES = %w[disabled readonly multiple checked autobuffer autoplay controls loop selected hidden scoped async defer reversed ismap seamless muted required autofocus novalidate formnovalidate open pubdate itemscope allowfullscreen default inert sortable truespeed typemustmatch download].freeze # Java extension is not implemented for JRuby yet. # TruffleRuby does not implement `rb_ary_sort_bang`, etc. if /java/ === RUBY_PLATFORM || RUBY_ENGINE == 'truffleruby' class << self def build(escape_attrs, quote, format, boolean_attributes, object_ref, *hashes) hashes << Hamlit::ObjectRef.parse(object_ref) if object_ref buf = [] hash = merge_all_attrs(hashes) keys = hash.keys.sort! keys.each do |key| case key when 'id'.freeze buf << " id=#{quote}#{build_id(escape_attrs, *hash[key])}#{quote}" when 'class'.freeze buf << " class=#{quote}#{build_class(escape_attrs, *hash[key])}#{quote}" when 'data'.freeze buf << build_data(escape_attrs, quote, *hash[key]) when *boolean_attributes, /\Adata-/ build_boolean!(escape_attrs, quote, format, buf, key, hash[key]) else buf << " #{key}=#{quote}#{escape_html(escape_attrs, hash[key].to_s)}#{quote}" end end buf.join end def build_id(escape_attrs, *values) escape_html(escape_attrs, values.flatten.select { |v| v }.join('_')) end def build_class(escape_attrs, *values) if values.size == 1 value = values.first case when value.is_a?(String) # noop when value.is_a?(Array) value = value.flatten.select { |v| v }.map(&:to_s).uniq.join(' ') when value value = value.to_s else return '' end return escape_html(escape_attrs, value) end classes = [] values.each do |value| case when value.is_a?(String) classes += value.split(' ') when value.is_a?(Array) classes += value.select { |v| v } when value classes << value.to_s end end escape_html(escape_attrs, classes.map(&:to_s).uniq.join(' ')) end def build_data(escape_attrs, quote, *hashes) build_data_attribute(:data, escape_attrs, quote, *hashes) end def build_aria(escape_attrs, quote, *hashes) build_data_attribute(:aria, escape_attrs, quote, *hashes) end private def build_data_attribute(key, escape_attrs, quote, *hashes) attrs = [] if hashes.size > 1 && hashes.all? { |h| h.is_a?(Hash) } data_value = merge_all_attrs(hashes) else data_value = hashes.last end hash = flatten_attributes(key => data_value) hash.sort_by(&:first).each do |key, value| case value when true attrs << " #{key}" when nil, false # noop else attrs << " #{key}=#{quote}#{escape_html(escape_attrs, value.to_s)}#{quote}" end end attrs.join end def flatten_attributes(attributes) flattened = {} attributes.each do |key, value| case value when attributes when Hash flatten_attributes(value).each do |k, v| if k.nil? flattened[key] = v else flattened["#{key}-#{k.to_s.gsub(/_/, '-')}"] = v end end else flattened[key] = value if value end end flattened end def merge_all_attrs(hashes) merged = {} hashes.each do |hash| hash.each do |key, value| key = key.to_s case key when 'id'.freeze, 'class'.freeze, 'data'.freeze merged[key] ||= [] merged[key] << value else merged[key] = value end end end merged end def build_boolean!(escape_attrs, quote, format, buf, key, value) case value when true case format when :xhtml buf << " #{key}=#{quote}#{key}#{quote}" else buf << " #{key}" end when false, nil # omitted else buf << " #{key}=#{quote}#{escape_html(escape_attrs, value)}#{quote}" end end def escape_html(escape_attrs, str) if escape_attrs Hamlit::Utils.escape_html(str) else str end end end else # Hamlit::AttributeBuilder.build # Hamlit::AttributeBuilder.build_id # Hamlit::AttributeBuilder.build_class # Hamlit::AttributeBuilder.build_data # Hamlit::AttributeBuilder.build_aria require 'hamlit/hamlit' end end hamlit-2.15.1/lib/hamlit/attribute_compiler.rb000066400000000000000000000106041407657076200213430ustar00rootroot00000000000000# frozen_string_literal: true require 'hamlit/attribute_builder' require 'hamlit/attribute_parser' require 'hamlit/ruby_expression' module Hamlit class AttributeCompiler def initialize(identity, options) @identity = identity @quote = options[:attr_quote] @format = options[:format] @escape_attrs = options[:escape_attrs] end def compile(node) hashes = [] if node.value[:object_ref] != :nil || !Ripper.respond_to?(:lex) # No Ripper.lex in truffleruby return runtime_compile(node) end [node.value[:dynamic_attributes].new, node.value[:dynamic_attributes].old].compact.each do |attribute_str| hash = AttributeParser.parse(attribute_str) return runtime_compile(node) unless hash hashes << hash end static_compile(node.value[:attributes], hashes) end private def runtime_compile(node) attrs = [] attrs.unshift(node.value[:attributes].inspect) if node.value[:attributes] != {} args = [ @escape_attrs.inspect, "#{@quote.inspect}.freeze", @format.inspect, '::Hamlit::AttributeBuilder::BOOLEAN_ATTRIBUTES', node.value[:object_ref], ] + attrs [:html, :attrs, [:dynamic, "::Hamlit::AttributeBuilder.build(#{args.join(', ')}, #{node.value[:dynamic_attributes].to_literal})"]] end def static_compile(static_hash, dynamic_hashes) temple = [:html, :attrs] keys = [*static_hash.keys, *dynamic_hashes.map(&:keys).flatten].uniq.sort keys.each do |key| values = [[:static, static_hash[key]], *dynamic_hashes.map { |h| [:dynamic, h[key]] }] values.select! { |_, exp| exp != nil } case key when 'id' compile_id!(temple, key, values) when 'class' compile_class!(temple, key, values) when 'data', 'aria' compile_data!(temple, key, values) when *AttributeBuilder::BOOLEAN_ATTRIBUTES, /\Adata-/, /\Aaria-/ compile_boolean!(temple, key, values) else compile_common!(temple, key, values) end end temple end def compile_id!(temple, key, values) build_code = attribute_builder(:id, values) if values.all? { |type, exp| type == :static || Temple::StaticAnalyzer.static?(exp) } temple << [:html, :attr, key, [:static, eval(build_code).to_s]] else temple << [:html, :attr, key, [:dynamic, build_code]] end end def compile_class!(temple, key, values) build_code = attribute_builder(:class, values) if values.all? { |type, exp| type == :static || Temple::StaticAnalyzer.static?(exp) } temple << [:html, :attr, key, [:static, eval(build_code).to_s]] else temple << [:html, :attr, key, [:dynamic, build_code]] end end def compile_data!(temple, key, values) args = [@escape_attrs.inspect, "#{@quote.inspect}.freeze", values.map { |v| literal_for(v) }] build_code = "::Hamlit::AttributeBuilder.build_#{key}(#{args.join(', ')})" if values.all? { |type, exp| type == :static || Temple::StaticAnalyzer.static?(exp) } temple << [:static, eval(build_code).to_s] else temple << [:dynamic, build_code] end end def compile_boolean!(temple, key, values) exp = literal_for(values.last) if Temple::StaticAnalyzer.static?(exp) value = eval(exp) case value when true then temple << [:html, :attr, key, @format == :xhtml ? [:static, key] : [:multi]] when false, nil else temple << [:html, :attr, key, [:fescape, @escape_attrs, [:static, value.to_s]]] end else var = @identity.generate temple << [ :case, "(#{var} = (#{exp}))", ['true', [:html, :attr, key, @format == :xhtml ? [:static, key] : [:multi]]], ['false, nil', [:multi]], [:else, [:multi, [:static, " #{key}=#{@quote}"], [:fescape, @escape_attrs, [:dynamic, var]], [:static, @quote]]], ] end end def compile_common!(temple, key, values) temple << [:html, :attr, key, [:fescape, @escape_attrs, values.last]] end def attribute_builder(type, values) args = [@escape_attrs.inspect, *values.map { |v| literal_for(v) }] "::Hamlit::AttributeBuilder.build_#{type}(#{args.join(', ')})" end def literal_for(value) type, exp = value type == :static ? "#{exp.inspect}.freeze" : exp end end end hamlit-2.15.1/lib/hamlit/attribute_parser.rb000066400000000000000000000050531407657076200210270ustar00rootroot00000000000000# frozen_string_literal: true require 'hamlit/ruby_expression' module Hamlit class AttributeParser class ParseSkip < StandardError end def self.parse(text) self.new.parse(text) end def parse(text) exp = wrap_bracket(text) return if RubyExpression.syntax_error?(exp) hash = {} tokens = Ripper.lex(exp)[1..-2] || [] each_attr(tokens) do |attr_tokens| key = parse_key!(attr_tokens) hash[key] = attr_tokens.map { |t| t[2] }.join.strip end hash rescue ParseSkip nil end private def wrap_bracket(text) text = text.strip return text if text[0] == '{' "{#{text}}" end def parse_key!(tokens) _, type, str = tokens.shift case type when :on_sp parse_key!(tokens) when :on_label str.tr(':', '') when :on_symbeg _, _, key = tokens.shift assert_type!(tokens.shift, :on_tstring_end) if str != ':' skip_until_hash_rocket!(tokens) key when :on_tstring_beg _, _, key = tokens.shift next_token = tokens.shift unless next_token[1] == :on_label_end assert_type!(next_token, :on_tstring_end) skip_until_hash_rocket!(tokens) end key else raise ParseSkip end end def assert_type!(token, type) raise ParseSkip if token[1] != type end def skip_until_hash_rocket!(tokens) until tokens.empty? _, type, str = tokens.shift break if type == :on_op && str == '=>' end end def each_attr(tokens) attr_tokens = [] open_tokens = Hash.new { |h, k| h[k] = 0 } tokens.each do |token| _, type, _ = token case type when :on_comma if open_tokens.values.all?(&:zero?) yield(attr_tokens) attr_tokens = [] next end when :on_lbracket open_tokens[:array] += 1 when :on_rbracket open_tokens[:array] -= 1 when :on_lbrace open_tokens[:block] += 1 when :on_rbrace open_tokens[:block] -= 1 when :on_lparen open_tokens[:paren] += 1 when :on_rparen open_tokens[:paren] -= 1 when :on_embexpr_beg open_tokens[:embexpr] += 1 when :on_embexpr_end open_tokens[:embexpr] -= 1 when :on_sp next if attr_tokens.empty? end attr_tokens << token end yield(attr_tokens) unless attr_tokens.empty? end end end hamlit-2.15.1/lib/hamlit/cli.rb000066400000000000000000000100251407657076200162120ustar00rootroot00000000000000# frozen_string_literal: true require 'hamlit' require 'thor' module Hamlit class CLI < Thor class_option :escape_html, type: :boolean, default: true class_option :escape_attrs, type: :boolean, default: true desc 'render HAML', 'Render haml template' option :load_path, type: :string, aliases: %w[-I] option :require, type: :string, aliases: %w[-r] def render(file) process_load_options code = generate_code(file) puts eval(code, binding, file) end desc 'compile HAML', 'Show compile result' option :actionview, type: :boolean, default: false, aliases: %w[-a] option :color, type: :boolean, default: true option :check, type: :boolean, default: false, aliases: %w[-c] def compile(file) code = generate_code(file) if options[:check] if error = validate_ruby(code, file) abort error.message.split("\n").first end puts "Syntax OK" return end puts_code(code, color: options[:color]) end desc 'temple HAML', 'Show temple intermediate expression' option :color, type: :boolean, default: true def temple(file) pp_object(generate_temple(file), color: options[:color]) end desc 'parse HAML', 'Show parse result' option :color, type: :boolean, default: true def parse(file) pp_object(generate_ast(file), color: options[:color]) end desc 'version', 'Show the used hamlit version' def version puts Hamlit::VERSION end private def process_load_options if options[:load_path] options[:load_path].split(':').each do |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) end end if options[:require] require options[:require] end end def read_file(file) if file == '-' STDIN.read else File.read(file) end end def generate_code(file) template = read_file(file) if options[:actionview] require 'action_view' require 'action_view/base' require 'hamlit/rails_template' handler = Hamlit::RailsTemplate.new template = ActionView::Template.new(template, 'inline template', handler, { locals: [] }) code = handler.call(template) <<-end_src def _inline_template___2144273726781623612_70327218547300(local_assigns, output_buffer) _old_virtual_path, @virtual_path = @virtual_path, nil;_old_output_buffer = @output_buffer;;#{code} ensure @virtual_path, @output_buffer = _old_virtual_path, _old_output_buffer end end_src else Hamlit::Engine.new(engine_options).call(template) end end def generate_ast(file) template = read_file(file) Hamlit::Parser.new(engine_options).call(template) end def generate_temple(file) ast = generate_ast(file) Hamlit::Compiler.new(engine_options).call(ast) end def engine_options Hamlit::Engine.options.to_h.merge( escape_attrs: options[:escape_attrs], escape_html: options[:escape_html], ) end # Flexible default_task, compatible with haml's CLI def method_missing(*args) return super(*args) if args.length > 1 render(args.first.to_s) end def puts_code(code, color: true) begin require 'irb/color' rescue LoadError color = false end if color puts IRB::Color.colorize_code(code) else puts code end end # Enable colored pretty printing only for development environment. def pp_object(arg, color: true) begin require 'irb/color_printer' rescue LoadError color = false end if color IRB::ColorPrinter.pp(arg) else require 'pp' pp(arg) end end def validate_ruby(code, file) begin eval("BEGIN {return nil}; #{code}", binding, file) rescue ::SyntaxError # Not to be confused with Hamlit::SyntaxError $! end end end end hamlit-2.15.1/lib/hamlit/compiler.rb000066400000000000000000000050501407657076200172570ustar00rootroot00000000000000# frozen_string_literal: true require 'hamlit/compiler/children_compiler' require 'hamlit/compiler/comment_compiler' require 'hamlit/compiler/doctype_compiler' require 'hamlit/compiler/script_compiler' require 'hamlit/compiler/silent_script_compiler' require 'hamlit/compiler/tag_compiler' require 'hamlit/filters' require 'hamlit/identity' module Hamlit class Compiler def initialize(options = {}) identity = Identity.new @children_compiler = ChildrenCompiler.new @comment_compiler = CommentCompiler.new @doctype_compiler = DoctypeCompiler.new(options) @filter_compiler = Filters.new(options) @script_compiler = ScriptCompiler.new(identity) @silent_script_compiler = SilentScriptCompiler.new @tag_compiler = TagCompiler.new(identity, options) end def call(ast) return runtime_error(ast) if ast.is_a?(HamlError) compile(ast) rescue Error => e runtime_error(e) end private def compile(node) case node.type when :root compile_children(node) when :comment compile_comment(node) when :doctype compile_doctype(node) when :filter compile_filter(node) when :plain compile_plain(node) when :script compile_script(node) when :silent_script compile_silent_script(node) when :tag compile_tag(node) when :haml_comment [:multi] else raise InternalError.new("Unexpected node type: #{node.type}") end end def compile_children(node) @children_compiler.compile(node) { |n| compile(n) } end def compile_comment(node) @comment_compiler.compile(node) { |n| compile_children(n) } end def compile_doctype(node) @doctype_compiler.compile(node) end def compile_filter(node) @filter_compiler.compile(node) end def compile_plain(node) [:static, node.value[:text]] end def compile_script(node) @script_compiler.compile(node) { |n| compile_children(n) } end def compile_silent_script(node) @silent_script_compiler.compile(node) { |n| compile_children(n) } end def compile_tag(node) @tag_compiler.compile(node) { |n| compile_children(n) } end def runtime_error(error) [:multi].tap do |temple| error.line.times { temple << [:newline] } if error.line temple << [:code, %Q[raise #{error.class}.new(%q[#{error.message}], #{error.line.inspect})]] end end end end hamlit-2.15.1/lib/hamlit/compiler/000077500000000000000000000000001407657076200167325ustar00rootroot00000000000000hamlit-2.15.1/lib/hamlit/compiler/children_compiler.rb000066400000000000000000000063271407657076200227510ustar00rootroot00000000000000# frozen_string_literal: true require 'hamlit/temple_line_counter' module Hamlit class Compiler class ChildrenCompiler def initialize @lineno = 1 end def compile(node, &block) temple = [:multi] return temple if node.children.empty? temple << :whitespace if prepend_whitespace?(node) node.children.each do |n| rstrip_whitespace!(temple) if nuke_prev_whitespace?(n) insert_newlines!(temple, n) temple << moving_lineno(n) { block.call(n) } temple << :whitespace if insert_whitespace?(n) end rstrip_whitespace!(temple) if nuke_inner_whitespace?(node) confirm_whitespace(temple) end private def insert_newlines!(temple, node) (node.line - @lineno).times do temple << [:newline] end @lineno = node.line end def moving_lineno(node, &block) # before: As they may have children, we need to increment lineno before compilation. case node.type when :script, :silent_script @lineno += 1 when :tag [node.value[:dynamic_attributes].new, node.value[:dynamic_attributes].old].compact.each do |attribute_hash| @lineno += attribute_hash.count("\n") end @lineno += 1 if node.children.empty? && node.value[:parse] end temple = block.call # compile # after: filter may not have children, and for some dynamic filters we can't predict the number of lines. case node.type when :filter @lineno += TempleLineCounter.count_lines(temple) end temple end def confirm_whitespace(temple) temple.map do |exp| case exp when :whitespace [:static, "\n"] else exp end end end def prepend_whitespace?(node) return false unless %i[comment tag].include?(node.type) !nuke_inner_whitespace?(node) end def nuke_inner_whitespace?(node) case when node.type == :tag node.value[:nuke_inner_whitespace] when node.parent.nil? false else nuke_inner_whitespace?(node.parent) end end def nuke_prev_whitespace?(node) case node.type when :tag node.value[:nuke_outer_whitespace] when :silent_script !node.children.empty? && nuke_prev_whitespace?(node.children.first) else false end end def nuke_outer_whitespace?(node) return false if node.type != :tag node.value[:nuke_outer_whitespace] end def rstrip_whitespace!(temple) if temple[-1] == :whitespace temple.delete_at(-1) end end def insert_whitespace?(node) return false if nuke_outer_whitespace?(node) case node.type when :doctype node.value[:type] != 'xml' when :comment, :plain, :tag true when :script node.children.empty? && !nuke_inner_whitespace?(node) when :filter !%w[ruby].include?(node.value[:name]) else false end end end end end hamlit-2.15.1/lib/hamlit/compiler/comment_compiler.rb000066400000000000000000000017171407657076200226210ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit class Compiler class CommentCompiler def compile(node, &block) if node.value[:conditional] compile_conditional_comment(node, &block) else compile_html_comment(node, &block) end end private def compile_html_comment(node, &block) if node.children.empty? [:html, :comment, [:static, " #{node.value[:text]} "]] else [:html, :comment, yield(node)] end end def compile_conditional_comment(node, &block) condition = node.value[:conditional] if node.value[:conditional] =~ /\A\[(\[*[^\[\]]+\]*)\]/ condition = $1 end content = if node.children.empty? [:static, " #{node.value[:text]} "] else yield(node) end [:html, :condcomment, condition, content, node.value[:revealed]] end end end end hamlit-2.15.1/lib/hamlit/compiler/doctype_compiler.rb000066400000000000000000000017011407657076200226170ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit class Compiler class DoctypeCompiler def initialize(options = {}) @format = options[:format] end def compile(node) case node.value[:type] when 'xml' xml_doctype when '' html_doctype(node) else [:html, :doctype, node.value[:type]] end end private def html_doctype(node) version = node.value[:version] || :transitional case @format when :xhtml [:html, :doctype, version] when :html4 [:html, :doctype, :transitional] when :html5 [:html, :doctype, :html] else [:html, :doctype, @format] end end def xml_doctype case @format when :xhtml [:static, "\n"] else [:multi] end end end end end hamlit-2.15.1/lib/hamlit/compiler/script_compiler.rb000066400000000000000000000060461407657076200224630ustar00rootroot00000000000000# frozen_string_literal: true require 'temple/static_analyzer' require 'hamlit/ruby_expression' require 'hamlit/string_splitter' module Hamlit class Compiler class ScriptCompiler def initialize(identity) @identity = identity end def compile(node, &block) unless Ripper.respond_to?(:lex) # No Ripper.lex in truffleruby return dynamic_compile(node, &block) end no_children = node.children.empty? case when no_children && node.value[:escape_interpolation] compile_interpolated_plain(node) when no_children && RubyExpression.string_literal?(node.value[:text]) delegate_optimization(node) when no_children && Temple::StaticAnalyzer.static?(node.value[:text]) static_compile(node) else dynamic_compile(node, &block) end end private # String-interpolated plain text must be compiled with this method # because we have to escape only interpolated values. def compile_interpolated_plain(node) temple = [:multi] StringSplitter.compile(node.value[:text]).each do |type, value| case type when :static temple << [:static, value] when :dynamic temple << [:escape, node.value[:escape_interpolation], [:dynamic, value]] end end temple << [:newline] end # :dynamic is optimized in other filter: StringSplitter def delegate_optimization(node) [:multi, [:escape, node.value[:escape_html], [:dynamic, node.value[:text]]], [:newline], ] end def static_compile(node) str = eval(node.value[:text]).to_s if node.value[:escape_html] str = Hamlit::Utils.escape_html(str) elsif node.value[:preserve] str = ::Hamlit::HamlHelpers.find_and_preserve(str, %w(textarea pre code)) end [:multi, [:static, str], [:newline]] end def dynamic_compile(node, &block) var = @identity.generate temple = compile_script_assign(var, node, &block) temple << compile_script_result(var, node) end def compile_script_assign(var, node, &block) if node.children.empty? [:multi, [:code, "#{var} = (#{node.value[:text]}"], [:newline], [:code, ')'], ] else [:multi, [:block, "#{var} = #{node.value[:text]}", [:multi, [:newline], yield(node)], ], ] end end def compile_script_result(result, node) if !node.value[:escape_html] && node.value[:preserve] result = find_and_preserve(result) else result = "(#{result}).to_s" end [:escape, node.value[:escape_html], [:dynamic, result]] end def find_and_preserve(code) %Q[::Hamlit::HamlHelpers.find_and_preserve(#{code}, %w(textarea pre code))] end def escape_html(temple) [:escape, true, temple] end end end end hamlit-2.15.1/lib/hamlit/compiler/silent_script_compiler.rb000066400000000000000000000007731407657076200240420ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit class Compiler class SilentScriptCompiler def compile(node, &block) if node.children.empty? [:multi, [:code, node.value[:text]], [:newline]] else compile_with_children(node, &block) end end private def compile_with_children(node, &block) [:multi, [:block, node.value[:text], [:multi, [:newline], yield(node)], ], ] end end end end hamlit-2.15.1/lib/hamlit/compiler/tag_compiler.rb000066400000000000000000000045421407657076200217310ustar00rootroot00000000000000# frozen_string_literal: true require 'hamlit/parser/haml_util' require 'hamlit/attribute_compiler' require 'hamlit/string_splitter' module Hamlit class Compiler class TagCompiler def initialize(identity, options) @autoclose = options[:autoclose] @identity = identity @attribute_compiler = AttributeCompiler.new(identity, options) end def compile(node, &block) attrs = @attribute_compiler.compile(node) contents = compile_contents(node, &block) [:html, :tag, node.value[:name], attrs, contents] end private def compile_contents(node, &block) case when !node.children.empty? yield(node) when node.value[:value].nil? && self_closing?(node) nil when node.value[:parse] return compile_interpolated_plain(node) if node.value[:escape_interpolation] if Ripper.respond_to?(:lex) # No Ripper.lex in truffleruby return delegate_optimization(node) if RubyExpression.string_literal?(node.value[:value]) return delegate_optimization(node) if Temple::StaticAnalyzer.static?(node.value[:value]) end var = @identity.generate [:multi, [:code, "#{var} = (#{node.value[:value]}"], [:newline], [:code, ')'], [:escape, node.value[:escape_html], [:dynamic, var]] ] else [:static, node.value[:value]] end end # :dynamic is optimized in other filters: StringSplitter or StaticAnalyzer def delegate_optimization(node) [:multi, [:escape, node.value[:escape_html], [:dynamic, node.value[:value]]], [:newline], ] end # We should handle interpolation here to escape only interpolated values. def compile_interpolated_plain(node) temple = [:multi] StringSplitter.compile(node.value[:value]).each do |type, value| case type when :static temple << [:static, value] when :dynamic temple << [:escape, node.value[:escape_interpolation], [:dynamic, value]] end end temple << [:newline] end def self_closing?(node) return true if @autoclose && @autoclose.include?(node.value[:name]) node.value[:self_closing] end end end end hamlit-2.15.1/lib/hamlit/dynamic_merger.rb000066400000000000000000000036541407657076200204420ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit # Compile [:multi, [:static, 'foo'], [:dynamic, 'bar']] to [:dynamic, '"foo#{bar}"'] class DynamicMerger < Temple::Filter def on_multi(*exps) exps = exps.dup result = [:multi] buffer = [] until exps.empty? type, arg = exps.first if type == :dynamic && arg.count("\n") == 0 buffer << exps.shift elsif type == :static && exps.size > (count = arg.count("\n")) && exps[1, count].all? { |e| e == [:newline] } (1 + count).times { buffer << exps.shift } elsif type == :newline && exps.size > (count = count_newline(exps)) && exps[count].first == :static && count == exps[count].last.count("\n") (count + 1).times { buffer << exps.shift } else result.concat(merge_dynamic(buffer)) buffer = [] result << compile(exps.shift) end end result.concat(merge_dynamic(buffer)) result.size == 2 ? result[1] : result end private def merge_dynamic(exps) # Merge exps only when they have both :static and :dynamic unless exps.any? { |type,| type == :static } && exps.any? { |type,| type == :dynamic } return exps end strlit_body = String.new exps.each do |type, arg| case type when :static strlit_body << arg.dump.sub!(/\A"/, '').sub!(/"\z/, '').gsub('\n', "\n") when :dynamic strlit_body << "\#{#{arg}}" when :newline # newline is added by `gsub('\n', "\n")` else raise "unexpected type #{type.inspect} is given to #merge_dynamic" end end [[:dynamic, "%Q\0#{strlit_body}\0"]] end def count_newline(exps) count = 0 exps.each do |exp| if exp == [:newline] count += 1 else return count end end return count end end end hamlit-2.15.1/lib/hamlit/engine.rb000066400000000000000000000017601407657076200167160ustar00rootroot00000000000000# frozen_string_literal: true require 'temple' require 'hamlit/parser' require 'hamlit/compiler' require 'hamlit/html' require 'hamlit/escapable' require 'hamlit/force_escapable' require 'hamlit/dynamic_merger' require 'hamlit/ambles' module Hamlit class Engine < Temple::Engine define_options( :buffer_class, generator: Temple::Generators::ArrayBuffer, format: :html, attr_quote: "'", escape_html: true, escape_attrs: true, autoclose: %w(area base basefont br col command embed frame hr img input isindex keygen link menuitem meta param source track wbr), filename: "", ) use Parser use Compiler use HTML filter :StringSplitter filter :StaticAnalyzer use Escapable use ForceEscapable filter :ControlFlow use Ambles filter :MultiFlattener filter :StaticMerger use DynamicMerger use :Generator, -> { options[:generator] } end end hamlit-2.15.1/lib/hamlit/error.rb000066400000000000000000000004621407657076200166000ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit class Error < StandardError attr_reader :line def initialize(message = nil, line = nil) super(message) @line = line end end class SyntaxError < Error; end class InternalError < Error; end class FilterNotFound < Error; end end hamlit-2.15.1/lib/hamlit/escapable.rb000066400000000000000000000005551407657076200173710ustar00rootroot00000000000000# frozen_string_literal: true require 'hamlit/utils' module Hamlit class Escapable < Temple::Filters::Escapable def initialize(opts = {}) super @escape_code = options[:escape_code] || "::Hamlit::Utils.escape_html#{options[:use_html_safe] ? '_safe' : ''}((%s))" @escaper = eval("proc {|v| #{@escape_code % 'v'} }") end end end hamlit-2.15.1/lib/hamlit/filters.rb000066400000000000000000000036041407657076200171200ustar00rootroot00000000000000# frozen_string_literal: true require 'hamlit/filters/base' require 'hamlit/filters/text_base' require 'hamlit/filters/tilt_base' require 'hamlit/filters/coffee' require 'hamlit/filters/css' require 'hamlit/filters/erb' require 'hamlit/filters/escaped' require 'hamlit/filters/javascript' require 'hamlit/filters/less' require 'hamlit/filters/markdown' require 'hamlit/filters/plain' require 'hamlit/filters/preserve' require 'hamlit/filters/ruby' require 'hamlit/filters/sass' require 'hamlit/filters/scss' require 'hamlit/filters/cdata' module Hamlit class Filters @registered = {} class << self attr_reader :registered def remove_filter(name) registered.delete(name.to_s.downcase.to_sym) if constants.map(&:to_s).include?(name.to_s) remove_const name.to_sym end end private def register(name, compiler) registered[name] = compiler end end register :coffee, Coffee register :coffeescript, CoffeeScript register :css, Css register :erb, Erb register :escaped, Escaped register :javascript, Javascript register :less, Less register :markdown, Markdown register :plain, Plain register :preserve, Preserve register :ruby, Ruby register :sass, Sass register :scss, Scss register :cdata, Cdata def initialize(options = {}) @options = options @compilers = {} end def compile(node) node.value[:text] ||= '' find_compiler(node).compile(node) end private def find_compiler(node) name = node.value[:name].to_sym compiler = Filters.registered[name] raise FilterNotFound.new("FilterCompiler for '#{name}' was not found", node.line.to_i - 1) unless compiler @compilers[name] ||= compiler.new(@options) end end end hamlit-2.15.1/lib/hamlit/filters/000077500000000000000000000000001407657076200165705ustar00rootroot00000000000000hamlit-2.15.1/lib/hamlit/filters/base.rb000066400000000000000000000003201407657076200200220ustar00rootroot00000000000000# frozen_string_literal: true require 'hamlit/parser/haml_util' module Hamlit class Filters class Base def initialize(options = {}) @format = options[:format] end end end end hamlit-2.15.1/lib/hamlit/filters/cdata.rb000066400000000000000000000006041407657076200201710ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit class Filters class Cdata < TextBase def compile(node) compile_cdata(node) end private def compile_cdata(node) temple = [:multi] temple << [:static, ""] temple end end end end hamlit-2.15.1/lib/hamlit/filters/coffee.rb000066400000000000000000000006451407657076200203510ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit class Filters class Coffee < TiltBase def compile(node) require 'tilt/coffee' if explicit_require?('coffee') temple = [:multi] temple << [:static, ""] temple end end CoffeeScript = Coffee end end hamlit-2.15.1/lib/hamlit/filters/css.rb000066400000000000000000000013401407657076200177030ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit class Filters class Css < TextBase def compile(node) case @format when :xhtml compile_xhtml(node) else compile_html(node) end end private def compile_html(node) temple = [:multi] temple << [:static, ""] temple end def compile_xhtml(node) temple = [:multi] temple << [:static, ""] temple end end end end hamlit-2.15.1/lib/hamlit/filters/erb.rb000066400000000000000000000002601407657076200176630ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit class Filters class Erb < TiltBase def compile(node) compile_with_tilt(node, 'erb') end end end end hamlit-2.15.1/lib/hamlit/filters/escaped.rb000066400000000000000000000007411407657076200205230ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit class Filters class Escaped < Base def compile(node) text = node.value[:text].rstrip temple = compile_text(text) [:escape, true, temple] end private def compile_text(text) if ::Hamlit::HamlUtil.contains_interpolation?(text) [:dynamic, ::Hamlit::HamlUtil.unescape_interpolation(text)] else [:static, text] end end end end end hamlit-2.15.1/lib/hamlit/filters/javascript.rb000066400000000000000000000013561407657076200212700ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit class Filters class Javascript < TextBase def compile(node) case @format when :xhtml compile_xhtml(node) else compile_html(node) end end private def compile_html(node) temple = [:multi] temple << [:static, ""] temple end def compile_xhtml(node) temple = [:multi] temple << [:static, ""] temple end end end end hamlit-2.15.1/lib/hamlit/filters/less.rb000066400000000000000000000011001407657076200200530ustar00rootroot00000000000000# frozen_string_literal: true # LESS support is deprecated since it requires therubyracer.gem, # which is hard to maintain. # # It's not supported in Sprockets 3.0+ too. # https://github.com/sstephenson/sprockets/pull/547 module Hamlit class Filters class Less < TiltBase def compile(node) require 'tilt/less' if explicit_require?('less') temple = [:multi] temple << [:static, "'] temple end end end end hamlit-2.15.1/lib/hamlit/filters/markdown.rb000066400000000000000000000003741407657076200207430ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit class Filters class Markdown < TiltBase def compile(node) require 'tilt/redcarpet' if explicit_require?('markdown') compile_with_tilt(node, 'markdown') end end end end hamlit-2.15.1/lib/hamlit/filters/plain.rb000066400000000000000000000013131407657076200202160ustar00rootroot00000000000000# frozen_string_literal: true require 'hamlit/string_splitter' module Hamlit class Filters class Plain < Base def compile(node) text = node.value[:text] text = text.rstrip unless ::Hamlit::HamlUtil.contains_interpolation?(text) # for compatibility [:multi, *compile_plain(text)] end private def compile_plain(text) string_literal = ::Hamlit::HamlUtil.unescape_interpolation(text) StringSplitter.compile(string_literal).map do |temple| type, str = temple case type when :dynamic [:escape, false, [:dynamic, str]] else temple end end end end end end hamlit-2.15.1/lib/hamlit/filters/preserve.rb000066400000000000000000000007531407657076200207550ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit class Filters class Preserve < Base def compile(node) text = node.value[:text].rstrip + "\n" text = text.gsub("\n", ' ') compile_text(text) end private def compile_text(text) if ::Hamlit::HamlUtil.contains_interpolation?(text) [:dynamic, ::Hamlit::HamlUtil.unescape_interpolation(text)] else [:static, text] end end end end end hamlit-2.15.1/lib/hamlit/filters/ruby.rb000066400000000000000000000002511407657076200200740ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit class Filters class Ruby < Base def compile(node) [:code, node.value[:text]] end end end end hamlit-2.15.1/lib/hamlit/filters/sass.rb000066400000000000000000000006001407657076200200620ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit class Filters class Sass < TiltBase def compile(node) require 'tilt/sass' if explicit_require?('sass') temple = [:multi] temple << [:static, ""] temple end end end end hamlit-2.15.1/lib/hamlit/filters/scss.rb000066400000000000000000000006001407657076200200640ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit class Filters class Scss < TiltBase def compile(node) require 'tilt/sass' if explicit_require?('scss') temple = [:multi] temple << [:static, ""] temple end end end end hamlit-2.15.1/lib/hamlit/filters/text_base.rb000066400000000000000000000014051407657076200210730ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit class Filters class TextBase < Base def compile_text!(temple, node, prefix) text = node.value[:text].rstrip.gsub(/^/, prefix) if ::Hamlit::HamlUtil.contains_interpolation?(node.value[:text]) # original: Haml::Filters#compile text = ::Hamlit::HamlUtil.unescape_interpolation(text).gsub(/(\\+)n/) do |s| escapes = $1.size next s if escapes % 2 == 0 "#{'\\' * (escapes - 1)}\n" end text.prepend("\n") temple << [:dynamic, text] else node.value[:text].split("\n").size.times do temple << [:newline] end temple << [:static, text] end end end end end hamlit-2.15.1/lib/hamlit/filters/tilt_base.rb000066400000000000000000000030501407657076200210610ustar00rootroot00000000000000# frozen_string_literal: true require 'tilt' module Hamlit class Filters class TiltBase < Base def self.render(name, source, indent_width: 0) text = ::Tilt["t.#{name}"].new { source }.render return text if indent_width == 0 text.gsub!(/^/, ' ' * indent_width) end def explicit_require?(needed_registration) Gem::Version.new(Tilt::VERSION) >= Gem::Version.new('2.0.0') && !Tilt.registered?(needed_registration) end private def compile_with_tilt(node, name, indent_width: 0) if ::Hamlit::HamlUtil.contains_interpolation?(node.value[:text]) dynamic_compile(node, name, indent_width: indent_width) else static_compile(node, name, indent_width: indent_width) end end def static_compile(node, name, indent_width: 0) temple = [:multi, [:static, TiltBase.render(name, node.value[:text], indent_width: indent_width)]] node.value[:text].split("\n").size.times do temple << [:newline] end temple end def dynamic_compile(node, name, indent_width: 0) # original: Haml::Filters#compile text = ::Hamlit::HamlUtil.unescape_interpolation(node.value[:text]).gsub(/(\\+)n/) do |s| escapes = $1.size next s if escapes % 2 == 0 "#{'\\' * (escapes - 1)}\n" end text.prepend("\n").sub!(/\n"\z/, '"') [:dynamic, "::Hamlit::Filters::TiltBase.render('#{name}', #{text}, indent_width: #{indent_width})"] end end end end hamlit-2.15.1/lib/hamlit/force_escapable.rb000066400000000000000000000015241407657076200205440ustar00rootroot00000000000000# frozen_string_literal: true require 'hamlit/escapable' module Hamlit # This module allows Temple::Filter to dispatch :fescape on `#compile`. module FescapeDispathcer def on_fescape(flag, exp) [:fescape, flag, compile(exp)] end end ::Temple::Filter.include FescapeDispathcer # Unlike Hamlit::Escapable, this escapes value even if it's html_safe. class ForceEscapable < Escapable def initialize(opts = {}) super @escape_code = options[:escape_code] || "::Hamlit::Utils.escape_html((%s))" @escaper = eval("proc {|v| #{@escape_code % 'v'} }") end alias_method :on_fescape, :on_escape # ForceEscapable doesn't touch :escape expression. # This method is not used if it's inserted after Hamlit::Escapable. def on_escape(flag, exp) [:escape, flag, compile(exp)] end end end hamlit-2.15.1/lib/hamlit/helpers.rb000066400000000000000000000005651407657076200171150ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit module Helpers extend self # The same as original Haml::Helpers#preserve without block support. def preserve(input) # https://github.com/haml/haml/blob/4.1.0.beta.1/lib/haml/helpers.rb#L130-L133 s = input.to_s.chomp("\n") s.gsub!(/\n/, ' ') s.delete!("\r") s end end end hamlit-2.15.1/lib/hamlit/html.rb000066400000000000000000000012241407657076200164100ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit class HTML < Temple::HTML::Fast DEPRECATED_FORMATS = %i[html4 html5].freeze def initialize(opts = {}) if DEPRECATED_FORMATS.include?(opts[:format]) opts = opts.dup opts[:format] = :html end super(opts) end # This dispatcher supports Haml's "revealed" conditional comment. def on_html_condcomment(condition, content, revealed = false) on_html_comment [:multi, [:static, "[#{condition}]>#{'' if revealed}"], content, [:static, "#{'\n" options[:postamble] = "\n" end Engine.new(options).call(source) end def supports_streaming? RailsTemplate.options[:streaming] end end ActionView::Template.register_template_handler(:haml, RailsTemplate.new) # https://github.com/haml/haml/blob/4.0.7/lib/haml/template.rb module HamlHelpers require 'hamlit/parser/haml_helpers/xss_mods' include Hamlit::HamlHelpers::XssMods end module HamlUtil undef :rails_xss_safe? if defined? rails_xss_safe? def rails_xss_safe?; true; end end end # Haml extends Haml::Helpers in ActionView each time. # It costs much, so Hamlit includes a compatible module at first. ActionView::Base.send :include, Hamlit::RailsHelpers hamlit-2.15.1/lib/hamlit/railtie.rb000066400000000000000000000005371407657076200171030ustar00rootroot00000000000000# frozen_string_literal: true require 'rails' module Hamlit class Railtie < ::Rails::Railtie initializer :hamlit, before: :load_config_initializers do |app| # Load haml/plugin first to override if available begin require 'haml/plugin' rescue LoadError end require 'hamlit/rails_template' end end end hamlit-2.15.1/lib/hamlit/ruby_expression.rb000066400000000000000000000011441407657076200207050ustar00rootroot00000000000000# frozen_string_literal: true require 'ripper' module Hamlit class RubyExpression < Ripper class ParseError < StandardError; end def self.syntax_error?(code) self.new(code).parse false rescue ParseError true end def self.string_literal?(code) return false if syntax_error?(code) type, instructions = Ripper.sexp(code) return false if type != :program return false if instructions.size > 1 type, _ = instructions.first type == :string_literal end private def on_parse_error(*) raise ParseError end end end hamlit-2.15.1/lib/hamlit/string_splitter.rb000066400000000000000000000007621407657076200207060ustar00rootroot00000000000000# frozen_string_literal: true require 'ripper' require 'hamlit/ruby_expression' module Hamlit module StringSplitter # `code` param must be valid string literal def self.compile(code) unless Ripper.respond_to?(:lex) # truffleruby doesn't have Ripper.lex return [[:dynamic, code]] end begin Temple::Filters::StringSplitter.compile(code) rescue Temple::FilterError => e raise Hamlit::InternalError.new(e.message) end end end end hamlit-2.15.1/lib/hamlit/template.rb000066400000000000000000000011621407657076200172600ustar00rootroot00000000000000# frozen_string_literal: false require 'temple' require 'hamlit/engine' require 'hamlit/helpers' # Load tilt/haml first to override if available begin require 'haml' rescue LoadError else require 'tilt/haml' end module Hamlit Template = Temple::Templates::Tilt.create( Hamlit::Engine, register_as: [:haml, :hamlit], ) module TemplateExtension # Activate Hamlit::Helpers for tilt templates. # https://github.com/judofyr/temple/blob/v0.7.6/lib/temple/mixins/template.rb#L7-L11 def compile(*) "extend Hamlit::Helpers; #{super}" end end Template.send(:extend, TemplateExtension) end hamlit-2.15.1/lib/hamlit/temple_line_counter.rb000066400000000000000000000016461407657076200215100ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit # A module to count lines of expected code. This would be faster than actual code generation # and counting newlines in it. module TempleLineCounter class UnexpectedExpression < StandardError; end def self.count_lines(exp) type, *args = exp case type when :multi args.map { |a| count_lines(a) }.reduce(:+) || 0 when :dynamic, :code args.first.count("\n") when :static 0 # It has not real newline "\n" but escaped "\\n". when :case arg, *cases = args arg.count("\n") + cases.map do |cond, e| (cond == :else ? 0 : cond.count("\n")) + count_lines(e) end.reduce(:+) when :escape count_lines(args[1]) when :newline 1 else raise UnexpectedExpression.new("[HAML BUG] Unexpected Temple expression '#{type}' is given!") end end end end hamlit-2.15.1/lib/hamlit/utils.rb000066400000000000000000000010141407657076200166010ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit module Utils # Java extension is not implemented for JRuby yet. # TruffleRuby does not implement `rb_ary_sort_bang`, etc. if /java/ === RUBY_PLATFORM || RUBY_ENGINE == 'truffleruby' require 'cgi/escape' def self.escape_html(html) CGI.escapeHTML(html.to_s) end else require 'hamlit/hamlit' # Hamlit::Utils.escape_html end def self.escape_html_safe(html) html.html_safe? ? html : escape_html(html) end end end hamlit-2.15.1/lib/hamlit/version.rb000066400000000000000000000001051407657076200171260ustar00rootroot00000000000000# frozen_string_literal: true module Hamlit VERSION = '2.15.1' end hamlit-2.15.1/test/000077500000000000000000000000001407657076200140535ustar00rootroot00000000000000hamlit-2.15.1/test/haml/000077500000000000000000000000001407657076200147745ustar00rootroot00000000000000hamlit-2.15.1/test/haml/engine_test.rb000066400000000000000000002060721407657076200176340ustar00rootroot00000000000000$:.unshift __dir__ require_relative '../test_helper' class EngineTest < Haml::TestCase # A map of erroneous Haml 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 = { "!!!\n a" => error(:illegal_nesting_header), "a\n b" => error(:illegal_nesting_plain), "/ a\n b" => error(:illegal_nesting_content), "% a" => error(:invalid_tag, '% a'), "%p a\n b" => error(:illegal_nesting_line, 'p'), "%p=" => error(:no_ruby_code, '='), "%p~" => error(:no_ruby_code, '~'), "~" => error(:no_ruby_code, '~'), "=" => error(:no_ruby_code, '='), "%p/\n a" => error(:illegal_nesting_self_closing), #":a\n b" => [error(:filter_not_defined, 'a'), 1], ":a= b" => error(:invalid_filter_name, 'a= b'), "." => error(:illegal_element), ".#" => error(:illegal_element), ".{} a" => error(:illegal_element), ".() a" => error(:illegal_element), ".= a" => error(:illegal_element), "%p..a" => error(:illegal_element), "%a/ b" => error(:self_closing_content), " %p foo" => error(:indenting_at_start), " %p foo" => error(:indenting_at_start), "- end" => error(:no_end), "%p{:a => 'b',\n:c => 'd'}/ e" => [error(:self_closing_content), 2], "%p{:a => 'b',\n:c => 'd'}=" => [error(:no_ruby_code, '='), 2], "%p.{:a => 'b',\n:c => 'd'} e" => [error(:illegal_element), 1], "%p{:a => 'b',\n:c => 'd',\n:e => 'f'}\n%p/ a" => [error(:self_closing_content), 4], "%p{:a => 'b',\n:c => 'd',\n:e => 'f'}\n- raise 'foo'" => ["foo", 4], "%p{:a => 'b',\n:c => raise('foo'),\n:e => 'f'}" => ["foo", 2], "%p{:a => 'b',\n:c => 'd',\n:e => raise('foo')}" => ["foo", 3], " \n\t\n %p foo" => [error(:indenting_at_start), 3], "\n\n %p foo" => [error(:indenting_at_start), 3], "%p\n foo\n foo" => [error(:inconsistent_indentation, "1 space", "2 spaces"), 3], "%p\n foo\n%p\n foo" => [error(:inconsistent_indentation, "1 space", "2 spaces"), 4], "%p\n\t\tfoo\n\tfoo" => [error(:inconsistent_indentation, "1 tab", "2 tabs"), 3], "%p\n foo\n foo" => [error(:inconsistent_indentation, "3 spaces", "2 spaces"), 3], "%p\n foo\n %p\n bar" => [error(:inconsistent_indentation, "3 spaces", "2 spaces"), 4], "%p\n :plain\n bar\n \t baz" => [error(:inconsistent_indentation, '" \t "', "2 spaces"), 4], "%p\n foo\n%p\n bar" => [error(:deeper_indenting, 2), 4], "%p\n foo\n %p\n bar" => [error(:deeper_indenting, 3), 4], "%p\n \tfoo" => [error(:cant_use_tabs_and_spaces), 2], "%p(" => error(:invalid_attribute_list, '"("'), "%p(foo=)" => error(:invalid_attribute_list, '"(foo=)"'), "%p(foo 'bar')" => error(:invalid_attribute_list, '"(foo \'bar\')"'), "%p(foo=\nbar)" => [error(:invalid_attribute_list, '"(foo="'), 1], "%p(foo 'bar'\nbaz='bang')" => [error(:invalid_attribute_list, '"(foo \'bar\'"'), 1], "%p(foo='bar'\nbaz 'bang'\nbip='bop')" => [error(:invalid_attribute_list, '"(foo=\'bar\' baz \'bang\'"'), 2], "%p{'foo' => 'bar' 'bar' => 'baz'}" => :compile, "%p{:foo => }" => :compile, "%p{=> 'bar'}" => :compile, "%p{'foo => 'bar'}" => error(:unbalanced_brackets), "%p{:foo => 'bar}" => error(:unbalanced_brackets), "%p{:foo => 'bar\"}" => error(:unbalanced_brackets), # Regression tests "foo\n\n\n bar" => [error(:illegal_nesting_plain), 4], "%p/\n\n bar" => [error(:illegal_nesting_self_closing), 3], "%p foo\n\n bar" => [error(:illegal_nesting_line, 'p'), 3], "/ foo\n\n bar" => [error(:illegal_nesting_content), 3], "!!!\n\n bar" => [error(:illegal_nesting_header), 3], "- raise 'foo'\n\n\n\nbar" => ["foo", 1], "= 'foo'\n-raise 'foo'" => ["foo", 2], "\n\n\n- raise 'foo'" => ["foo", 4], "%p foo |\n bar |\n baz |\nbop\n- raise 'foo'" => ["foo", 5], #"foo\n:ruby\n 1\n 2\n 3\n- raise 'foo'" => ["foo", 6], #"foo\n:erb\n 1\n 2\n 3\n- raise 'foo'" => ["foo", 6], "foo\n:plain\n 1\n 2\n 3\n- raise 'foo'" => ["foo", 6], "foo\n:plain\n 1\n 2\n 3\n4\n- raise 'foo'" => ["foo", 7], "foo\n:plain\n 1\n 2\n 3\#{''}\n- raise 'foo'" => ["foo", 6], "foo\n:plain\n 1\n 2\n 3\#{''}\n4\n- raise 'foo'" => ["foo", 7], "foo\n:plain\n 1\n 2\n \#{raise 'foo'}" => ["foo", 5], "= raise 'foo'\nfoo\nbar\nbaz\nbang" => ["foo", 1], "- case 1\n\n- when 1\n - raise 'foo'" => ["foo", 4], } User = Struct.new('User', :id) class CustomHamlClass < Struct.new(:id) def haml_object_ref "my_thing" end end CpkRecord = Struct.new('CpkRecord', :id) do def to_key [*self.id] unless id.nil? end end def use_test_tracing(options) unless options[:filename] # use caller method name as fake filename. useful for debugging i = -1 caller[i+=1] =~ /`(.+?)'/ until $1 and $1.index('test_') == 0 options[:filename] = "(#{$1})" end options end def render(text, options = {}, &block) options = use_test_tracing(options) super end def engine(text, options = {}) options = use_test_tracing(options) Hamlit::Template.new(hamlit_base.merge(options)) { text } end def setup @old_default_internal = Encoding.default_internal silence_warnings{Encoding.default_internal = nil} end def teardown silence_warnings{Encoding.default_internal = @old_default_internal} end def test_empty_render assert_equal "", render("") end def test_flexible_tabulation assert_haml_ugly("%p\n foo\n%q\n bar\n %a\n baz") assert_haml_ugly("%p\n\tfoo\n%q\n\tbar\n\t%a\n\t\tbaz") assert_haml_ugly("%p\n :plain\n \t \t bar\n baz") end def test_empty_render_should_remain_empty assert_equal('', render('')) end def test_attributes_should_render_correctly assert_equal("
", render(".atlantis{:style => 'ugly'}").chomp) end def test_css_id_as_attribute_should_be_appended_with_underscore assert_equal("
", render("#my_id{:id => '1'}").chomp) assert_equal("
", render("#my_id{:id => 1}").chomp) end def test_ruby_code_should_work_inside_attributes assert_equal("

foo

", render("%p{:class => 1+2} foo").chomp) end def test_class_attr_with_array assert_equal("

foo

\n", render("%p{:class => %w[a b]} foo")) # basic assert_equal("

foo

\n", render("%p.css{:class => %w[a b]} foo")) # merge with css assert_equal("

foo

\n", render("%p.css{:class => %w[css b]} foo")) # merge uniquely assert_equal("

foo

\n", render("%p{:class => [%w[a b], %w[c d]]} foo")) # flatten assert_equal("

foo

\n", render("%p{:class => [:a, :b] } foo")) # stringify # [INCOMPATIBILITY] Hamlit limits boolean attributes # assert_equal("

foo

\n", render("%p{:class => [nil, false] } foo")) # strip falsey assert_equal("

foo

\n", render("%p{:class => [nil, false] } foo")) # strip falsey assert_equal("

foo

\n", render("%p{:class => :a} foo")) # single stringify # [INCOMPATIBILITY] Hamlit limits boolean attributes # assert_equal("

foo

\n", render("%p{:class => false} foo")) # single falsey assert_equal("

foo

\n", render("%p{:class => false} foo")) # single falsey assert_equal("

foo

\n", render("%p(class='html'){:class => %w[a b]} foo")) # html attrs end def test_id_attr_with_array assert_equal("

foo

\n", render("%p{:id => %w[a b]} foo")) # basic assert_equal("

foo

\n", render("%p#css{:id => %w[a b]} foo")) # merge with css assert_equal("

foo

\n", render("%p{:id => [%w[a b], %w[c d]]} foo")) # flatten assert_equal("

foo

\n", render("%p{:id => [:a, :b] } foo")) # stringify # [INCOMPATIBILITY] Hamlit limits boolean attributes # assert_equal("

foo

\n", render("%p{:id => [nil, false] } foo")) # strip falsey assert_equal("

foo

\n", render("%p{:id => [nil, false] } foo")) # strip falsey assert_equal("

foo

\n", render("%p{:id => :a} foo")) # single stringify # [INCOMPATIBILITY] Hamlit limits boolean attributes # assert_equal("

foo

\n", render("%p{:id => false} foo")) # single falsey assert_equal("

foo

\n", render("%p{:id => false} foo")) # single falsey assert_equal("

foo

\n", render("%p(id='html'){:id => %w[a b]} foo")) # html attrs end def test_colon_in_class_attr assert_equal("

\n", render("%p.foo:bar/")) end def test_colon_in_id_attr assert_equal("

\n", render("%p#foo:bar/")) end def test_dynamic_attributes_with_no_content assert_haml_ugly(< "http://" + "haml.info"} HAML end def test_attributes_with_to_s assert_equal(<

HTML %p#foo{:id => 1+1} %p.foo{:class => 1+1} %p{:blaz => 1+1} %p{(1+1) => 1+1} HAML end def test_nil_should_render_empty_tag # [INCOMPATIBILITY] Hamlit limits boolean attributes # assert_equal("
", # render(".no_attributes{:nil => nil}").chomp) assert_equal("
", render(".no_attributes{:nil => nil}").chomp) end def test_strings_should_get_stripped_inside_tags assert_equal("
This should have no spaces in front of it
", render(".stripped This should have no spaces in front of it").chomp) end def test_one_liner_should_be_one_line assert_equal("

Hello

", render('%p Hello').chomp) end def test_one_liner_with_newline_shouldnt_be_one_line assert_haml_ugly('%p= "foo\nbar"') end def test_multi_render; skip engine = engine("%strong Hi there!") assert_equal("Hi there!\n", engine.render) assert_equal("Hi there!\n", engine.render) assert_equal("Hi there!\n", engine.render) end def test_interpolation assert_haml_ugly('%p Hello #{who}', locals: {who: 'World'}, escape_html: false) assert_haml_ugly("%p\n Hello \#{who}", locals: {who: 'World'}, escape_html: false) assert_haml_ugly('%p Hello #{who}', locals: {who: 'World'}, escape_html: true) assert_haml_ugly("%p\n Hello \#{who}", locals: {who: 'World'}, escape_html: true) end def test_interpolation_with_instance_var; skip # special interpolation scope = Object.new scope.instance_variable_set(:@who, 'World') assert_equal("

Hello World

\n", render('%p Hello #@who', scope: scope, escape_html: false)) assert_equal("

\n Hello World\n

\n", render("%p\n Hello \#@who", scope: scope, escape_html: false)) assert_equal("

Hello World

\n", render('%p Hello #@who', scope: scope, escape_html: true)) assert_equal("

\n Hello World\n

\n", render("%p\n Hello \#@who", scope: scope, escape_html: true)) end def test_interpolation_with_global; skip # special interpolation $global_var_for_testing = 'World' assert_equal("

Hello World

\n", render('%p Hello #$global_var_for_testing', escape_html: false)) assert_equal("

\n Hello World\n

\n", render("%p\n Hello \#$global_var_for_testing", escape_html: false)) assert_equal("

Hello World

\n", render('%p Hello #$global_var_for_testing', escape_html: true)) assert_equal("

\n Hello World\n

\n", render("%p\n Hello \#$global_var_for_testing", escape_html: true)) ensure $global_var_for_testing = nil end def test_interpolation_in_the_middle_of_a_string assert_equal("\"title 'Title'. \"\n", render("\"title '\#{\"Title\"}'. \"")) end def test_interpolation_with_instance_var_in_the_middle_of_a_string; skip # special interpolation scope = Object.new scope.instance_variable_set(:@title, 'Title') assert_equal("\"title 'Title'. \"\n", render("\"title '\#@title'. \"", :scope => scope)) end def test_interpolation_with_global_in_the_middle_of_a_string; skip # special interpolation $global_var_for_testing = 'Title' assert_equal("\"title 'Title'. \"\n", render("\"title '\#$global_var_for_testing'. \"")) ensure $global_var_for_testing = nil end def test_interpolation_at_the_beginning_of_a_line assert_haml_ugly('%p #{1 + 1}') assert_haml_ugly("%p\n \#{1 + 1}") end def test_interpolation_with_instance_var_at_the_beginning_of_a_line; skip # special interpolation scope = Object.new scope.instance_variable_set(:@foo, 2) assert_equal("

2

\n", render('%p #@foo', :scope => scope)) assert_equal("

\n 2\n

\n", render("%p\n \#@foo", :scope => scope)) end def test_interpolation_with_global_at_the_beginning_of_a_line; skip # special interpolation $global_var_for_testing = 2 assert_equal("

2

\n", render('%p #$global_var_for_testing')) assert_equal("

\n 2\n

\n", render("%p\n \#$global_var_for_testing")) ensure $global_var_for_testing = nil end def test_escaped_interpolation assert_equal("

Foo & Bar & Baz

\n", render('%p& Foo #{"&"} Bar & Baz')) end def test_nil_tag_value_should_render_as_empty assert_equal("

\n", render("%p= nil")) end def test_tag_with_failed_if_should_render_as_empty assert_equal("

\n", render("%p= 'Hello' if false")) end def test_static_attributes_with_empty_attr assert_equal("\n", render("%img{:src => '/foo.png', :alt => ''}")) end def test_dynamic_attributes_with_empty_attr # [INCOMPATIBILITY] Hamlit limits boolean attributes # assert_equal("\n", render("%img{:width => nil, :src => '/foo.png', :alt => String.new}")) assert_equal("\n", render("%img{:width => nil, :src => '/foo.png', :alt => String.new}")) end def test_attribute_hash_with_newlines assert_haml_ugly("%p{:a => 'b',\n :c => 'd'} foop") assert_haml_ugly("%p{:a => 'b',\n :c => 'd'}\n foop") assert_haml_ugly("%p{:a => 'b',\n :c => 'd'}/") assert_haml_ugly("%p{:a => 'b',\n :c => 'd',\n :e => 'f'}") end def test_attr_hashes_not_modified hash = {:color => 'red'} assert_haml_ugly(< {:hash => hash})
HTML %div{hash} .special{hash} %div{hash} HAML assert_equal(hash, {:color => 'red'}) end def test_ugly_semi_prerendered_tags assert_equal(< true))

foo

foo

foo bar

foo bar

foo

HTML %p{:a => 1 + 1} %p{:a => 1 + 1} foo %p{:a => 1 + 1}/ %p{:a => 1 + 1}= "foo" %p{:a => 1 + 1}= "foo\\nbar" %p{:a => 1 + 1}~ "foo\\nbar" %p{:a => 1 + 1} foo HAML end def test_end_of_file_multiline assert_equal("

0

\n

1

\n

2

\n", render("- for i in (0...3)\n %p= |\n i |")) end def test_cr_newline assert_equal("

foo

\n

bar

\n

baz

\n

boom

\n", render("%p foo\r%p bar\r\n%p baz\n\r%p boom")) end def test_textareas; skip # script bug assert_equal("\n", render('%textarea= "Foo\n bar\n baz"')) assert_equal("
Foo
  bar
   baz
\n", render('%pre= "Foo\n bar\n baz"')) assert_equal("\n", render("%textarea #{'a' * 100}")) assert_equal("

\n \n

\n", render(<Foo bar baz HTML %pre %code :preserve Foo bar baz HAML end def test_boolean_attributes # [INCOMPATIBILITY] Hamlit limits boolean attributes # assert_equal("

\n", # render("%p{:foo => 'bar', :bar => true, :baz => 'true'}", :format => :html4)) # assert_equal("

\n", # render("%p{:foo => 'bar', :bar => true, :baz => 'true'}", :format => :xhtml)) # # assert_equal("

\n", # render("%p{:foo => 'bar', :bar => false, :baz => 'false'}", :format => :html4)) # assert_equal("

\n", # render("%p{:foo => 'bar', :bar => false, :baz => 'false'}", :format => :xhtml)) assert_equal("

\n", render("%p{:foo => 'bar', :bar => true, :baz => 'true'}", :format => :html4)) assert_equal("

\n", render("%p{:foo => 'bar', :bar => true, :baz => 'true'}", :format => :xhtml)) assert_equal("

\n", render("%p{:foo => 'bar', :bar => false, :baz => 'false'}", :format => :html4)) assert_equal("

\n", render("%p{:foo => 'bar', :bar => false, :baz => 'false'}", :format => :xhtml)) end def test_nuke_inner_whitespace_in_loops assert_equal(<foobarbaz HTML %ul< - for str in %w[foo bar baz] = str HAML end def test_both_whitespace_nukes_work_together; skip # dynamic indentation assert_equal(<Foo Bar

RESULT %p %q><= "Foo\\nBar" SOURCE end def test_nil_option assert_equal("

\n", render('%p{:foo => "bar"}', :attr_wrapper => nil)) end def test_comment_with_crazy_nesting assert_equal(< 'te'+'st'} = "foo\\nbar" HAML end def test_whitespace_nuke_with_both_newlines; skip # script bug # runtime nuke assert_equal("

foo

\n", render('%p<= "\nfoo\n"')) assert_equal(<

foo

HTML %p %p<= "\\nfoo\\n" HAML end def test_whitespace_nuke_with_tags_and_else assert_haml_ugly(< foo

HTML %p foo = " " %a> HAML end def test_both_case_indentation_work_with_deeply_nested_code assert_haml_ugly(< true)) = capture_haml do foo HAML end def test_plain_equals_with_ugly assert_equal("foo\nbar\n", render(< true)) = "foo" bar HAML end def test_inline_if assert_equal(<One

Three

HTML - for name in ["One", "Two", "Three"] %p= name unless name == "Two" HAML end def test_end_with_method_call; skip # block script # silent script assert_equal(< 2|3|4 b-a-r

HTML %p = [1, 2, 3].map do |i| - i + 1 - end.join("|") = "bar".gsub(/./) do |s| - s + "-" - end.gsub(/-$/) do |s| - '' HAML end def test_silent_end_with_stuff; skip # silent script assert_equal(<hi!

HTML - if true %p hi! - end if "foo".gsub(/f/) do - "z" - end + "bar" HAML end def test_multiline_with_colon_after_filter assert_equal(< "Bar", | :b => "Baz" }[:a] | HAML assert_equal(< "Bar", | :b => "Baz" }[:a] | HAML end def test_multiline_in_filter assert_equal(< false) #foo{:class => ''} bar HAML end def test_escape_attrs_always; skip # attribute escape assert_equal(< :always))
bar
HTML #foo{:class => '"<>&"'} bar HAML end def test_escape_html html = < true)) &= "&" != "&" = "&" HAML assert_equal(html, render(< true)) &~ "&" !~ "&" ~ "&" HAML assert_equal(html, render(< true)) & \#{"&"} ! \#{"&"} \#{"&"} HAML assert_equal(html, render(< true)) &== \#{"&"} !== \#{"&"} == \#{"&"} HAML tag_html = <&

&

&

HTML assert_equal(tag_html, render(< true)) %p&= "&" %p!= "&" %p= "&" HAML assert_equal(tag_html, render(< true)) %p&~ "&" %p!~ "&" %p~ "&" HAML assert_equal(tag_html, render(< true)) %p& \#{"&"} %p! \#{"&"} %p \#{"&"} HAML assert_equal(tag_html, render(< true)) %p&== \#{"&"} %p!== \#{"&"} %p== \#{"&"} HAML end def test_new_attrs_with_hash assert_equal("\n", render('%a(href="#")')) end def test_silent_script_with_hyphen_case assert_equal("", render("- a = 'foo-case-bar-case'")) end def test_silent_script_with_hyphen_end assert_equal("", render("- a = 'foo-end-bar-end'")) end def test_silent_script_with_hyphen_end_and_block; skip # silent script silence_warnings do assert_equal(<foo-end

bar-end

HTML - ("foo-end-bar-end".gsub(/\\w+-end/) do |s| %p= s - end; nil) HAML end end def test_if_without_content_and_else assert_equal(<Foo\n", render('%a(href="#" rel="top") Foo')) assert_equal("Foo\n", render('%a(href="#") #{"Foo"}')) assert_equal("\n", render('%a(href="#\\"")')) end def test_case_assigned_to_var assert_equal(< true)) foo, HTML foo\#{"," if true} HAML end # HTML escaping tests def test_ampersand_equals_should_escape assert_haml_ugly("%p\n &= 'foo & bar'", :escape_html => false) end def test_ampersand_equals_inline_should_escape; skip # script bug assert_equal("

foo & bar

\n", render("%p&= 'foo & bar'", :escape_html => false)) end def test_ampersand_equals_should_escape_before_preserve; skip # script bug assert_equal("\n", render('%textarea&= "foo\nbar"', :escape_html => false)) end def test_bang_equals_should_not_escape assert_haml_ugly("%p\n != 'foo & bar'", :escape_html => true) end def test_bang_equals_inline_should_not_escape assert_equal("

foo & bar

\n", render("%p!= 'foo & bar'", :escape_html => true)) end def test_static_attributes_should_be_escaped; skip # attribute escape assert_equal("\n", render("%img.atlantis{:style => 'ugly&stupid'}")) assert_equal("
foo
\n", render(".atlantis{:style => 'ugly&stupid'} foo")) assert_equal("

foo

\n", render("%p.atlantis{:style => 'ugly&stupid'}= 'foo'")) assert_equal("

\n", render("%p.atlantis{:style => \"ugly\\nstupid\"}")) end def test_dynamic_attributes_should_be_escaped; skip # script bug assert_equal("\n", render("%img{:width => nil, :src => '&foo.png', :alt => String.new}")) assert_equal("

foo

\n", render("%p{:width => nil, :src => '&foo.png', :alt => String.new} foo")) assert_equal("
foo
\n", render("%div{:width => nil, :src => '&foo.png', :alt => String.new}= 'foo'")) assert_equal("\n", render("%img{:width => nil, :src => \"foo\\n.png\", :alt => String.new}")) end def test_string_double_equals_should_be_escaped assert_equal("

4&<

\n", render("%p== \#{2+2}&\#{'<'}", :escape_html => true)) assert_equal("

4&<

\n", render("%p== \#{2+2}&\#{'<'}", :escape_html => false)) end def test_escaped_inline_string_double_equals assert_equal("

4&<

\n", render("%p&== \#{2+2}&\#{'<'}", :escape_html => true)) assert_equal("

4&<

\n", render("%p&== \#{2+2}&\#{'<'}", :escape_html => false)) end def test_unescaped_inline_string_double_equals assert_equal("

4&<

\n", render("%p!== \#{2+2}&\#{'<'}", :escape_html => true)) assert_equal("

4&<

\n", render("%p!== \#{2+2}&\#{'<'}", :escape_html => false)) end def test_escaped_string_double_equals assert_haml_ugly("%p\n &== \#{2+2}&\#{'<'}", :escape_html => true) assert_haml_ugly("%p\n &== \#{2+2}&\#{'<'}", :escape_html => false) end def test_unescaped_string_double_equals assert_haml_ugly("%p\n !== \#{2+2}&\#{'<'}", :escape_html => true) assert_haml_ugly("%p\n !== \#{2+2}&\#{'<'}", :escape_html => false) end def test_string_interpolation_should_be_esaped assert_equal("

4&<

\n", render("%p \#{2+2}&\#{'<'}", :escape_html => true)) assert_equal("

4&<

\n", render("%p \#{2+2}&\#{'<'}", :escape_html => false)) end def test_escaped_inline_string_interpolation assert_equal("

4&<

\n", render("%p& \#{2+2}&\#{'<'}", :escape_html => true)) assert_equal("

4&<

\n", render("%p& \#{2+2}&\#{'<'}", :escape_html => false)) end def test_unescaped_inline_string_interpolation assert_equal("

4&<

\n", render("%p! \#{2+2}&\#{'<'}", :escape_html => true)) assert_equal("

4&<

\n", render("%p! \#{2+2}&\#{'<'}", :escape_html => false)) end def test_escaped_string_interpolation assert_haml_ugly("%p\n & \#{2+2}&\#{'<'}", :escape_html => true) assert_haml_ugly("%p\n & \#{2+2}&\#{'<'}", :escape_html => false) end def test_escaped_string_interpolation_with_no_space assert_equal("<br>\n", render('&#{"
"}')) assert_equal("<br>\n", render('%span&#{"
"}')) end def test_unescaped_string_interpolation assert_haml_ugly("%p\n ! \#{2+2}&\#{'<'}", :escape_html => true) assert_haml_ugly("%p\n ! \#{2+2}&\#{'<'}", :escape_html => false) end def test_unescaped_string_interpolation_with_no_space assert_equal("
\n", render('!#{"
"}')) assert_equal("
\n", render('%span!#{"
"}')) end def test_scripts_should_respect_escape_html_option assert_haml_ugly("%p\n = 'foo & bar'", :escape_html => true) assert_haml_ugly("%p\n = 'foo & bar'", :escape_html => false) end def test_inline_scripts_should_respect_escape_html_option; skip # escape html assert_equal("

foo & bar

\n", render("%p= 'foo & bar'", :escape_html => true)) assert_equal("

foo & bar

\n", render("%p= 'foo & bar'", :escape_html => false)) end def test_script_ending_in_comment_should_render_when_html_is_escaped assert_equal("foo&bar\n", render("= 'foo&bar' #comment", :escape_html => true)) end def test_script_with_if_shouldnt_output assert_equal(<foo

HTML %p= "foo" %p= "bar" if false HAML end # Options tests def test_filename_and_line; skip # options begin render("\n\n = abc", :filename => 'test', :line => 2) rescue Exception => e assert_kind_of Haml::SyntaxError, e assert_match(/test:4/, e.backtrace.first) end begin render("\n\n= 123\n\n= nil[]", :filename => 'test', :line => 2) rescue Exception => e assert_kind_of NoMethodError, e backtrace = e.backtrace backtrace.shift if rubinius? assert_match(/test:6/, backtrace.first) end end def test_stop_eval; skip # options assert_equal("", render("= 'Hello'", :suppress_eval => true)) assert_equal("", render("- haml_concat 'foo'", :suppress_eval => true)) assert_equal("
\n", render("#foo{:yes => 'no'}/", :suppress_eval => true)) assert_equal("
\n", render("#foo{:yes => 'no', :call => a_function() }/", :suppress_eval => true)) assert_equal("
\n", render("%div[1]/", :suppress_eval => true)) assert_equal("", render(":ruby\n Kernel.puts 'hello'", :suppress_eval => true)) end def test_doctypes assert_equal('', render('!!!', :format => :html5).strip) assert_equal('', render('!!! 5').strip) assert_equal('', render('!!! strict', :format => :xhtml).strip) assert_equal('', render('!!! frameset', :format => :xhtml).strip) assert_equal('', render('!!! mobile', :format => :xhtml).strip) assert_equal('', render('!!! basic', :format => :xhtml).strip) assert_equal('', render('!!! transitional', :format => :xhtml).strip) assert_equal('', render('!!!', :format => :xhtml).strip) assert_equal('', render('!!! strict', :format => :html4).strip) assert_equal('', render('!!! frameset', :format => :html4).strip) assert_equal('', render('!!! transitional', :format => :html4).strip) assert_equal('', render('!!!', :format => :html4).strip) end def test_attr_wrapper; skip # options assert_equal("

\n", render("%p{ :strange => 'attrs'}", :attr_wrapper => '*')) assert_equal("

\n", render("%p{ :escaped => 'quo\"te'}", :attr_wrapper => '"')) assert_equal("

\n", render("%p{ :escaped => 'quo\\'te'}", :attr_wrapper => '"')) assert_equal("

\n", render("%p{ :escaped => 'q\\'uo\"te'}", :attr_wrapper => '"')) assert_equal("\n", render("!!! XML", :attr_wrapper => '"', :format => :xhtml)) end def test_autoclose_option assert_equal("\n", render("%flaz{:foo => 'bar'}", :autoclose => ["flaz"])) assert_equal(< [/^flaz/])) HTML %flaz %flaznicate %flan HAML end def test_attrs_parsed_correctly; skip # attribute escape assert_equal("

biddly='bar => baz'>

\n", render("%p{'boom=>biddly' => 'bar => baz'}")) assert_equal("

\n", render("%p{'foo,bar' => 'baz, qux'}")) assert_equal("

\n", render("%p{ :escaped => \"quo\\nte\"}")) assert_equal("

\n", render("%p{ :escaped => \"quo\#{2 + 2}te\"}")) end def test_correct_parsing_with_brackets; skip # script bug assert_equal("

{tada} foo

\n", render("%p{:class => 'foo'} {tada} foo")) assert_equal("

deep {nested { things }}

\n", render("%p{:class => 'foo'} deep {nested { things }}")) assert_equal("

{a { d

\n", render("%p{{:class => 'foo'}, :class => 'bar'} {a { d")) assert_equal("

a}

\n", render("%p{:foo => 'bar'} a}")) foo = [] foo[0] = Struct.new('Foo', :id).new assert_equal("

New User]

\n", render("%p[foo[0]] New User]", :locals => {:foo => foo})) assert_equal("

New User]

\n", render("%p[foo[0], :prefix] New User]", :locals => {:foo => foo})) foo[0].id = 1 assert_equal("

New User]

\n", render("%p[foo[0]] New User]", :locals => {:foo => foo})) assert_equal("

New User]

\n", render("%p[foo[0], :prefix] New User]", :locals => {:foo => foo})) end def test_empty_attrs assert_haml_ugly("%p{ :attr => '' } empty") assert_haml_ugly("%p{ :attr => x } empty", :locals => {:x => ''}) end def test_nil_attrs skip '[INCOMPATIBILITY] Hamlit limits boolean attributes' assert_equal("

nil

\n", render("%p{ :attr => nil } nil")) assert_equal("

nil

\n", render("%p{ :attr => x } nil", :locals => {:x => nil})) end def test_nil_id_with_syntactic_id assert_equal("

nil

\n", render("%p#foo{:id => nil} nil")) assert_equal("

nil

\n", render("%p#foo{{:id => 'bar'}, :id => nil} nil")) assert_equal("

nil

\n", render("%p#foo{{:id => nil}, :id => 'bar'} nil")) end def test_nil_class_with_syntactic_class assert_equal("

nil

\n", render("%p.foo{:class => nil} nil")) assert_equal("

nil

\n", render("%p.bar.foo{:class => nil} nil")) assert_equal("

nil

\n", render("%p.foo{{:class => 'bar'}, :class => nil} nil")) assert_equal("

nil

\n", render("%p.foo{{:class => nil}, :class => 'bar'} nil")) end def test_locals assert_haml_ugly("%p= text", :locals => { :text => "Paragraph!" }) end def test_dynamic_attrs_shouldnt_register_as_literal_values assert_equal("

\n", render('%p{:a => "b#{1 + 1}c"}')) assert_equal("

\n", render("%p{:a => 'b' + (1 + 1).to_s + 'c'}")) end def test_dynamic_attrs_with_self_closed_tag assert_equal("\nc\n", render("%a{'b' => 1 + 1}/\n= 'c'\n")) end EXCEPTION_MAP.each do |key, value| define_method("test_exception (#{key.inspect})") do begin silence_warnings do render(key, :filename => "(test_exception (#{key.inspect}))") end rescue Exception => err value = [value] unless value.is_a?(Array) expected_message, line_no = value line_no ||= key.split("\n").length if expected_message == :compile assert_match(/(compile error|syntax error|unterminated string|expecting)/, err.message, "Line: #{key}") else assert_equal(expected_message, err.message, "Line: #{key}") end else assert(false, "Exception not raised for\n#{key}") end end end def test_exception_map skip EXCEPTION_MAP end def test_exception_line; skip # error render("a\nb\n!!!\n c\nd") rescue Haml::SyntaxError => e assert_equal("(test_exception_line):4", e.backtrace[0]) else assert(false, '"a\nb\n!!!\n c\nd" doesn\'t produce an exception') end def test_exception; skip # error render("%p\n hi\n %a= undefined\n= 12") rescue Exception => e skip backtrace = e.backtrace backtrace.shift if rubinius? assert_match("(test_exception):3", backtrace[0]) else # Test failed... should have raised an exception assert(false) end def test_compile_error; skip # error render("a\nb\n- fee)\nc") rescue Exception => e skip assert_match(/\(test_compile_error\):3:/i, e.message) assert_match(/(syntax error|expecting \$end)/i, e.message) else assert(false, '"a\nb\n- fee)\nc" doesn\'t produce an exception!') end def test_unbalanced_brackets; skip # error render('foo #{1 + 5} foo #{6 + 7 bar #{8 + 9}') rescue Hamlit::SyntaxError => e assert_equal(Hamlit::Error.message(:unbalanced_brackets), e.message) end def test_single_line_comments_are_interpolated; skip # comment assert_equal("\n", render('/ Hello #{1 + 1}')) end def test_single_line_comments_are_not_interpolated_with_suppress_eval; skip # comment assert_equal("\n", render('/ Hello #{1 + 1}', :suppress_eval => true)) end def test_single_line_comments_with_interpolation_dont_break_tabulation; skip # comment assert_equal("\nconcatted\n", render("/ Hello \#{1 + 1}\n- haml_concat 'concatted'")) end def test_balanced_conditional_comments assert_equal("\n", render("/[if !(IE 6)|(IE 7)] Bracket: ]")) end def test_downlevel_revealed_conditional_comments; skip assert_equal(" A comment \n", render("/![if !IE] A comment")) end def test_downlevel_revealed_conditional_comments_block assert_equal("\nA comment\n\n", render("/![if !IE]\n A comment")) end def test_local_assigns_dont_modify_class assert_haml_ugly("= foo", :locals => {:foo => 'bar'}) assert_nil(defined?(foo)) end def test_object_ref_with_nil_id; skip # object reference user = User.new assert_equal("

New User

\n", render("%p[user] New User", :locals => {:user => user})) end def test_object_ref_before_attrs; skip # object reference user = User.new 42 assert_equal("

New User

\n", render("%p[user]{:style => 'width: 100px;'} New User", :locals => {:user => user})) end def test_object_ref_with_custom_haml_class; skip # object reference custom = CustomHamlClass.new 42 assert_equal("

My Thing

\n", render("%p[custom]{:style => 'width: 100px;'} My Thing", :locals => {:custom => custom})) end def test_object_ref_with_multiple_ids; skip # object reference cpk_record = CpkRecord.new([42,6,9]) assert_equal("

CPK Record

\n", render("%p[cpk_record]{:style => 'width: 100px;'} CPK Record", :locals => {:cpk_record => cpk_record})) end def test_non_literal_attributes assert_haml_ugly("%p{a2, a1, :a3 => 'baz'}", :locals => {:a1 => {:a1 => 'foo'}, :a2 => {:a2 => 'bar'}}) end def test_render_should_accept_a_binding_as_scope; skip string = "This is a string!" string.instance_variable_set(:@var, "Instance variable") b = string.instance_eval do var = "Local variable" # Silence unavoidable warning; Ruby doesn't know we're going to use this # later. nil if var binding end assert_haml_ugly("%p= upcase\n%p= @var\n%p= var", :scope => b) end def test_yield_should_work_with_binding; skip # options assert_equal("12\nFOO\n", render("= yield\n= upcase", :scope => "foo".instance_eval{binding}) { 12 }) end def test_yield_should_work_with_def_method; skip # def_method s = "foo" engine("= yield\n= upcase").def_method(s, :render) assert_equal("12\nFOO\n", s.render { 12 }) end def test_def_method_with_module; skip # def_method engine("= yield\n= upcase").def_method(String, :render_haml) assert_equal("12\nFOO\n", "foo".render_haml { 12 }) end def test_def_method_locals; skip # def_method obj = Object.new engine("%p= foo\n.bar{:baz => baz}= boom").def_method(obj, :render, :foo, :baz, :boom) assert_equal("

1

\n
3
\n", obj.render(:foo => 1, :baz => 2, :boom => 3)) end def test_render_proc_locals; skip # render_proc proc = engine("%p= foo\n.bar{:baz => baz}= boom").render_proc(Object.new, :foo, :baz, :boom) assert_equal("

1

\n
3
\n", proc[:foo => 1, :baz => 2, :boom => 3]) end def test_render_proc_with_binding; skip # render_proc assert_equal("FOO\n", engine("= upcase").render_proc("foo".instance_eval{binding}).call) end def test_haml_buffer_gets_reset_even_with_exception; skip # haml_buffer scope = Object.new render("- raise Hamlit::Error", :scope => scope) assert(false, "Expected exception") rescue Exception skip assert_nil(scope.send(:haml_buffer)) end def test_def_method_haml_buffer_gets_reset_even_with_exception; skip # def_method scope = Object.new engine("- raise Hamlit::Error").def_method(scope, :render) scope.render assert(false, "Expected exception") rescue Exception; skip assert_nil(scope.send(:haml_buffer)) end def test_render_proc_haml_buffer_gets_reset_even_with_exception; skip # render_proc scope = Object.new proc = engine("- raise Hamlit::Error").render_proc(scope) proc.call assert(false, "Expected exception") rescue Exception; skip assert_nil(scope.send(:haml_buffer)) end def test_render_proc_should_raise_haml_syntax_error_not_ruby_syntax_error assert_raises(Haml::SyntaxError) do Haml::Engine.new("%p{:foo => !}").render_proc(Object.new, :foo).call end end def test_render_should_raise_haml_syntax_error_not_ruby_syntax_error assert_raises(Haml::SyntaxError) do Haml::Engine.new("%p{:foo => !}").render end end def test_ugly_true assert_equal("
\n
\n

hello world

\n
\n
\n", render("#outer\n #inner\n %p hello world", :ugly => true)) assert_equal("

#{'s' * 75}

\n", render("%p #{'s' * 75}", :ugly => true)) assert_equal("

#{'s' * 75}

\n", render("%p= 's' * 75", :ugly => true)) end def test_remove_whitespace_true; skip # options assert_equal("

hello world

", render("#outer\n #inner\n %p hello world", :remove_whitespace => true)) assert_equal("

hello world

foo   bar\nbaz

", render(< true)) %p hello world %pre foo bar baz HAML assert_equal("
foo bar
", render('%div foo bar', :remove_whitespace => true)) end def test_auto_preserve_unless_ugly; skip # preserve assert_equal("
foo
bar
\n", render('%pre="foo\nbar"')) assert_equal("
foo\nbar
\n", render("%pre\n foo\n bar")) assert_equal("
foo\nbar
\n", render('%pre="foo\nbar"', :ugly => true)) assert_equal("
foo\nbar
\n", render("%pre\n foo\n bar", :ugly => true)) end def test_xhtml_output_option assert_haml_ugly("%p\n %br", :format => :xhtml) assert_haml_ugly("%a/", :format => :xhtml) end def test_arbitrary_output_option; skip # error assert_raises_message(Hamlit::Error, "Invalid output format :html1") do engine("%br", :format => :html1) end end def test_static_hashes assert_equal("
\n", render("%a{:b => 'a => b'}", :suppress_eval => true)) assert_equal("\n", render("%a{:b => 'a, b'}", :suppress_eval => true)) assert_equal("\n", render('%a{:b => "a\tb"}', :suppress_eval => true)) assert_equal("\n", render('%a{:b => "a\\#{foo}b"}', :suppress_eval => true)) assert_equal("\n", render("%a{:b => '#f00'}", :suppress_eval => true)) end def test_dynamic_hashes_with_suppress_eval; skip # options assert_equal("\n", render('%a{:b => "a #{1 + 1} b", :c => "d"}', :suppress_eval => true)) end def test_interpolates_instance_vars_in_attribute_values; skip # special interpolation scope = Object.new scope.instance_variable_set :@foo, 'bar' assert_haml_ugly('%a{:b => "a #@foo b"}', :scope => scope) end def test_interpolates_global_vars_in_attribute_values # make sure the value isn't just interpolated in during template compilation engine = Haml::Engine.new('%a{:b => "a #$global_var_for_testing b"}') $global_var_for_testing = 'bar' assert_equal("\n", engine.to_html) ensure $global_var_for_testing = nil end def test_utf8_attrs assert_equal("\n", render("%a{:href => 'héllo'}")) assert_equal("\n", render("%a(href='héllo')")) end # HTML 4.0 def test_html_has_no_self_closing_tags assert_haml_ugly("%p\n %br", :format => :html4) assert_haml_ugly("%br/", :format => :html4) end def test_html_renders_empty_node_with_closing_tag assert_equal "
\n", render(".foo", :format => :html4) end def test_html_doesnt_add_slash_to_self_closing_tags assert_equal "\n", render("%a/", :format => :html4) assert_equal "\n", render("%a{:foo => 1 + 1}/", :format => :html4) assert_equal "\n", render("%meta", :format => :html4) assert_equal "\n", render("%meta{:foo => 1 + 1}", :format => :html4) end def test_html_ignores_xml_prolog_declaration assert_equal "", render('!!! XML', :format => :html4) end def test_html_has_different_doctype assert_equal %{\n}, render('!!!', :format => :html4) end # because anything before the doctype triggers quirks mode in IE def test_xml_prolog_and_doctype_dont_result_in_a_leading_whitespace_in_html refute_match(/^\s+/, render("!!! xml\n!!!", :format => :html4)) end # HTML5 def test_html5_doctype assert_equal %{\n}, render('!!!', :format => :html5) end # HTML5 custom data attributes def test_html5_data_attributes_without_hyphenation; skip # hyphenate assert_equal("
\n", render("%div{:data => {:author_id => 123, :foo => 'bar', :biz => 'baz'}}", :hyphenate_data_attrs => false)) assert_equal("
\n", render("%div{:data => {:one_plus_one => 1+1}}", :hyphenate_data_attrs => false)) assert_equal("
\n", render(%{%div{:data => {:foo => %{Here's a "quoteful" string.}}}}, :hyphenate_data_attrs => false)) #' end def test_html5_data_attributes_with_hyphens assert_equal("
\n", render("%div{:data => {:foo_bar => 'blip'}}")) assert_equal("
\n", render("%div{:data => {:foo_bar => 'blip', :baz => 'bang'}}")) end def test_html5_arbitrary_hash_valued_attributes_with skip '[INCOMPATIBILITY] Hamlit supports hyphenation only for data attributes' assert_equal("
\n", render("%div{:aria => {:foo => 'blip'}}")) assert_equal("
\n", render("%div{:foo => {:baz => 'bang'}}")) end def test_arbitrary_attribute_hash_merging skip '[INCOMPATIBILITY] Hamlit supports hyphenation only for data attributes' assert_equal(%Q{
\n}, render(<<-HAML)) - h1 = {:aria => {:foo => :bar}} - h2 = {:baz => :qux} %a{h1, :aria => h2} HAML end def test_html5_data_attributes_with_nested_hash; skip # cyclic reference assert_equal("
\n", render(<<-HAML)) - hash = {:a => {:b => 'c'}} - hash[:d] = hash %div{:data => hash} HAML end def test_html5_data_attributes_with_nested_hash_and_without_hyphenation; skip # hyphenate assert_equal("
\n", render(<<-HAML, :hyphenate_data_attrs => false)) - hash = {:a => {:b => 'c'}} - hash[:d] = hash %div{:data => hash} HAML end def test_html5_data_attributes_with_multiple_defs; skip # hyphenate # Should always use the more-explicit attribute assert_equal("
\n", render("%div{:data => {:foo => 'first'}, 'data-foo' => 'second'}")) assert_equal("
\n", render("%div{'data-foo' => 'first', :data => {:foo => 'second'}}")) end def test_html5_data_attributes_with_attr_method; skip # runtime attribute obj = Object.new def obj.data_hash {:data => {:foo => "bar", :baz => "bang"}} end def obj.data_val {:data => "dat"} end assert_equal("
\n", render("%div{data_hash, :data => {:foo => 'blip', :brat => 'wurst'}}", scope: obj)) assert_equal("
\n", render("%div{data_hash, 'data-foo' => 'blip'}", scope: obj)) assert_equal("
\n", render("%div{data_hash, :data => 'dat'}", scope: obj)) assert_equal("
\n", render("%div{data_val, :data => {:foo => 'blip', :brat => 'wurst'}}", scope: obj)) end def test_html5_data_attributes_with_identical_attribute_values assert_equal("
\n", render("%div{:data => {:x => 50, :y => 50}}")) end def test_xml_doc_using_html5_format_and_mime_type; skip # mime_type assert_equal(< :html5, :mime_type => 'text/xml' }))
XML !!! XML %root %element/ %hr HAML end def test_xml_doc_using_html4_format_and_mime_type; skip # mime_type assert_equal(< :html4, :mime_type => 'text/xml' }))
XML !!! XML %root %element/ %hr HAML end # New attributes def test_basic_new_attributes assert_equal("bar\n", render("%a() bar")) assert_equal("bar\n", render("%a(href='foo') bar")) assert_equal("baz\n", render(%q{%a(b="c" c='d' d="e") baz})) end def test_new_attribute_ids; skip # object reference assert_equal("
\n", render("#foo(id='bar')")) assert_equal("
\n", render("#foo{:id => 'bar'}(id='baz')")) assert_equal("
\n", render("#foo(id='baz'){:id => 'bar'}")) foo = User.new(42) assert_equal("
\n", render("#foo(id='baz'){:id => 'bar'}[foo]", :locals => {:foo => foo})) assert_equal("
\n", render("#foo(id='baz')[foo]{:id => 'bar'}", :locals => {:foo => foo})) assert_equal("
\n", render("#foo[foo](id='baz'){:id => 'bar'}", :locals => {:foo => foo})) assert_equal("
\n", render("#foo[foo]{:id => 'bar'}(id='baz')", :locals => {:foo => foo})) end def test_new_attribute_classes; skip # object reference assert_equal("
\n", render(".foo(class='bar')")) assert_equal("
\n", render(".foo{:class => 'bar'}(class='baz')")) assert_equal("
\n", render(".foo(class='baz'){:class => 'bar'}")) foo = User.new(42) assert_equal("
\n", render(".foo(class='baz'){:class => 'bar'}[foo]", :locals => {:foo => foo})) assert_equal("
\n", render(".foo[foo](class='baz'){:class => 'bar'}", :locals => {:foo => foo})) assert_equal("
\n", render(".foo[foo]{:class => 'bar'}(class='baz')", :locals => {:foo => foo})) end def test_dynamic_new_attributes assert_haml_ugly("%a(href=foo) bar", :locals => {:foo => 12}) assert_haml_ugly("%a(b=b c='13' d=d) bar", :locals => {:b => 12, :d => 14}) end def test_new_attribute_interpolation assert_haml_ugly('%a(href="1#{1 + 1}") bar') assert_haml_ugly(%q{%a(href='2: #{1 + 1}, 3: #{foo}') bar}, :locals => {:foo => 3}) assert_haml_ugly('%a(href="1\#{1 + 1}") bar') end def test_truthy_new_attributes; skip # xhtml assert_equal("bar\n", render("%a(href) bar", :format => :xhtml)) assert_equal("bar\n", render("%a(href bar='baz') bar", :format => :html5)) assert_equal("bar\n", render("%a(href=true) bar")) assert_equal("bar\n", render("%a(href=false) bar")) end def test_new_attribute_parsing; skip # attribute escape assert_equal("bar\n", render("%a(a2=b2) bar", :locals => {:b2 => 'b2'})) assert_equal(%Q{bar\n}, render(%q{%a(a="#{'foo"bar'}") bar})) #' assert_equal(%Q{bar\n}, render(%q{%a(a="#{"foo'bar"}") bar})) #' assert_equal(%Q{bar\n}, render(%q{%a(a='foo"bar') bar})) assert_equal(%Q{bar\n}, render(%q{%a(a="foo'bar") bar})) assert_equal("bar\n", render("%a(a:b='foo') bar")) assert_equal("bar\n", render("%a(a = 'foo' b = 'bar') bar")) assert_equal("bar\n", render("%a(a = foo b = bar) bar", :locals => {:foo => 'foo', :bar => 'bar'})) assert_equal("(b='bar')\n", render("%a(a='foo')(b='bar')")) assert_equal("baz\n", render("%a(a='foo)bar') baz")) assert_equal("baz\n", render("%a( a = 'foo' ) baz")) end def test_new_attribute_escaping; skip # attribute escape assert_equal(%Q{bar\n}, render(%q{%a(a="foo \" bar") bar})) assert_equal(%Q{bar\n}, render(%q{%a(a="foo \\\\\" bar") bar})) assert_equal(%Q{bar\n}, render(%q{%a(a='foo \' bar') bar})) assert_equal(%Q{bar\n}, render(%q{%a(a='foo \\\\\' bar') bar})) assert_equal(%Q{bar\n}, render(%q{%a(a="foo \\\\ bar") bar})) assert_equal(%Q{bar\n}, render(%q{%a(a="foo \#{1 + 1} bar") bar})) end def test_multiline_new_attribute assert_haml_ugly("%a(a='b'\n c='d') bar") assert_haml_ugly("%a(a='b' b='c'\n c='d' d=e\n e='f' f='j') bar", :locals => {:e => 'e'}) end def test_new_and_old_attributes assert_haml_ugly("%a(a='b'){:c => 'd'} bar") assert_haml_ugly("%a{:c => 'd'}(a='b') bar") assert_haml_ugly("%a(c='d'){:a => 'b'} bar") assert_haml_ugly("%a{:a => 'b'}(c='d') bar") # Old-style always takes precedence over new-style, # because theoretically old-style could have arbitrary end-of-method-call syntax. assert_haml_ugly("%a{:a => 'b'}(a='d') bar") assert_haml_ugly("%a(a='d'){:a => 'b'} bar") assert_haml_ugly("%a{:a => 'b',\n:b => 'c'}(c='d'\nd='e') bar") locals = {:b => 'b', :d => 'd'} assert_haml_ugly("%p{:a => b}(c=d)", :locals => locals) assert_haml_ugly("%p(a=b){:c => d}", :locals => locals) end # Ruby Multiline def test_silent_ruby_multiline assert_equal(<foo

HTML - foo = ["bar", "baz", "bang"] = foo.join(", ") %p foo HAML end def test_loud_ruby_multiline assert_equal(<foo

bar

HTML = ["bar", "baz", "bang"].join(", ") %p foo %p bar HAML end def test_ruby_multiline_with_punctuated_methods_is_continuation assert_equal(<foo

bar

HTML = ["bar", " ".strip, "".empty?, "bang"].join(", ") %p foo %p bar HAML end def test_ruby_character_literals_are_not_continuation html = ",\n,\n

foo

\n" assert_equal(html, render(<foo

bar

HTML &= ["bar<", "baz", "bang"].join(", ") %p foo %p bar HAML end def test_unescaped_loud_ruby_multiline assert_equal(< true)) bar<, baz, bang

foo

bar

HTML != ["bar<", "baz", "bang"].join(", ") %p foo %p bar HAML end def test_flattened_loud_ruby_multiline assert_equal(<bar baz bang

foo

bar

HTML ~ "
" + ["bar",
             "baz",
             "bang"].join("\\n") + "
" %p foo %p bar HAML end def test_loud_ruby_multiline_with_block; skip # block script assert_equal(<foo

bar

HTML = ["bar", "baz", "bang"].map do |str| - str.gsub("ba", "fa") %p foo %p bar HAML end def test_silent_ruby_multiline_with_block assert_equal(<foo

bar

HTML - ["bar", "baz", "bang"].map do |str| = str.gsub("ba", "fa") %p foo %p bar HAML end def test_ruby_multiline_in_tag assert_equal(<foo, bar, baz

foo

bar

HTML %p= ["foo", "bar", "baz"].join(", ") %p foo %p bar HAML end def test_escaped_ruby_multiline_in_tag; skip # script bug assert_equal(<foo<, bar, baz

foo

bar

HTML %p&= ["foo<", "bar", "baz"].join(", ") %p foo %p bar HAML end def test_unescaped_ruby_multiline_in_tag assert_equal(< true))

foo<, bar, baz

foo

bar

HTML %p!= ["foo<", "bar", "baz"].join(", ") %p foo %p bar HAML end def test_ruby_multiline_with_normal_multiline assert_equal(<foo

bar

HTML = "foo" + | "bar" + | ["bar", | "baz", "bang"].join(", ") %p foo %p bar HAML end def test_ruby_multiline_after_filter assert_equal(<foo

bar

HTML :plain foo bar = ["bar", "baz", "bang"].join(", ") %p foo %p bar HAML end # Encodings def test_utf_8_bom; # encoding assert_equal <

baz

HTML \xEF\xBB\xBF.foo %p baz HAML end def test_default_encoding assert_equal(Encoding.find("utf-8"), render(< "ascii-8bit"))

bâr

föö

HTML %p bâr %p föö HAML end def test_convert_template_render_proc assert_converts_template_properly {|e| e.render_proc.call} end def test_convert_template_render assert_converts_template_properly {|e| e.render} end def test_convert_template_def_method assert_converts_template_properly do |e| o = Object.new e.def_method(o, :render) o.render end end def test_encoding_error # encoding render("foo\nbar\nb\xFEaz".dup.force_encoding("utf-8")) assert(false, "Expected exception") rescue Hamlit::Error => e assert_equal(3, e.line) assert_match(/Invalid .* character/, e.message) end def test_ascii_incompatible_encoding_error; skip # encoding template = "foo\nbar\nb_z".encode("utf-16le") template[9] = "\xFE".force_encoding("utf-16le") render(template) assert(false, "Expected exception") rescue Hamlit::Error => e assert_equal(3, e.line) assert_match(/Invalid .* character/, e.message) end def test_same_coding_comment_as_encoding assert_renders_encoded(<bâr

föö

HTML -# coding: utf-8 %p bâr %p föö HAML end def test_coding_comments; skip # encoding assert_valid_encoding_comment("-# coding: ibm866") assert_valid_encoding_comment("-# CodINg: IbM866") assert_valid_encoding_comment("-#coding:ibm866") assert_valid_encoding_comment("-# CodINg= ibm866") assert_valid_encoding_comment("-# foo BAR FAOJcoding: ibm866") assert_valid_encoding_comment("-# coding: ibm866 ASFJ (&(&#!$") assert_valid_encoding_comment("-# -*- coding: ibm866") assert_valid_encoding_comment("-# coding: ibm866 -*- coding: blah") assert_valid_encoding_comment("-# -*- coding: ibm866 -*-") assert_valid_encoding_comment("-# -*- encoding: ibm866 -*-") assert_valid_encoding_comment('-# -*- coding: "ibm866" -*-') assert_valid_encoding_comment("-#-*-coding:ibm866-*-") assert_valid_encoding_comment("-#-*-coding:ibm866-*-") assert_valid_encoding_comment("-# -*- foo: bar; coding: ibm866; baz: bang -*-") assert_valid_encoding_comment("-# foo bar coding: baz -*- coding: ibm866 -*-") assert_valid_encoding_comment("-# -*- coding: ibm866 -*- foo bar coding: baz") end def test_different_coding_than_system; skip # encoding assert_renders_encoded(<тАЬ

HTML %p тАЬ HAML end def test_block_spacing begin assert render(<<-HAML) - foo = ["bar", "baz", "kni"] - foo.each do | item | = item HAML rescue ::SyntaxError flunk("Should not have raised syntax error") end end def test_tracing; skip # options result = render('%p{:class => "hello"}', :trace => true, :filename => 'foo').strip assert_equal "

", result end private def assert_valid_encoding_comment(comment) assert_renders_encoded(<ЖЛЫ

тАЬ

HTML #{comment} %p ЖЛЫ %p тАЬ HAML end def assert_converts_template_properly engine = Haml::Engine.new(< "macRoman") %p bâr %p föö HAML assert_encoded_equal(<bâr

föö

HTML end def assert_renders_encoded(html, haml) result = render(haml) assert_encoded_equal html, result end def assert_encoded_equal(expected, actual) assert_equal expected.encoding, actual.encoding assert_equal expected, actual end end if RUBY_ENGINE != 'truffleruby' # truffleruby cannot run Haml hamlit-2.15.1/test/haml/erb/000077500000000000000000000000001407657076200155445ustar00rootroot00000000000000hamlit-2.15.1/test/haml/erb/_av_partial_1.erb000066400000000000000000000004431407657076200207400ustar00rootroot00000000000000

This is a pretty complicated partial

It has several nested partials,

    <% 5.times do %>
  • Partial: <% @nesting = 5 %> <%= render :partial => 'erb/av_partial_2' %> <% end %>
hamlit-2.15.1/test/haml/erb/_av_partial_2.erb000066400000000000000000000003651407657076200207440ustar00rootroot00000000000000<% @nesting -= 1 %>

This is a crazy deep-nested partial.

Nesting level <%= @nesting %>

<% if @nesting > 0 %> <%= render :partial => 'erb/av_partial_2' %> <% end %>
hamlit-2.15.1/test/haml/erb/action_view.erb000066400000000000000000000042331407657076200205470ustar00rootroot00000000000000 Hampton Catlin Is Totally Awesome

This is very much like the standard template, except that it has some ActionView-specific stuff. It's only used for benchmarking.

<%= render :partial => 'erb/av_partial_1' %>
Yes, ladies and gentileman. He is just that egotistical. Fantastic! This should be multi-line output The question is if this would translate! Ahah! <%= 1 + 9 + 8 + 2 %> <%# numbers should work and this should be ignored %>
<% 120.times do |number| -%> <%= number %> <% end -%>
<%= " Quotes should be loved! Just like people!" %>
Wow.

<%= "Holy cow " + "multiline " + "tags! " + "A pipe (|) even!" %> <%= [1, 2, 3].collect { |n| "PipesIgnored|" } %> <%= [1, 2, 3].collect { |n| n.to_s }.join("|") %>

<% foo = String.new foo << "this" foo << " shouldn't" foo << " evaluate" %> <%= foo + "but now it should!" %> <%# Woah crap a comment! %>
    <% ('a'..'f').each do |a|%>
  • <%= a %> <% end %>
    <%= @should_eval = "with this text" %>
    <%= [ 104, 101, 108, 108, 111 ].map do |byte| byte.chr end %> hamlit-2.15.1/test/haml/erb/standard.erb000066400000000000000000000037171407657076200200460ustar00rootroot00000000000000 Hampton Catlin Is Totally Awesome
    Yes, ladies and gentileman. He is just that egotistical. Fantastic! This should be multi-line output The question is if this would translate! Ahah! <%= 1 + 9 + 8 + 2 %> <%# numbers should work and this should be ignored %>
    <% 120.times do |number| -%> <%= number %> <% end -%>
    <%= " Quotes should be loved! Just like people!" %>
    Wow.

    <%= "Holy cow " + "multiline " + "tags! " + "A pipe (|) even!" %> <%= [1, 2, 3].collect { |n| "PipesIgnored|" }.join %> <%= [1, 2, 3].collect { |n| n.to_s }.join("|") %>

    <% bar = 17 %>
    <% foo = String.new foo << "this" foo << " shouldn't" foo << " evaluate" %> <%= foo + "but now it should!" %> <%# Woah crap a comment! %>
      <% ('a'..'f').each do |a|%>
    • <%= a %>
    • <% end %>
      <%= @should_eval = "with this text" %>
      <%= "foo".each_line do |line| nil end %> hamlit-2.15.1/test/haml/filters_test.rb000066400000000000000000000203211407657076200200260ustar00rootroot00000000000000require 'test_helper' class FiltersTest < Haml::TestCase test "should be registered as filters when including Hamlit::Filters::Base" do; skip begin refute Hamlit::Filters.defined.has_key? "bar" Module.new {def self.name; "Foo::Bar"; end; include Hamlit::Filters::Base} assert Hamlit::Filters.defined.has_key? "bar" ensure Hamlit::Filters.remove_filter "Bar" end end test "should raise error when attempting to register a defined Tilt filter" do; skip begin assert_raises RuntimeError do 2.times do Hamlit::Filters.register_tilt_filter "Foo" end end ensure Hamlit::Filters.remove_filter "Foo" end end test "should raise error when a Tilt filters dependencies are unavailable for extension" do; skip begin assert_raises Hamlit::Error do # ignore warnings from Tilt silence_warnings do Hamlit::Filters.register_tilt_filter "Textile" Hamlit::Filters.defined["textile"].template_class end end ensure Hamlit::Filters.remove_filter "Textile" end end test "should raise error when a Tilt filters dependencies are unavailable for filter without extension" do; skip begin assert_raises Hamlit::Error do Hamlit::Filters.register_tilt_filter "Maruku" Hamlit::Filters.defined["maruku"].template_class end ensure Hamlit::Filters.remove_filter "Maruku" end end test "should raise informative error about Maruku being moved to haml-contrib" do; skip begin render(":maruku\n # foo") flunk("Should have raised error with message about the haml-contrib gem.") rescue Hamlit::Error => e assert_equal e.message, Hamlit::Error.message(:install_haml_contrib, "maruku") end end test "should raise informative error about Textile being moved to haml-contrib" do; skip begin render(":textile\n h1. foo") flunk("Should have raised error with message about the haml-contrib gem.") rescue Hamlit::Error => e assert_equal e.message, Hamlit::Error.message(:install_haml_contrib, "textile") end end test "should respect escaped newlines and interpolation" do assert_haml_ugly(":plain\n \\n\#{""}") end test "should process an filter with no content" do assert_equal("\n", render(':plain')) end test "should be compatible with ugly mode" do expectation = "foo\n" assert_equal(expectation, render(":plain\n foo")) end test "should pass options to Tilt filters that precompile" do; skip begin orig_erb_opts = Hamlit::Filters::Erb.options haml = ":erb\n <%= 'foo' %>" refute_match('test_var', Haml::Engine.new(haml).compiler.precompiled) Hamlit::Filters::Erb.options = {:outvar => 'test_var'} assert_match('test_var', Haml::Engine.new(haml).compiler.precompiled) ensure Hamlit::Filters::Erb.options = orig_erb_opts end end test "should pass options to Tilt filters that don't precompile" do; skip begin filter = Class.new(Tilt::Template) do def self.name "Foo" end def prepare @engine = {:data => data, :options => options} end def evaluate(scope, locals, &block) @output = @engine[:options].to_a.join end end Hamlit::Filters.register_tilt_filter "Foo", :template_class => filter Hamlit::Filters::Foo.options[:foo] = "bar" haml = ":foo" assert_equal "foobar\n", render(haml) ensure Hamlit::Filters.remove_filter "Foo" end end test "interpolated code should be escaped if escape_html is set" do; skip assert_haml_ugly(":plain\n \#{''}") end end if RUBY_ENGINE != 'truffleruby' # truffleruby does not implement Ripper.lex class ErbFilterTest < Haml::TestCase test "multiline expressions should work" do; skip assert_haml_ugly(%Q{:erb\n <%= "foo" +\n "bar" +\n "baz" %>}) end test "should evaluate in the same context as Haml" do; skip haml = ":erb\n <%= foo %>" html = "bar\n" scope = Object.new.instance_eval {foo = "bar"; nil if foo; binding} assert_equal(html, render(haml, :scope => scope)) end test "should use Rails's XSS safety features" do; skip assert_equal("<img>\n", render(":erb\n <%= '' %>")) assert_equal("\n", render(":erb\n <%= ''.html_safe %>")) end end class JavascriptFilterTest < Haml::TestCase test "should interpolate" do; skip scope = Object.new.instance_eval {foo = "bar"; nil if foo; binding} haml = ":javascript\n \#{foo}" html = render(haml, :scope => scope) assert_match(/bar/, html) end test "should never HTML-escape non-interpolated ampersands" do; skip html = "\n" haml = %Q{:javascript\n & < > \#{"&"}} assert_equal(html, render(haml, :escape_html => true)) end test "should not include type in HTML 5 output" do html = "\n" haml = ":javascript\n foo bar" assert_equal(html, render(haml, :format => :html5)) end test "should always include CDATA when format is xhtml" do html = "\n" haml = ":javascript\n foo bar" assert_equal(html, render(haml, :format => :xhtml, :cdata => false)) end test "should omit CDATA when cdata option is false" do html = "\n" haml = ":javascript\n foo bar" assert_equal(html, render(haml, :format => :html5, :cdata => false)) end test "should include CDATA when cdata option is true" do; skip html = "\n" haml = ":javascript\n foo bar" assert_equal(html, render(haml, :format => :html5, :cdata => true)) end test "should default to no CDATA when format is html5" do haml = ":javascript\n foo bar" out = render(haml, :format => :html5) refute_match('//', out) end end class CSSFilterTest < Haml::TestCase test "should wrap output in CDATA and a CSS tag when output is XHTML" do html = "\n" haml = ":css\n foo" assert_equal(html, render(haml, :format => :xhtml)) end test "should not include type in HTML 5 output" do html = "\n" haml = ":css\n foo bar" assert_equal(html, render(haml, :format => :html5)) end test "should always include CDATA when format is xhtml" do html = "\n" haml = ":css\n foo bar" assert_equal(html, render(haml, :format => :xhtml, :cdata => false)) end test "should omit CDATA when cdata option is false" do html = "\n" haml = ":css\n foo bar" assert_equal(html, render(haml, :format => :html5, :cdata => false)) end test "should include CDATA when cdata option is true" do; skip html = "\n" haml = ":css\n foo bar" assert_equal(html, render(haml, :format => :html5, :cdata => true)) end test "should default to no CDATA when format is html5" do haml = ":css\n foo bar" out = render(haml, :format => :html5) refute_match('', out) end end class CDATAFilterTest < Haml::TestCase test "should wrap output in CDATA tag" do html = "\n" haml = ":cdata\n foo" assert_equal(html, render(haml)) end end class EscapedFilterTest < Haml::TestCase test "should escape ampersands" do html = "&\n" haml = ":escaped\n &" assert_equal(html, render(haml)) end end class RubyFilterTest < Haml::TestCase test "can write to haml_io" do; skip haml = ":ruby\n haml_io.puts 'hello'\n" html = "hello\n" assert_equal(html, render(haml)) end test "haml_io appends to output" do; skip haml = "hello\n:ruby\n haml_io.puts 'hello'\n" html = "hello\nhello\n" assert_equal(html, render(haml)) end test "can create local variables" do; skip haml = ":ruby\n a = 7\n=a" html = "7\n" assert_equal(html, render(haml)) end end hamlit-2.15.1/test/haml/gemfiles/000077500000000000000000000000001407657076200165675ustar00rootroot00000000000000hamlit-2.15.1/test/haml/gemfiles/.bundle/000077500000000000000000000000001407657076200201165ustar00rootroot00000000000000hamlit-2.15.1/test/haml/gemfiles/.bundle/config000066400000000000000000000000071407657076200213030ustar00rootroot00000000000000--- {} hamlit-2.15.1/test/haml/gemfiles/Gemfile.rails-4.0.x000066400000000000000000000002461407657076200217420ustar00rootroot00000000000000source "https://rubygems.org" if ENV['TRAVIS'] platform :mri_21 do gem 'coveralls', require: false end end gem 'rails', '~> 4.0.0' gemspec :path => '../..' hamlit-2.15.1/test/haml/gemfiles/Gemfile.rails-4.1.x000066400000000000000000000001201407657076200217320ustar00rootroot00000000000000source "https://rubygems.org" gem 'rails', '~> 4.1.0' gemspec :path => '../..' hamlit-2.15.1/test/haml/gemfiles/Gemfile.rails-4.2.x000066400000000000000000000001201407657076200217330ustar00rootroot00000000000000source "https://rubygems.org" gem 'rails', '~> 4.2.0' gemspec :path => '../..' hamlit-2.15.1/test/haml/haml-spec/000077500000000000000000000000001407657076200166455ustar00rootroot00000000000000hamlit-2.15.1/test/haml/haml-spec/LICENSE000066400000000000000000000007441407657076200176570ustar00rootroot00000000000000 DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE Version 2, December 2004 Copyright (C) 2004 Sam Hocevar Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed. DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. You just DO WHAT THE FUCK YOU WANT TO. hamlit-2.15.1/test/haml/haml-spec/README.md000066400000000000000000000102231407657076200201220ustar00rootroot00000000000000# Haml Spec # Haml Spec provides a basic suite of tests for Haml interpreters. It is intented for developers who are creating or maintaining an implementation of the [Haml](http://haml-lang.com) markup language. At the moment, there are test runners for the [original Haml](http://github.com/nex3/haml) in Ruby, [Lua Haml](http://github.com/norman/lua-haml) and the [Text::Haml](http://github.com/vti/text-haml) Perl port. Support for other versions of Haml will be added if their developers/maintainers are interested in using it. ## The Tests ## The tests are kept in JSON format for portability across languages. Each test is a JSON object with expected input, output, local variables and configuration parameters (see below). The test suite only provides tests for features which are portable, therefore no tests for script are provided, nor for external filters such as :markdown or :textile. The one major exception to this are the tests for interpolation, which you may need to modify with a regular expression to run under PHP or Perl, which require a sigil before variable names. These tests are included despite being less than 100% portable because interpolation is an important part of Haml and can be tricky to implement. These tests are flagged as "optional" so that you can avoid running them if your implementation of Haml will not support this feature. ## Running the Tests ## ### Ruby ### The Ruby test runner uses minitest, the same as the Ruby Haml implementation. To run the tests you probably only need to install `haml`, `minitest` and possibly `ruby` if your platform doesn't come with it by default. If you're using Ruby 1.8.x, you'll also need to install `json`: sudo gem install haml sudo gem install minitest # for Ruby 1.8.x; check using "ruby --version" if unsure sudo gem install json Then, running the Ruby test suite is easy: ruby ruby_haml_test.rb At the moment, running the tests with Ruby 1.8.7 fails because of issues with the JSON library. Please use 1.9.2 until this is resolved. ### Lua ### The Lua test depends on [Penlight](http://stevedonovan.github.com/Penlight/), [Telescope](http://github.com/norman/telescope), [jason4lua](http://json.luaforge.net/), and [Lua Haml](http://github.com/norman/lua-haml). Install and run `tsc lua_haml_spec.lua`. ### Getting it ### You can access the [Git repository](http://github.com/norman/haml-spec) at: git://github.com/norman/haml-spec.git Patches are *very* welcome, as are test runners for your Haml implementation. As long as any test you add run against Ruby Haml and are not redundant, I'll be very happy to add them. ### Test JSON format ### "test name" : { "haml" : "haml input", "html" : "expected html output", "result" : "expected test result", "locals" : "local vars", "config" : "config params", "optional" : true|false } * test name: This should be a *very* brief description of what's being tested. It can be used by the test runners to name test methods, or to exclude certain tests from being run. * haml: The Haml code to be evaluated. Always required. * html: The HTML output that should be generated. Required unless "result" is "error". * result: Can be "pass" or "error". If it's absent, then "pass" is assumed. If it's "error", then the goal of the test is to make sure that malformed Haml code generates an error. * locals: An object containing local variables needed for the test. * config: An object containing configuration parameters used to run the test. The configuration parameters should be usable directly by Ruby's Haml with no modification. If your implementation uses config parameters with different names, you may need to process them to make them match your implementation. If your implementation has options that do not exist in Ruby's Haml, then you should add tests for this in your implementation's test rather than here. * optional: whether or not the test is optional ## License ## This project is released under the [WTFPL](http://sam.zoy.org/wtfpl/) in order to be as usable as possible in any project, commercial or free. ## Author ## [Norman Clarke](mailto:norman@njclarke.com) hamlit-2.15.1/test/haml/haml-spec/Rakefile000066400000000000000000000045641407657076200203230ustar00rootroot00000000000000$:.unshift File.expand_path('../../lib', __FILE__) require 'yaml' require 'unindent' require 'open-uri' def escape_name(name, replacer) name.gsub(/[\s\-\(\)\.\.+'\/<>&=~\!]+/, replacer) end def generate_spec(mode) spec = <<-SPEC.unindent require "minitest/autorun" require "hamlit" require "haml" # This is a spec converted by haml-spec. # See: https://github.com/haml/haml-spec class #{mode.capitalize}Test < MiniTest::Test HAML_DEFAULT_OPTIONS = { ugly: #{mode == :ugly}, escape_html: true }.freeze HAMLIT_DEFAULT_OPTIONS = { escape_html: true }.freeze def self.haml_result(haml, options, locals) Haml::Engine.new(haml, HAML_DEFAULT_OPTIONS.merge(options)).render(Object.new, locals) end def self.hamlit_result(haml, options, locals) eval Hamlit::Engine.new(haml, HAMLIT_DEFAULT_OPTIONS.merge(options)).render(Object.new, locals) end SPEC contexts = YAML.load(File.read(File.expand_path('./tests.yml', __dir__))) contexts.each_with_index do |context, index| spec += "\n" if index != 0 spec += " class #{escape_name(context[0], '').capitalize} < MiniTest::Test\n" tests = [] context[1].each do |name, test| tests << { name: name, html: test['html'], haml: test['haml'], locals: test['locals'], config: test['config'], } end spec += tests.map { |test| locals = Hash[(test[:locals] || {}).map {|x, y| [x.to_sym, y]}] options = Hash[(test[:config] || {}).map {|x, y| [x.to_sym, y]}] options[:format] = options[:format].to_sym if options[:format] generate_specify(test, locals, options, mode) }.join("\n") spec += " end\n" end spec += "end\n" File.write("#{mode}_test.rb", spec) end def generate_specify(test, locals, options, mode) <<-SPEC def test_#{escape_name(test[:name], '_')} haml = %q{#{test[:haml]}} html = %q{#{test[:html]}} locals = #{locals} options = #{options} haml_result = #{mode.capitalize}Test.haml_result(haml, options, locals) hamlit_result = #{mode.capitalize}Test.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end SPEC end desc 'Convert tests.yml into ugly tests' task :pretty do generate_spec(:pretty) end desc 'Convert tests.yml into ugly tests' task :ugly do generate_spec(:ugly) end hamlit-2.15.1/test/haml/haml-spec/tests.yml000066400000000000000000000311231407657076200205320ustar00rootroot00000000000000--- headers: an XHTML XML prolog: haml: "!!! XML" html: "" config: format: xhtml an XHTML default (transitional) doctype: haml: "!!!" html: config: format: xhtml an XHTML 1.1 doctype: haml: "!!! 1.1" html: config: format: xhtml an XHTML 1.2 mobile doctype: haml: "!!! mobile" html: config: format: xhtml an XHTML 1.1 basic doctype: haml: "!!! basic" html: config: format: xhtml an XHTML 1.0 frameset doctype: haml: "!!! frameset" html: config: format: xhtml an HTML 5 doctype with XHTML syntax: haml: "!!! 5" html: "" config: format: xhtml an HTML 5 XML prolog (silent): haml: "!!! XML" html: '' config: format: html5 an HTML 5 doctype: haml: "!!!" html: "" config: format: html5 an HTML 4 XML prolog (silent): haml: "!!! XML" html: '' config: format: html4 an HTML 4 default (transitional) doctype: haml: "!!!" html: config: format: html4 an HTML 4 frameset doctype: haml: "!!! frameset" html: config: format: html4 an HTML 4 strict doctype: haml: "!!! strict" html: config: format: html4 basic Haml tags and CSS: a simple Haml tag: haml: "%p" html: "

      " a self-closing tag (XHTML): haml: "%meta" html: "" config: format: xhtml a self-closing tag (HTML4): haml: "%meta" html: "" config: format: html4 a self-closing tag (HTML5): haml: "%meta" html: "" config: format: html5 a self-closing tag ('/' modifier + XHTML): haml: "%zzz/" html: "" config: format: xhtml a self-closing tag ('/' modifier + HTML5): haml: "%zzz/" html: "" config: format: html5 a tag with a CSS class: haml: "%p.class1" html: "

      " a tag with multiple CSS classes: haml: "%p.class1.class2" html: "

      " a tag with a CSS id: haml: "%p#id1" html: "

      " a tag with multiple CSS id's: haml: "%p#id1#id2" html: "

      " a tag with a class followed by an id: haml: "%p.class1#id1" html: "

      " a tag with an id followed by a class: haml: "%p#id1.class1" html: "

      " an implicit div with a CSS id: haml: "#id1" html: "
      " an implicit div with a CSS class: haml: ".class1" html: "
      " multiple simple Haml tags: haml: |- %div %div %p html: |-

      tags with unusual HTML characters: a tag with colons: haml: "%ns:tag" html: "" a tag with underscores: haml: "%snake_case" html: "" a tag with dashes: haml: "%dashed-tag" html: "" a tag with camelCase: haml: "%camelCase" html: "" a tag with PascalCase: haml: "%PascalCase" html: "" tags with unusual CSS identifiers: an all-numeric class: haml: ".123" html: "
      " a class with underscores: haml: ".__" html: "
      " a class with dashes: haml: ".--" html: "
      " tags with inline content: Inline content simple tag: haml: "%p hello" html: "

      hello

      " Inline content tag with CSS: haml: "%p.class1 hello" html: "

      hello

      " Inline content multiple simple tags: haml: |- %div %div %p text html: |-

      text

      tags with nested content: Nested content simple tag: haml: |- %p hello html: |-

      hello

      Nested content tag with CSS: haml: |- %p.class1 hello html: |-

      hello

      Nested content multiple simple tags: haml: |- %div %div %p text html: |-

      text

      tags with HTML-style attributes: HTML-style one attribute: haml: "%p(a='b')" html: "

      " HTML-style multiple attributes: haml: "%p(a='b' c='d')" html: "

      " HTML-style attributes separated with newlines: haml: |- %p(a='b' c='d') html: "

      " HTML-style interpolated attribute: haml: '%p(a="#{var}")' html: "

      " locals: var: value HTML-style 'class' as an attribute: haml: "%p(class='class1')" html: "

      " HTML-style tag with a CSS class and 'class' as an attribute: haml: "%p.class2(class='class1')" html: "

      " HTML-style tag with 'id' as an attribute: haml: "%p(id='1')" html: "

      " HTML-style tag with a CSS id and 'id' as an attribute: haml: "%p#id(id='1')" html: "

      " HTML-style tag with a variable attribute: haml: "%p(class=var)" html: "

      " locals: var: hello HTML-style tag with a CSS class and 'class' as a variable attribute: haml: ".hello(class=var)" html: "
      " locals: var: world HTML-style tag multiple CSS classes (sorted correctly): haml: ".z(class=var)" html: "
      " locals: var: a HTML-style tag with an atomic attribute: haml: "%a(flag)" html: "" tags with Ruby-style attributes: Ruby-style one attribute: haml: "%p{:a => 'b'}" html: "

      " optional: true Ruby-style attributes hash with whitespace: haml: "%p{ :a => 'b' }" html: "

      " optional: true Ruby-style interpolated attribute: haml: '%p{:a =>"#{var}"}' html: "

      " optional: true locals: var: value Ruby-style multiple attributes: haml: "%p{ :a => 'b', 'c' => 'd' }" html: "

      " optional: true Ruby-style attributes separated with newlines: haml: |- %p{ :a => 'b', 'c' => 'd' } html: "

      " optional: true Ruby-style 'class' as an attribute: haml: "%p{:class => 'class1'}" html: "

      " optional: true Ruby-style tag with a CSS class and 'class' as an attribute: haml: "%p.class2{:class => 'class1'}" html: "

      " optional: true Ruby-style tag with 'id' as an attribute: haml: "%p{:id => '1'}" html: "

      " optional: true Ruby-style tag with a CSS id and 'id' as an attribute: haml: "%p#id{:id => '1'}" html: "

      " optional: true Ruby-style tag with a CSS id and a numeric 'id' as an attribute: haml: "%p#id{:id => 1}" html: "

      " optional: true Ruby-style tag with a variable attribute: haml: "%p{:class => var}" html: "

      " optional: true locals: var: hello Ruby-style tag with a CSS class and 'class' as a variable attribute: haml: ".hello{:class => var}" html: "
      " optional: true locals: var: world Ruby-style tag multiple CSS classes (sorted correctly): haml: ".z{:class => var}" html: "
      " optional: true locals: var: a silent comments: an inline silent comment: haml: "-# hello" html: '' a nested silent comment: haml: |- -# hello html: '' a multiply nested silent comment: haml: |- -# %div foo html: '' a multiply nested silent comment with inconsistent indents: haml: |- -# %div foo html: '' markup comments: an inline markup comment: haml: "/ comment" html: "" a nested markup comment: haml: |- / comment comment2 html: |- conditional comments: a conditional comment: haml: |- /[if IE] %p a html: |- internal filters: content in an 'escaped' filter: haml: |- :escaped <&"> html: "<&">" content in a 'preserve' filter: haml: |- :preserve hello %p html: |- hello

      content in a 'plain' filter: haml: |- :plain hello %p html: |- hello

      content in a 'css' filter (XHTML): haml: |- :css hello %p html: |-

      config: format: xhtml content in a 'javascript' filter (XHTML): haml: |- :javascript a(); %p html: |-

      config: format: xhtml content in a 'css' filter (HTML): haml: |- :css hello %p html: |-

      config: format: html5 content in a 'javascript' filter (HTML): haml: |- :javascript a(); %p html: |-

      config: format: html5 Ruby-style interpolation: interpolation inside inline content: haml: "%p #{var}" html: "

      value

      " optional: true locals: var: value no interpolation when escaped: haml: "%p \\#{var}" html: "

      #{var}

      " optional: true locals: var: value interpolation when the escape character is escaped: haml: "%p \\\\#{var}" html: "

      \\value

      " optional: true locals: var: value interpolation inside filtered content: haml: |- :plain #{var} interpolated: #{var} html: 'value interpolated: value' optional: true locals: var: value HTML escaping: code following '&=': haml: '&= ''<"&>''' html: "<"&>" code following '=' when escape_haml is set to true: haml: = '<"&>' html: "<"&>" config: escape_html: 'true' code following '!=' when escape_haml is set to true: haml: '!= ''<"&>''' html: <"&> config: escape_html: 'true' boolean attributes: boolean attribute with XHTML: haml: "%input(checked=true)" html: "" config: format: xhtml boolean attribute with HTML: haml: "%input(checked=true)" html: "" config: format: html5 whitespace preservation: following the '~' operator: haml: ~ "Foo\n
      Bar\nBaz
      " html: |- Foo
      Bar
      Baz
      optional: true inside a textarea tag: haml: |- %textarea hello hello html: |- inside a pre tag: haml: |- %pre hello hello html: |-
      hello
            hello
      whitespace removal: a tag with '>' appended and inline content: haml: |- %li hello %li> world %li again html: "
    • hello
    • world
    • again
    • " a tag with '>' appended and nested content: haml: |- %li hello %li> world %li again html: |-
    • hello
    • world
    • again
    • a tag with '<' appended: haml: |- %p< hello world html: |-

      hello world

      hamlit-2.15.1/test/haml/haml-spec/ugly_test.rb000066400000000000000000001067651407657076200212300ustar00rootroot00000000000000$:.unshift File.expand_path('../../test', __dir__) require 'test_helper' require 'haml' require 'minitest/autorun' # This is a spec converted by haml-spec. # See: https://github.com/haml/haml-spec class UglyTest < MiniTest::Test HAML_DEFAULT_OPTIONS = { escape_html: true, escape_attrs: true }.freeze HAMLIT_DEFAULT_OPTIONS = { escape_html: true }.freeze def self.haml_result(haml, options, locals) Haml::Engine.new(haml, HAML_DEFAULT_OPTIONS.merge(options)).render(Object.new, locals) end def self.hamlit_result(haml, options, locals) Hamlit::Template.new(HAMLIT_DEFAULT_OPTIONS.merge(options)) { haml }.render(Object.new, locals) end class Headers < MiniTest::Test def test_an_XHTML_XML_prolog haml = %q{!!! XML} _html = %q{} locals = {} options = {:format=>:xhtml} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_an_XHTML_default_transitional_doctype haml = %q{!!!} _html = %q{} locals = {} options = {:format=>:xhtml} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_an_XHTML_1_1_doctype haml = %q{!!! 1.1} _html = %q{} locals = {} options = {:format=>:xhtml} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_an_XHTML_1_2_mobile_doctype haml = %q{!!! mobile} _html = %q{} locals = {} options = {:format=>:xhtml} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_an_XHTML_1_1_basic_doctype haml = %q{!!! basic} _html = %q{} locals = {} options = {:format=>:xhtml} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_an_XHTML_1_0_frameset_doctype haml = %q{!!! frameset} _html = %q{} locals = {} options = {:format=>:xhtml} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_an_HTML_5_doctype_with_XHTML_syntax haml = %q{!!! 5} _html = %q{} locals = {} options = {:format=>:xhtml} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_an_HTML_5_XML_prolog_silent_ haml = %q{!!! XML} _html = %q{} locals = {} options = {:format=>:html5} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_an_HTML_5_doctype haml = %q{!!!} _html = %q{} locals = {} options = {:format=>:html5} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_an_HTML_4_XML_prolog_silent_ haml = %q{!!! XML} _html = %q{} locals = {} options = {:format=>:html4} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_an_HTML_4_default_transitional_doctype haml = %q{!!!} _html = %q{} locals = {} options = {:format=>:html4} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_an_HTML_4_frameset_doctype haml = %q{!!! frameset} _html = %q{} locals = {} options = {:format=>:html4} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_an_HTML_4_strict_doctype haml = %q{!!! strict} _html = %q{} locals = {} options = {:format=>:html4} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end end class Basichamltagsandcss < MiniTest::Test def test_a_simple_Haml_tag haml = %q{%p} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_self_closing_tag_XHTML_ haml = %q{%meta} _html = %q{} locals = {} options = {:format=>:xhtml} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_self_closing_tag_HTML4_ haml = %q{%meta} _html = %q{} locals = {} options = {:format=>:html4} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_self_closing_tag_HTML5_ haml = %q{%meta} _html = %q{} locals = {} options = {:format=>:html5} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_self_closing_tag_modifier_XHTML_ haml = %q{%zzz/} _html = %q{} locals = {} options = {:format=>:xhtml} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_self_closing_tag_modifier_HTML5_ haml = %q{%zzz/} _html = %q{} locals = {} options = {:format=>:html5} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_tag_with_a_CSS_class haml = %q{%p.class1} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_tag_with_multiple_CSS_classes haml = %q{%p.class1.class2} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_tag_with_a_CSS_id haml = %q{%p#id1} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_tag_with_multiple_CSS_id_s haml = %q{%p#id1#id2} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_tag_with_a_class_followed_by_an_id haml = %q{%p.class1#id1} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_tag_with_an_id_followed_by_a_class haml = %q{%p#id1.class1} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_an_implicit_div_with_a_CSS_id haml = %q{#id1} _html = %q{
      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_an_implicit_div_with_a_CSS_class haml = %q{.class1} _html = %q{
      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_multiple_simple_Haml_tags haml = %q{%div %div %p} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end end class Tagswithunusualhtmlcharacters < MiniTest::Test def test_a_tag_with_colons haml = %q{%ns:tag} _html = %q{} locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_tag_with_underscores haml = %q{%snake_case} _html = %q{} locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_tag_with_dashes haml = %q{%dashed-tag} _html = %q{} locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_tag_with_camelCase haml = %q{%camelCase} _html = %q{} locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_tag_with_PascalCase haml = %q{%PascalCase} _html = %q{} locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end end class Tagswithunusualcssidentifiers < MiniTest::Test def test_an_all_numeric_class haml = %q{.123} _html = %q{
      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_class_with_underscores haml = %q{.__} _html = %q{
      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_class_with_dashes haml = %q{.--} _html = %q{
      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end end class Tagswithinlinecontent < MiniTest::Test def test_Inline_content_simple_tag haml = %q{%p hello} _html = %q{

      hello

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_Inline_content_tag_with_CSS haml = %q{%p.class1 hello} _html = %q{

      hello

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_Inline_content_multiple_simple_tags haml = %q{%div %div %p text} _html = %q{

      text

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end end class Tagswithnestedcontent < MiniTest::Test def test_Nested_content_simple_tag haml = %q{%p hello} _html = %q{

      hello

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_Nested_content_tag_with_CSS haml = %q{%p.class1 hello} _html = %q{

      hello

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_Nested_content_multiple_simple_tags haml = %q{%div %div %p text} _html = %q{

      text

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end end class Tagswithhtmlstyleattributes < MiniTest::Test def test_HTML_style_one_attribute haml = %q{%p(a='b')} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_HTML_style_multiple_attributes haml = %q{%p(a='b' c='d')} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_HTML_style_attributes_separated_with_newlines haml = %q{%p(a='b' c='d')} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_HTML_style_interpolated_attribute haml = %q{%p(a="#{var}")} _html = %q{

      } locals = {:var=>"value"} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_HTML_style_class_as_an_attribute haml = %q{%p(class='class1')} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_HTML_style_tag_with_a_CSS_class_and_class_as_an_attribute haml = %q{%p.class2(class='class1')} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_HTML_style_tag_with_id_as_an_attribute haml = %q{%p(id='1')} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_HTML_style_tag_with_a_CSS_id_and_id_as_an_attribute haml = %q{%p#id(id='1')} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_HTML_style_tag_with_a_variable_attribute haml = %q{%p(class=var)} _html = %q{

      } locals = {:var=>"hello"} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_HTML_style_tag_with_a_CSS_class_and_class_as_a_variable_attribute haml = %q{.hello(class=var)} _html = %q{
      } locals = {:var=>"world"} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_HTML_style_tag_multiple_CSS_classes_sorted_correctly_ haml = %q{.z(class=var)} _html = %q{
      } locals = {:var=>"a"} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_HTML_style_tag_with_an_atomic_attribute skip '[INCOMPATIBILITY] Hamlit limits boolean attributes' haml = %q{%a(flag)} _html = %q{} locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end end class Tagswithrubystyleattributes < MiniTest::Test def test_Ruby_style_one_attribute haml = %q{%p{:a => 'b'}} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_Ruby_style_attributes_hash_with_whitespace haml = %q{%p{ :a => 'b' }} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_Ruby_style_interpolated_attribute haml = %q{%p{:a =>"#{var}"}} _html = %q{

      } locals = {:var=>"value"} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_Ruby_style_multiple_attributes haml = %q{%p{ :a => 'b', 'c' => 'd' }} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_Ruby_style_attributes_separated_with_newlines haml = %q{%p{ :a => 'b', 'c' => 'd' }} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_Ruby_style_class_as_an_attribute haml = %q{%p{:class => 'class1'}} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_Ruby_style_tag_with_a_CSS_class_and_class_as_an_attribute haml = %q{%p.class2{:class => 'class1'}} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_Ruby_style_tag_with_id_as_an_attribute haml = %q{%p{:id => '1'}} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_Ruby_style_tag_with_a_CSS_id_and_id_as_an_attribute haml = %q{%p#id{:id => '1'}} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_Ruby_style_tag_with_a_CSS_id_and_a_numeric_id_as_an_attribute haml = %q{%p#id{:id => 1}} _html = %q{

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_Ruby_style_tag_with_a_variable_attribute haml = %q{%p{:class => var}} _html = %q{

      } locals = {:var=>"hello"} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_Ruby_style_tag_with_a_CSS_class_and_class_as_a_variable_attribute haml = %q{.hello{:class => var}} _html = %q{
      } locals = {:var=>"world"} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_Ruby_style_tag_multiple_CSS_classes_sorted_correctly_ haml = %q{.z{:class => var}} _html = %q{
      } locals = {:var=>"a"} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end end class Silentcomments < MiniTest::Test def test_an_inline_silent_comment haml = %q{-# hello} _html = %q{} locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_nested_silent_comment haml = %q{-# hello} _html = %q{} locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_multiply_nested_silent_comment haml = %q{-# %div foo} _html = %q{} locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_multiply_nested_silent_comment_with_inconsistent_indents haml = %q{-# %div foo} _html = %q{} locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end end class Markupcomments < MiniTest::Test def test_an_inline_markup_comment haml = %q{/ comment} _html = %q{} locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_nested_markup_comment haml = %q{/ comment comment2} _html = %q{} locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end end class Conditionalcomments < MiniTest::Test def test_a_conditional_comment haml = %q{/[if IE] %p a} _html = %q{} locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end end class Internalfilters < MiniTest::Test def test_content_in_an_escaped_filter haml = %q{:escaped <&">} _html = %q{<&">} locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_content_in_a_preserve_filter haml = %q{:preserve hello %p} _html = %q{hello

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_content_in_a_plain_filter haml = %q{:plain hello %p} _html = %q{hello

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_content_in_a_css_filter_XHTML_ haml = %q{:css hello %p} _html = %q{

      } locals = {} options = {:format=>:xhtml} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_content_in_a_javascript_filter_XHTML_ haml = %q{:javascript a(); %p} _html = %q{

      } locals = {} options = {:format=>:xhtml} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_content_in_a_css_filter_HTML_ haml = %q{:css hello %p} _html = %q{

      } locals = {} options = {:format=>:html5} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_content_in_a_javascript_filter_HTML_ haml = %q{:javascript a(); %p} _html = %q{

      } locals = {} options = {:format=>:html5} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end end class Rubystyleinterpolation < MiniTest::Test def test_interpolation_inside_inline_content haml = %q{%p #{var}} _html = %q{

      value

      } locals = {:var=>"value"} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_no_interpolation_when_escaped haml = %q{%p \#{var}} _html = %q{

      #{var}

      } locals = {:var=>"value"} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_interpolation_when_the_escape_character_is_escaped haml = %q{%p \\#{var}} _html = %q{

      \value

      } locals = {:var=>"value"} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_interpolation_inside_filtered_content haml = %q{:plain #{var} interpolated: #{var}} _html = %q{value interpolated: value} locals = {:var=>"value"} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end end class Htmlescaping < MiniTest::Test def test_code_following_ haml = %q{&= '<"&>'} _html = %q{<"&>} locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_code_following_eq_when_escape_haml_is_set_to_true haml = %q{= '<"&>'} _html = %q{<"&>} locals = {} options = {:escape_html=>"true"} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_code_following_neq_when_escape_haml_is_set_to_true haml = %q{!= '<"&>'} _html = %q{<"&>} locals = {} options = {:escape_html=>"true"} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end end class Booleanattributes < MiniTest::Test def test_boolean_attribute_with_XHTML haml = %q{%input(checked=true)} _html = %q{} locals = {} options = {:format=>:xhtml} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_boolean_attribute_with_HTML haml = %q{%input(checked=true)} _html = %q{} locals = {} options = {:format=>:html5} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end end class Whitespacepreservation < MiniTest::Test def test_following_the_operator haml = %q{~ "Foo\n
      Bar\nBaz
      "} _html = %q{Foo
      Bar
      Baz
      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_inside_a_textarea_tag haml = %q{%textarea hello hello} _html = %q{} locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_inside_a_pre_tag haml = %q{%pre hello hello} _html = %q{
      hello
      hello
      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end end class Whitespaceremoval < MiniTest::Test def test_a_tag_with_appended_and_inline_content haml = %q{%li hello %li> world %li again} _html = %q{
    • hello
    • world
    • again
    • } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_tag_with_appended_and_nested_content haml = %q{%li hello %li> world %li again} _html = %q{
    • hello
    • world
    • again
    • } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end def test_a_tag_with_appended haml = %q{%p< hello world} _html = %q{

      hello world

      } locals = {} options = {} haml_result = UglyTest.haml_result(haml, options, locals) hamlit_result = UglyTest.hamlit_result(haml, options, locals) assert_equal haml_result, hamlit_result end end end if RUBY_ENGINE != 'truffleruby' # truffleruby cannot run Haml hamlit-2.15.1/test/haml/helper_test.rb000066400000000000000000000524261407657076200176500ustar00rootroot00000000000000require 'test_helper' require "active_model/naming" class FormModel extend ActiveModel::Naming end class HelperTest < Haml::TestCase TEXT_AREA_CONTENT_REGEX = /<(textarea)[^>]*>\n(.*?)<\/\1>/im Post = Struct.new('Post', :body, :error_field, :errors) class PostErrors def on(name) return unless name == 'error_field' ["Really bad error"] end alias_method :full_messages, :on def [](name) on(name) || [] end end def setup @base = Class.new(ActionView::Base) do def nested_tag content_tag(:span) {content_tag(:div) {"something"}} end def wacky_form form_tag("/foo") {"bar"} end def compiled_method_container self.class end end.new(ActionView::LookupContext.new(''), {}, ActionController::Base.new) @base.view_paths << File.expand_path("../templates", __FILE__) @base.instance_variable_set(:@post, Post.new("Foo bar\nbaz", nil, PostErrors.new)) end def render(text, options = {}) return @base.render :inline => text, :type => :haml if options == :action_view super end def test_rendering_with_escapes; skip def @base.render_something_with_haml_concat haml_concat "

      " end def @base.render_something_with_haml_tag_and_concat haml_tag 'p' do haml_concat '' end end output = render(<<-HAML, :action_view) - render_something_with_haml_concat - render_something_with_haml_tag_and_concat - render_something_with_haml_concat HAML assert_equal("<p>\n

      \n <foo>\n

      \n<p>\n", output) end def test_with_raw_haml_concat; skip haml = <&" HAML assert_equal("<>&\n", render(haml, :action_view)) end def test_flatten assert_equal("FooBar", Haml::Helpers.flatten("FooBar")) assert_equal("FooBar", Haml::Helpers.flatten("Foo\rBar")) assert_equal("Foo Bar", Haml::Helpers.flatten("Foo\nBar")) assert_equal("Hello World! YOU ARE FLAT? OMGZ!", Haml::Helpers.flatten("Hello\nWorld!\nYOU ARE \rFLAT?\n\rOMGZ!")) end def test_list_of_should_render_correctly; skip assert_equal("
    • 1
    • \n
    • 2
    • \n", render("= list_of([1, 2]) do |i|\n = i")) assert_equal("
    • [1]
    • \n", render("= list_of([[1]]) do |i|\n = i.inspect")) assert_equal("
    • \n

      Fee

      \n

      A word!

      \n
    • \n
    • \n

      Fi

      \n

      A word!

      \n
    • \n
    • \n

      Fo

      \n

      A word!

      \n
    • \n
    • \n

      Fum

      \n

      A word!

      \n
    • \n", render("= list_of(['Fee', 'Fi', 'Fo', 'Fum']) do |title|\n %h1= title\n %p A word!")) assert_equal("
    • 1
    • \n
    • 2
    • \n", render("= list_of([1, 2], {:c => 3}) do |i|\n = i")) assert_equal("
    • [1]
    • \n", render("= list_of([[1]], {:c => 3}) do |i|\n = i.inspect")) assert_equal("
    • \n

      Fee

      \n

      A word!

      \n
    • \n
    • \n

      Fi

      \n

      A word!

      \n
    • \n
    • \n

      Fo

      \n

      A word!

      \n
    • \n
    • \n

      Fum

      \n

      A word!

      \n
    • \n", render("= list_of(['Fee', 'Fi', 'Fo', 'Fum'], {:c => 3}) do |title|\n %h1= title\n %p A word!")) end def test_buffer_access; skip assert(render("= buffer") =~ /#/) assert_equal(render("= (buffer == _hamlout)"), "true\n") end def test_tabs; skip assert_equal("foo\n bar\nbaz\n", render("foo\n- tab_up\nbar\n- tab_down\nbaz")) assert_equal("

      tabbed

      \n", render("- buffer.tabulation=5\n%p tabbed")) end def test_with_tabs; skip assert_equal(< "<%= flatten('Foo\\nBar') %>") rescue NoMethodError, ActionView::Template::Error proper_behavior = true end assert(proper_behavior) begin action_view_instance.render(:inline => "<%= concat('foo') %>") rescue ArgumentError, NameError proper_behavior = true end assert(proper_behavior) end def test_action_view_included; skip assert(Haml::Helpers.action_view?) end def test_form_tag; skip def @base.protect_against_forgery?; false; end rendered = render(<]+>Foo bar baz\n), render('= content_tag "pre", "Foo bar\n baz"', :action_view)) end def test_text_area_tag; skip output = render('= text_area_tag "body", "Foo\nBar\n Baz\n Boom"', :action_view) match_data = output.match(TEXT_AREA_CONTENT_REGEX) assert_equal "Foo Bar Baz Boom", match_data[2] end def test_text_area; skip output = render('= text_area :post, :body', :action_view) match_data = output.match(TEXT_AREA_CONTENT_REGEX) assert_equal "Foo bar baz", match_data[2] end def test_partials_should_not_cause_textareas_to_be_indented; skip # non-indentation of textareas rendered inside partials @base.instance_variable_set(:@post, Post.new("Foo", nil, PostErrors.new)) output = render(".foo\n .bar\n = render '/text_area_helper'", :action_view) match_data = output.match(TEXT_AREA_CONTENT_REGEX) assert_equal 'Foo', match_data[2] end def test_textareas_should_preserve_leading_whitespace; skip # leading whitespace preservation @base.instance_variable_set(:@post, Post.new(" Foo", nil, PostErrors.new)) output = render(".foo\n = text_area :post, :body", :action_view) match_data = output.match(TEXT_AREA_CONTENT_REGEX) assert_equal ' Foo', match_data[2] end def test_textareas_should_preserve_leading_whitespace_in_partials; skip # leading whitespace in textareas rendered inside partials @base.instance_variable_set(:@post, Post.new(" Foo", nil, PostErrors.new)) output = render(".foo\n .bar\n = render '/text_area_helper'", :action_view) match_data = output.match(TEXT_AREA_CONTENT_REGEX) assert_equal ' Foo', match_data[2] end def test_capture_haml; skip assert_equal(<13

      \\n" HTML - (foo = capture_haml(13) do |a| %p= a - end) = foo.inspect HAML end def test_content_tag_block; skip assert_equal(<

      bar

      bar
HTML = content_tag :div do %p bar %strong bar HAML end def test_content_tag_error_wrapping; skip def @base.protect_against_forgery?; false; end output = render(< :post, :html => {:class => nil, :id => nil}, :url => '' do |f| = f.label 'error_field' HAML fragment = Nokogiri::HTML.fragment(output) refute_nil fragment.css('form div.field_with_errors label[for=post_error_field]').first end def test_form_tag_in_helper_with_string_block; skip def @base.protect_against_forgery?; false; end rendered = render('= wacky_form', :action_view) fragment = Nokogiri::HTML.fragment(rendered) assert_equal 'bar', fragment.text.strip assert_equal '/foo', fragment.css('form').first.attributes['action'].to_s end def test_haml_tag_name_attribute_with_id; skip assert_equal("

\n", render("- haml_tag 'p#some_id'")) end def test_haml_tag_name_attribute_with_colon_id; skip assert_equal("

\n", render("- haml_tag 'p#some:id'")) end def test_haml_tag_without_name_but_with_id; skip assert_equal("
\n", render("- haml_tag '#some_id'")) end def test_haml_tag_without_name_but_with_class; skip assert_equal("
\n", render("- haml_tag '.foo'")) end def test_haml_tag_without_name_but_with_colon_class; skip assert_equal("
\n", render("- haml_tag '.foo:bar'")) end def test_haml_tag_name_with_id_and_class; skip assert_equal("

\n", render("- haml_tag 'p#some_id.foo'")) end def test_haml_tag_name_with_class; skip assert_equal("

\n", render("- haml_tag 'p.foo'")) end def test_haml_tag_name_with_class_and_id; skip assert_equal("

\n", render("- haml_tag 'p.foo#some_id'")) end def test_haml_tag_name_with_id_and_multiple_classes; skip assert_equal("

\n", render("- haml_tag 'p#some_id.foo.bar'")) end def test_haml_tag_name_with_multiple_classes_and_id; skip assert_equal("

\n", render("- haml_tag 'p.foo.bar#some_id'")) end def test_haml_tag_name_and_attribute_classes_merging_with_id; skip assert_equal("

\n", render("- haml_tag 'p#some_id.foo', :class => 'bar'")) end def test_haml_tag_name_and_attribute_classes_merging; skip assert_equal("

\n", render("- haml_tag 'p.foo', :class => 'bar'")) end def test_haml_tag_name_merges_id_and_attribute_id; skip assert_equal("

\n", render("- haml_tag 'p#foo', :id => 'bar'")) end def test_haml_tag_attribute_html_escaping; skip assert_equal("

baz

\n", render("%p{:id => 'foo&bar'} baz", :escape_html => true)) end def test_haml_tag_autoclosed_tags_are_closed_xhtml; skip assert_equal("
\n", render("- haml_tag :br, :class => 'foo'", :format => :xhtml)) end def test_haml_tag_autoclosed_tags_are_closed_html; skip assert_equal("
\n", render("- haml_tag :br, :class => 'foo'", :format => :html5)) end def test_haml_tag_with_class_array; skip assert_equal("

foo

\n", render("- haml_tag :p, 'foo', :class => %w[a b]")) assert_equal("

foo

\n", render("- haml_tag 'p.c.d', 'foo', :class => %w[a b]")) end def test_haml_tag_with_id_array; skip assert_equal("

foo

\n", render("- haml_tag :p, 'foo', :id => %w[a b]")) assert_equal("

foo

\n", render("- haml_tag 'p#c', 'foo', :id => %w[a b]")) end def test_haml_tag_with_data_hash; skip assert_equal("

foo

\n", render("- haml_tag :p, 'foo', :data => {:foo => 'bar', :baz => true}")) end def test_haml_tag_non_autoclosed_tags_arent_closed; skip assert_equal("

\n", render("- haml_tag :p")) end def test_haml_tag_renders_text_on_a_single_line; skip assert_equal("

#{'a' * 100}

\n", render("- haml_tag :p, 'a' * 100")) end def test_haml_tag_raises_error_for_multiple_content; skip assert_raises(Haml::Error) { render("- haml_tag :p, 'foo' do\n bar") } end def test_haml_tag_flags; skip assert_equal("

\n", render("- haml_tag :p, :/", :format => :xhtml)) assert_equal("

\n", render("- haml_tag :p, :/", :format => :html5)) assert_equal("

kumquat

\n", render("- haml_tag :p, :< do\n kumquat")) assert_raises(Haml::Error) { render("- haml_tag :p, 'foo', :/") } assert_raises(Haml::Error) { render("- haml_tag :p, :/ do\n foo") } end def test_haml_tag_error_return; skip assert_raises(Haml::Error) { render("= haml_tag :p") } end def test_haml_tag_with_multiline_string; skip assert_equal(< foo bar baz

HTML - haml_tag :p, "foo\\nbar\\nbaz" HAML end def test_haml_concat_inside_haml_tag_escaped_with_xss; skip assert_equal("

\n <>&\n

\n", render(<&" HAML end def test_haml_concat_with_multiline_string; skip assert_equal(< foo bar baz

HTML %p - haml_concat "foo\\nbar\\nbaz" HAML end def test_haml_tag_with_ugly; skip assert_equal(< true))

Hi!

HTML - haml_tag :p do - haml_tag :strong, "Hi!" HAML end def test_haml_tag_if_positive; skip assert_equal(<

A para

HTML - haml_tag_if true, '.conditional' do %p A para HAML end def test_haml_tag_if_positive_with_attributes; skip assert_equal(<

A para

HTML - haml_tag_if true, '.conditional', {:foo => 'bar'} do %p A para HAML end def test_haml_tag_if_negative; skip assert_equal(<A para

HTML - haml_tag_if false, '.conditional' do %p A para HAML end def test_haml_tag_if_error_return; skip assert_raises(Haml::Error) { render("= haml_tag_if false, '.conditional' do\n %p Hello") } end def test_is_haml; skip assert(!ActionView::Base.new.is_haml?) assert_equal("true\n", render("= is_haml?")) assert_equal("true\n", render("= is_haml?", :action_view)) assert_equal("false", @base.render(:inline => '<%= is_haml? %>')) assert_equal("false\n", render("= render :inline => '<%= is_haml? %>'", :action_view)) end def test_page_class; skip controller = Struct.new(:controller_name, :action_name).new('troller', 'tion') scope = Struct.new(:controller).new(controller) result = render("%div{:class => page_class} MyDiv", :scope => scope) expected = "
MyDiv
\n" assert_equal expected, result end def test_indented_capture assert_equal(" Foo\n ", @base.render(:inline => " <% res = capture do %>\n Foo\n <% end %><%= res %>")) end def test_capture_deals_properly_with_collections; skip obj = Object.new def obj.trc(collection, &block) collection.each do |record| haml_concat capture_haml(record, &block) end end assert_equal("1\n\n2\n\n3\n\n", render("- trc([1, 2, 3]) do |i|\n = i.inspect", scope: obj)) end def test_capture_with_string_block; skip assert_equal("foo\n", render("= capture { 'foo' }", :action_view)) end def test_capture_with_non_string_value_reurns_nil; skip def @base.check_capture_returns_nil(&block) contents = capture(&block) contents << "ERROR" if contents end assert_equal("\n", render("= check_capture_returns_nil { 2 }", :action_view)) end class HomemadeViewContext include ActionView::Context include ActionView::Helpers::FormHelper def initialize _prepare_context end def url_for(*) "/" end def dom_class(*) end def dom_id(*) end def m # I have to inject the model into the view using an instance method, using locals doesn't work. FormModel.new end def protect_against_forgery? end # def capture(*args, &block) # capture_haml(*args, &block) # end end def test_form_for_with_homemade_view_context; skip handler = ActionView::Template.handler_for_extension("haml") template = ActionView::Template.new(< "/") do %b Bold! HAML # see if Bold is within form tags: assert_match(/.*Bold!<\/b>.*<\/form>/m, template.render(HomemadeViewContext.new, {})) end def test_find_and_preserve_with_block; skip assert_equal("
Foo
Bar
\nFoo\nBar\n", render("= find_and_preserve do\n %pre\n Foo\n Bar\n Foo\n Bar")) end def test_find_and_preserve_with_block_and_tags; skip assert_equal("
Foo\nBar
\nFoo\nBar\n", render("= find_and_preserve([]) do\n %pre\n Foo\n Bar\n Foo\n Bar")) end def test_preserve_with_block; skip assert_equal("
Foo
Bar
Foo Bar\n", render("= preserve do\n %pre\n Foo\n Bar\n Foo\n Bar")) end def test_init_haml_helpers context = Object.new class << context include Haml::Helpers end context.init_haml_helpers result = context.capture_haml do context.haml_tag :p, :attr => "val" do context.haml_concat "Blah" end end assert_equal("

\n Blah\n

\n", result) end def test_non_haml; skip assert_equal("false\n", render("= non_haml { is_haml? }")) end def test_content_tag_nested; skip assert_equal "
something
", render("= nested_tag", :action_view).strip end def test_error_return; skip assert_raises(Haml::Error, < e assert_equal 2, e.backtrace[1].scan(/:(\d+)/).first.first.to_i end def test_error_return_line_in_helper; skip obj = Object.new def obj.something_that_uses_haml_concat haml_concat('foo').to_s end render("- something_that_uses_haml_concat", scope: obj) assert false, "Expected Haml::Error" rescue Haml::Error => e assert_equal __LINE__ - 6, e.backtrace[0].scan(/:(\d+)/).first.first.to_i end class ActsLikeTag # We want to be able to have people include monkeypatched ActionView helpers # without redefining is_haml?. # This is accomplished via Object#is_haml?, and this is a test for it. include ActionView::Helpers::TagHelper def to_s content_tag :p, 'some tag content' end end def test_random_class_includes_tag_helper assert_equal "

some tag content

", ActsLikeTag.new.to_s end def test_capture_with_nuke_outer; skip assert_equal "
\n*
hi there!
\n", render(< hi there! HAML assert_equal "
\n*
hi there!
\n", render(< hi there! HAML end def test_html_escape assert_equal ""><&", Haml::Helpers.html_escape('"><&') end def test_html_escape_should_work_on_frozen_strings begin assert Haml::Helpers.html_escape('foo'.freeze) rescue => e flunk e.message end end def test_html_escape_encoding old_stderr, $stderr = $stderr, StringIO.new string = "\"><&\u00e9" # if you're curious, u00e9 is "LATIN SMALL LETTER E WITH ACUTE" assert_equal ""><&\u00e9", Haml::Helpers.html_escape(string) assert $stderr.string == "", "html_escape shouldn't generate warnings with UTF-8 strings: #{$stderr.string}" ensure $stderr = old_stderr end def test_html_escape_non_string; skip assert_equal('4.58', Haml::Helpers.html_escape(4.58)) assert_equal('4.58', Haml::Helpers.html_escape_without_haml_xss(4.58)) end def test_escape_once assert_equal ""><&", Haml::Helpers.escape_once('"><&') end def test_escape_once_leaves_entity_references assert_equal ""><&  ", Haml::Helpers.escape_once('"><&  ') end def test_escape_once_leaves_numeric_references; skip assert_equal ""><&  ", Haml::Helpers.escape_once('"><&  ') #decimal assert_equal ""><&  ", Haml::Helpers.escape_once('"><&  ') #hexadecimal end def test_escape_once_encoding old_stderr, $stderr = $stderr, StringIO.new string = "\"><&\u00e9  " assert_equal ""><&\u00e9  ", Haml::Helpers.escape_once(string) assert $stderr.string == "", "html_escape shouldn't generate warnings with UTF-8 strings: #{$stderr.string}" ensure $stderr = old_stderr end def test_html_attrs_xhtml; skip assert_equal("\n", render("%html{html_attrs}", :format => :xhtml)) end def test_html_attrs_html4; skip assert_equal("\n", render("%html{html_attrs}", :format => :html4)) end def test_html_attrs_html5; skip assert_equal("\n", render("%html{html_attrs}", :format => :html5)) end def test_html_attrs_xhtml_other_lang; skip assert_equal("\n", render("%html{html_attrs('es-AR')}", :format => :xhtml)) end def test_html_attrs_html4_other_lang; skip assert_equal("\n", render("%html{html_attrs('es-AR')}", :format => :html4)) end def test_html_attrs_html5_other_lang; skip assert_equal("\n", render("%html{html_attrs('es-AR')}", :format => :html5)) end def test_escape_once_should_work_on_frozen_strings begin Haml::Helpers.escape_once('foo'.freeze) rescue => e flunk e.message end end end hamlit-2.15.1/test/haml/markaby/000077500000000000000000000000001407657076200164225ustar00rootroot00000000000000hamlit-2.15.1/test/haml/markaby/standard.mab000066400000000000000000000036701407657076200207110ustar00rootroot00000000000000self << '' html(:xmlns=>'http://www.w3.org/1999/xhtml', 'xml:lang'=>'en-US') do head do title "Hampton Catlin Is Totally Awesome" meta("http-equiv" => "Content-Type", :content => "text/html; charset=utf-8") end body do # You're In my house now! div :class => "header" do self << %|Yes, ladies and gentileman. He is just that egotistical. Fantastic! This should be multi-line output The question is if this would translate! Ahah!| self << 1 + 9 + 8 + 2 #numbers should work and this should be ignored end div(:id => "body") { self << "Quotes should be loved! Just like people!"} 120.times do |number| number end self << "Wow.|" p do self << "Holy cow " + "multiline " + "tags! " + "A pipe (|) even!" self << [1, 2, 3].collect { |n| "PipesIgnored|" } self << [1, 2, 3].collect { |n| n.to_s }.join("|") end div(:class => "silent") do foo = String.new foo << "this" foo << " shouldn't" foo << " evaluate" self << foo + " but now it should!" # Woah crap a comment! end # That was a line that shouldn't close everything. ul(:class => "really cool") do ('a'..'f').each do |a| li a end end div((@should_eval = "with this text"), :id => "combo", :class => "of_divs_with_underscore") [ 104, 101, 108, 108, 111 ].map do |byte| byte.chr end div(:class => "footer") do strong("This is a really long ruby quote. It should be loved and wrapped because its more than 50 characters. This value may change in the future and this test may look stupid. \nSo, I'm just making it *really* long. God, I hope this works", :class => "shout") end end end hamlit-2.15.1/test/haml/mocks/000077500000000000000000000000001407657076200161105ustar00rootroot00000000000000hamlit-2.15.1/test/haml/mocks/article.rb000066400000000000000000000001701407657076200200560ustar00rootroot00000000000000class Article attr_accessor :id, :title, :body def initialize @id, @title, @body = 1, 'Hello', 'World' end endhamlit-2.15.1/test/haml/results/000077500000000000000000000000001407657076200164755ustar00rootroot00000000000000hamlit-2.15.1/test/haml/results/content_for_layout.xhtml000066400000000000000000000004571407657076200234760ustar00rootroot00000000000000
Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet
hamlit-2.15.1/test/haml/results/eval_suppressed.xhtml000066400000000000000000000001621407657076200227560ustar00rootroot00000000000000

Me!

All


This

Should render
hamlit-2.15.1/test/haml/results/helpers.xhtml000066400000000000000000000017021407657076200212150ustar00rootroot00000000000000&&&&&&&&&&&

Title

Woah this is really crazy I mean wow, man.

Title

Woah this is really crazy I mean wow, man.

Title

Woah this is really crazy I mean wow, man.

foo

reeeeeeeeeeeeeeeeeeeeeeeeeeeeeeally loooooooooooooooooong

Big!

Small

foo

bar

(parentheses!)
*Not really click here.

baz

boom

foo
  • google
  • foo

    bar
    boom baz boom, again

    strong! data more_data

    hamlit-2.15.1/test/haml/results/helpful.xhtml000066400000000000000000000006411407657076200212130ustar00rootroot00000000000000

    Hello

    World
    id
    class
    id class
    boo
    moo
    foo
    Boo hamlit-2.15.1/test/haml/results/just_stuff.xhtml000066400000000000000000000026121407657076200217500ustar00rootroot00000000000000 Boo! Embedded? false! Embedded? true! Embedded? true! Embedded? twice! true! Embedded? one af"t"er another!

    Embedded? false!

    Embedded? true!

    Embedded? true!

    Embedded? twice! true!

    Embedded? one af"t"er another!

    stuff followed by whitespace block with whitespace

    Escape - character %p foo yee\ha don't lstrip me

    class attribute should appear!

    this attribute shouldn't appear

    testtest


    Nested content

    Blah

    Blah

    Blah

    Blump

    Whee

    Woah inner quotes

    hello

    hamlit-2.15.1/test/haml/results/list.xhtml000066400000000000000000000001761407657076200205320ustar00rootroot00000000000000!Not a Doctype!
    • a
    • b
    • c
    • d
    • e
    • f
    • g
    • h
    • i
    hamlit-2.15.1/test/haml/results/nuke_inner_whitespace.xhtml000066400000000000000000000004211407657076200241210ustar00rootroot00000000000000

    Foo

    Foo

    Foo Bar

    Foo Bar

    Foo Bar

    Foo Bar

    Foo Bar

    Foo Bar

    foo bar

    hamlit-2.15.1/test/haml/results/nuke_outer_whitespace.xhtml000066400000000000000000000017141407657076200241520ustar00rootroot00000000000000

    Foo

    Foo

    Foo

    Foo

    Foo

    Foo

    Foo

    Foo

    Foo Bar

    Foo Bar

    Foo Bar

    Foo Bar

    foo Foo bar

    foo Foo bar

    fooFoobar

    fooFoobar

    foo Foo bar

    foo Foo bar

    fooFoobar

    fooFoobar

    foo Foo Bar bar

    foo Foo Bar bar

    fooFoo Barbar

    fooFoo Barbar

    hamlit-2.15.1/test/haml/results/original_engine.xhtml000066400000000000000000000007331407657076200227070ustar00rootroot00000000000000 Stop. haml time

    This is a title!

    Lorem ipsum dolor sit amet, consectetur adipisicing elit

    Cigarettes!

    Man alive!

    • Slippers
    • Shoes
    • Bathrobe
    • Coffee
    This is some text that's in a pre block!
    Let's see what happens when it's rendered! What about now, since we're on a new line?
    hamlit-2.15.1/test/haml/results/partial_layout.xhtml000066400000000000000000000002371407657076200226060ustar00rootroot00000000000000

    Partial layout used with for block:

    This is inside a partial layout

    Some content within a layout

    hamlit-2.15.1/test/haml/results/partial_layout_erb.xhtml000066400000000000000000000002301407657076200234270ustar00rootroot00000000000000

    Partial layout used with for block:

    This is inside a partial layout

    Some content within a layout
    hamlit-2.15.1/test/haml/results/partials.xhtml000066400000000000000000000002371407657076200213740ustar00rootroot00000000000000

    @foo = value one

    @foo = value two

    @foo = value two

    Toplevel? false

    @foo = value three

    @foo = value three

    hamlit-2.15.1/test/haml/results/render_layout.xhtml000066400000000000000000000000241407657076200224230ustar00rootroot00000000000000Before During After hamlit-2.15.1/test/haml/results/silent_script.xhtml000066400000000000000000000013031407657076200224320ustar00rootroot00000000000000

    I can count!

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

    I know my ABCs!

    • a
    • b
    • c
    • d
    • e
    • f
    • g
    • h
    • i
    • j
    • k
    • l
    • m
    • n
    • o
    • p
    • q
    • r
    • s
    • t
    • u
    • v
    • w
    • x
    • y
    • z

    I can catch errors!

    Oh no! "foo" happened!

    "false" is: false

    Even! Odd! Even! Odd! Even!
    foobar
    0 1 2 3 4

    boom

    hamlit-2.15.1/test/haml/results/standard.xhtml000066400000000000000000000030351407657076200213540ustar00rootroot00000000000000 Hampton Catlin Is Totally Awesome
    Yes, ladies and gentileman. He is just that egotistical. Fantastic! This should be multi-line output The question is if this would translate! Ahah! 20
    Quotes should be loved! Just like people!
    0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 Wow.|

    Holy cow multiline tags! A pipe (|) even! PipesIgnored|PipesIgnored|PipesIgnored| 1|2|3

    this shouldn't evaluate but now it should!
    • a
    • b
    • c
    • d
    • e
    • f
    with this text
    foo hamlit-2.15.1/test/haml/results/tag_parsing.xhtml000066400000000000000000000010031407657076200220430ustar00rootroot00000000000000
    1 2 3 4 5 6 7 8 9 10 11

    a
    b
    c
    d
    e
    f
    g
    hamlit-2.15.1/test/haml/results/very_basic.xhtml000066400000000000000000000000731407657076200217010ustar00rootroot00000000000000 hamlit-2.15.1/test/haml/results/whitespace_handling.xhtml000066400000000000000000000074701407657076200235630ustar00rootroot00000000000000
    Foo bar <pre>foo bar</pre> <pre>foo bar</pre>

    <pre>foo bar</pre>

    foo bar

    13 <textarea> a </textarea> <textarea> a </textarea>
    Foo bar
    foo bar
    foo
    bar

    foo
    bar

    foo bar

                                                     ___
                                                  ,o88888
                                               ,o8888888'
                         ,:o:o:oooo.        ,8O88Pd8888"
                     ,.::.::o:ooooOoOoO. ,oO8O8Pd888'"
                   ,.:.::o:ooOoOoOO8O8OOo.8OOPd8O8O"
                  , ..:.::o:ooOoOOOO8OOOOo.FdO8O8"
                 , ..:.::o:ooOoOO8O888O8O,COCOO"
                , . ..:.::o:ooOoOOOO8OOOOCOCO"
                 . ..:.::o:ooOoOoOO8O8OCCCC"o
                    . ..:.::o:ooooOoCoCCC"o:o
                    . ..:.::o:o:,cooooCo"oo:o:
                 `   . . ..:.:cocoooo"'o:o:::'
                 .`   . ..::ccccoc"'o:o:o:::'
                :.:.    ,c:cccc"':.:.:.:.:.'
              ..:.:"'`::::c:"'..:.:.:.:.:.'  http://www.chris.com/ASCII/
            ...:.'.:.::::"'    . . . . .'
           .. . ....:."' `   .  . . ''
         . . . ...."'
         .. . ."'     -hrr-
        .
    
    
                                                  It's a planet!
    %strong This shouldn't be bold!
    This should!
    13
           __     ______        __               ______
    .----.|  |--.|__    |.----.|  |--..--------.|  __  |
    |  __||     ||__    ||  __||    < |        ||  __  |
    |____||__|__||______||____||__|__||__|__|__||______|
    foo
    bar
    hamlit-2.15.1/test/haml/template_test.rb000066400000000000000000000227761407657076200202110ustar00rootroot00000000000000require 'test_helper' require 'haml/mocks/article' require 'action_pack/version' require 'hamlit/rails_template' module Haml::Filters::Test include Haml::Filters::Base def render(text) "TESTING HAHAHAHA!" end end module Hamlit::RailsHelpers def test_partial(name, locals = {}) Hamlit::Template.new { File.read(File.join(TemplateTest::TEMPLATE_PATH, "_#{name}.haml")) }.render(self, locals) end end class Egocentic def method_missing(*args) self end end class DummyController attr_accessor :logger def initialize @logger = Egocentic.new end def self.controller_path '' end def controller_path '' end end class TemplateTest < Haml::TestCase TEMPLATE_PATH = File.join(File.dirname(__FILE__), "templates") TEMPLATES = [ 'very_basic', #'standard', #'helpers', #'whitespace_handling', 'original_engine', 'list', 'helpful', 'silent_script', 'tag_parsing', #'just_stuff', #'partials', #'nuke_outer_whitespace', #'nuke_inner_whitespace', #'render_layout', #'partial_layout', 'partial_layout_erb', ] def setup @base = create_base # filters template uses :sass # Sass::Plugin.options.update(:line_comments => true, :style => :compact) end def create_base vars = { 'article' => Article.new, 'foo' => 'value one' } context = ActionView::LookupContext.new(TEMPLATE_PATH) base = ActionView::Base.new(context, vars, ActionController::Base.new) # This is needed by RJS in (at least) Rails 3 base.instance_variable_set(:@template, base) # This is used by form_for. # It's usually provided by ActionController::Base. def base.protect_against_forgery?; false; end def base.compiled_method_container() self.class; end base end def render(text, options = {}) return @base.render(:inline => text, :type => :haml) if options == :action_view options = options.merge(:format => :xhtml) super(text, options, @base) end def load_result(name) @result = '' File.new(File.dirname(__FILE__) + "/results/#{name}.xhtml").each_line { |l| @result += l } @result end def assert_renders_correctly(name, &render_method) old_options = Haml::Template.options.dup Haml::Template.options[:escape_html] = false render_method ||= proc { |n| @base.render(template: n) } silence_warnings do load_result(name).split("\n").zip(render_method[name].split("\n")).each_with_index do |pair, line| message = "template: #{name}\nline: #{line}" assert_equal(pair.first, pair.last, message) end end rescue ActionView::Template::Error => e if e.message =~ /Can't run [\w:]+ filter; required (one of|file) ((?:'\w+'(?: or )?)+)(, but none were found| not found)/ puts "\nCouldn't require #{$2}; skipping a test." else raise e end ensure Haml::Template.options = old_options end def test_empty_render_should_remain_empty assert_equal('', render('')) end TEMPLATES.each do |template| define_method "test_template_should_render_correctly [template: #{template}]" do assert_renders_correctly template end end def test_templates skip TEMPLATES end def test_render_method_returning_null_with_ugly; skip @base.instance_eval do def empty nil end def render_something(&block) capture(self, &block) end end content_to_render = "%h1 This is part of the broken view.\n= render_something do |thing|\n = thing.empty do\n = 'test'" result = render(content_to_render, :ugly => true) expected_result = "

    This is part of the broken view.

    \n" assert_equal(expected_result, result) end def test_simple_rendering_with_ugly skip assert_haml_ugly("%p test\n= capture { 'foo' }") end def test_templates_should_render_correctly_with_render_proc; skip assert_renders_correctly("standard") do |name| engine = Hamlit::HamlEngine.new(File.read(File.dirname(__FILE__) + "/templates/#{name}.haml"), :format => :xhtml) engine.render_proc(@base).call end end def test_templates_should_render_correctly_with_def_method; skip assert_renders_correctly("standard") do |name| engine = Haml::HamlEngine.new(File.read(File.dirname(__FILE__) + "/templates/#{name}.haml"), :format => :xhtml) engine.def_method(@base, "render_standard") @base.render_standard end end def test_instance_variables_should_work_inside_templates @base.instance_variable_set(:@content_for_layout, 'something') assert_haml_ugly("%p= @content_for_layout", scope: @base) @base.instance_eval("@author = 'Hampton Catlin'") assert_haml_ugly(".author= @author", scope: @base) @base.instance_eval("@author = 'Hampton'") assert_haml_ugly("= @author", scope: @base) @base.instance_eval("@author = 'Catlin'") assert_haml_ugly("= @author", scope: @base) end def test_instance_variables_should_work_inside_attributes skip @base.instance_eval("@author = 'hcatlin'") assert_haml_ugly("%p{:class => @author} foo") end def test_template_renders_should_eval assert_equal("2\n", render("= 1+1")) end def test_haml_options; skip old_options = Haml::Template.options.dup Haml::Template.options[:suppress_eval] = true old_base, @base = @base, create_base assert_renders_correctly("eval_suppressed") ensure skip @base = old_base Haml::Template.options = old_options end def test_with_output_buffer_with_ugly; skip assert_equal(< true))

    foo baz

    HTML %p foo -# Parenthesis required due to Rails 3.0 deprecation of block helpers -# that return strings. - (with_output_buffer do bar = "foo".gsub(/./) do |s| - "flup" - end) baz HAML end def test_exceptions_should_work_correctly; skip begin render("- raise 'oops!'") rescue Exception => e assert_equal("oops!", e.message) assert_match(/^\(haml\):1/, e.backtrace[0]) else assert false end template = < e assert_match(/^\(haml\):5/, e.backtrace[0]) else assert false end end def test_form_builder_label_with_block; skip output = render(< :article, :html => {:class => nil, :id => nil}, :url => '' do |f| = f.label :title do Block content HAML fragment = Nokogiri::HTML.fragment output assert_equal "Block content", fragment.css('form label').first.content.strip end ## XSS Protection Tests def test_escape_html_option_set; skip assert Haml::Template.options[:escape_html] end def test_xss_protection; skip assert_equal("Foo & Bar\n", render('= "Foo & Bar"', :action_view)) end def test_xss_protection_with_safe_strings; skip assert_equal("Foo & Bar\n", render('= Haml::Util.html_safe("Foo & Bar")', :action_view)) end def test_xss_protection_with_bang; skip assert_haml_ugly('!= "Foo & Bar"', :action_view) end def test_xss_protection_in_interpolation; skip assert_equal("Foo & Bar\n", render('Foo #{"&"} Bar', :action_view)) end def test_xss_protection_in_attributes; skip assert_equal("
    \n", render('%div{ "data-html" => "bar" }', :action_view)) end def test_xss_protection_in_attributes_with_safe_strings; skip assert_equal("
    \n", render('%div{ "data-html" => "bar".html_safe }', :action_view)) end def test_xss_protection_with_bang_in_interpolation; skip assert_haml_ugly('! Foo #{"&"} Bar', :action_view) end def test_xss_protection_with_safe_strings_in_interpolation; skip assert_equal("Foo & Bar\n", render('Foo #{Haml::Util.html_safe("&")} Bar', :action_view)) end def test_xss_protection_with_mixed_strings_in_interpolation; skip assert_equal("Foo & Bar & Baz\n", render('Foo #{Haml::Util.html_safe("&")} Bar #{"&"} Baz', :action_view)) end def test_rendered_string_is_html_safe; skip assert(render("Foo").html_safe?) end def test_rendered_string_is_html_safe_with_action_view assert(render("Foo", :action_view).html_safe?) end def test_xss_html_escaping_with_non_strings assert_haml_ugly("= html_escape(4)") end def test_xss_protection_with_concat; skip assert_equal("Foo & Bar", render('- concat "Foo & Bar"', :action_view)) end def test_xss_protection_with_concat_with_safe_string; skip assert_equal("Foo & Bar", render('- concat(Haml::Util.html_safe("Foo & Bar"))', :action_view)) end def test_xss_protection_with_safe_concat; skip assert_equal("Foo & Bar", render('- safe_concat "Foo & Bar"', :action_view)) end ## Regression def test_xss_protection_with_nested_haml_tag; skip assert_equal(<
    • Content!
    HTML - haml_tag :div do - haml_tag :ul do - haml_tag :li, "Content!" HAML end if defined?(ActionView::Helpers::PrototypeHelper) def test_rjs assert_equal(< 'templates/av_partial_2'hamlit-2.15.1/test/haml/templates/_av_partial_1_ugly.haml000066400000000000000000000003421407657076200233750ustar00rootroot00000000000000%h2 This is a pretty complicated partial .partial %p It has several nested partials, %ul - 5.times do %li %strong Partial: - @nesting = 5 = render :partial => 'templates/av_partial_2_ugly'hamlit-2.15.1/test/haml/templates/_av_partial_2.haml000066400000000000000000000002701407657076200223360ustar00rootroot00000000000000- @nesting -= 1 .partial{:level => @nesting} %h3 This is a crazy deep-nested partial. %p== Nesting level #{@nesting} = render :partial => 'templates/av_partial_2' if @nesting > 0hamlit-2.15.1/test/haml/templates/_av_partial_2_ugly.haml000066400000000000000000000002751407657076200234030ustar00rootroot00000000000000- @nesting -= 1 .partial{:level => @nesting} %h3 This is a crazy deep-nested partial. %p== Nesting level #{@nesting} = render :partial => 'templates/av_partial_2_ugly' if @nesting > 0hamlit-2.15.1/test/haml/templates/_layout.erb000066400000000000000000000000331407657076200211340ustar00rootroot00000000000000Before <%= yield -%> After hamlit-2.15.1/test/haml/templates/_layout_for_partial.haml000066400000000000000000000000771407657076200236770ustar00rootroot00000000000000.partial-layout %h2 This is inside a partial layout = yieldhamlit-2.15.1/test/haml/templates/_partial.haml000066400000000000000000000001511407657076200214250ustar00rootroot00000000000000%p @foo = = @foo - @foo = 'value three' == Toplevel? #{haml_buffer.toplevel?} %p @foo = = @foo hamlit-2.15.1/test/haml/templates/_text_area.haml000066400000000000000000000001361407657076200217500ustar00rootroot00000000000000.text_area_test_area ~ "" = "" hamlit-2.15.1/test/haml/templates/_text_area_helper.html.haml000066400000000000000000000001421407657076200242470ustar00rootroot00000000000000- defined?(text_area_helper) and nil # silence a warning .foo .bar = text_area :post, :body hamlit-2.15.1/test/haml/templates/action_view.haml000066400000000000000000000033651407657076200221530ustar00rootroot00000000000000!!! %html{html_attrs} %head %title Hampton Catlin Is Totally Awesome %meta{"http-equiv" => "Content-Type", :content => "text/html; charset=utf-8"} %body %h1 This is very much like the standard template, except that it has some ActionView-specific stuff. It's only used for benchmarking. .crazy_partials= render :partial => 'templates/av_partial_1' / You're In my house now! .header Yes, ladies and gentileman. He is just that egotistical. Fantastic! This should be multi-line output The question is if this would translate! Ahah! = 1 + 9 + 8 + 2 #numbers should work and this should be ignored #body= " Quotes should be loved! Just like people!" - 120.times do |number| - number Wow.| %p = "Holy cow " + | "multiline " + | "tags! " + | "A pipe (|) even!" | = [1, 2, 3].collect { |n| "PipesIgnored|" } = [1, 2, 3].collect { |n| | n.to_s | }.join("|") | %div.silent - foo = String.new - foo << "this" - foo << " shouldn't" - foo << " evaluate" = foo + " but now it should!" -# Woah crap a comment! -# That was a line that shouldn't close everything. %ul.really.cool - ('a'..'f').each do |a| %li= a #combo.of_divs_with_underscore= @should_eval = "with this text" = [ 104, 101, 108, 108, 111 ].map do |byte| - byte.chr .footer %strong.shout= "This is a really long ruby quote. It should be loved and wrapped because its more than 50 characters. This value may change in the future and this test may look stupid. \nSo, I'm just making it *really* long. God, I hope this works" hamlit-2.15.1/test/haml/templates/action_view_ugly.haml000066400000000000000000000033721407657076200232110ustar00rootroot00000000000000!!! %html{html_attrs} %head %title Hampton Catlin Is Totally Awesome %meta{"http-equiv" => "Content-Type", :content => "text/html; charset=utf-8"} %body %h1 This is very much like the standard template, except that it has some ActionView-specific stuff. It's only used for benchmarking. .crazy_partials= render :partial => 'templates/av_partial_1_ugly' / You're In my house now! .header Yes, ladies and gentileman. He is just that egotistical. Fantastic! This should be multi-line output The question is if this would translate! Ahah! = 1 + 9 + 8 + 2 #numbers should work and this should be ignored #body= " Quotes should be loved! Just like people!" - 120.times do |number| - number Wow.| %p = "Holy cow " + | "multiline " + | "tags! " + | "A pipe (|) even!" | = [1, 2, 3].collect { |n| "PipesIgnored|" } = [1, 2, 3].collect { |n| | n.to_s | }.join("|") | %div.silent - foo = String.new - foo << "this" - foo << " shouldn't" - foo << " evaluate" = foo + " but now it should!" -# Woah crap a comment! -# That was a line that shouldn't close everything. %ul.really.cool - ('a'..'f').each do |a| %li= a #combo.of_divs_with_underscore= @should_eval = "with this text" = [ 104, 101, 108, 108, 111 ].map do |byte| - byte.chr .footer %strong.shout= "This is a really long ruby quote. It should be loved and wrapped because its more than 50 characters. This value may change in the future and this test may look stupid. \nSo, I'm just making it *really* long. God, I hope this works" hamlit-2.15.1/test/haml/templates/breakage.haml000066400000000000000000000001751407657076200214010ustar00rootroot00000000000000%p %h1 Hello! = "lots of lines" - raise "Oh no!" %p this is after the exception %strong yes it is! ho ho ho. hamlit-2.15.1/test/haml/templates/content_for_layout.haml000066400000000000000000000001251407657076200235500ustar00rootroot00000000000000!!! %html %head %body #yieldy = yield :layout #nosym = yield hamlit-2.15.1/test/haml/templates/eval_suppressed.haml000066400000000000000000000002131407657076200230350ustar00rootroot00000000000000= "not me!" = "nor me!" - haml_concat "not even me!" %p= "NO!" %p~ "UH-UH!" %h1 Me! #foo %p#bar All %br/ %p.baz This Should render hamlit-2.15.1/test/haml/templates/helpers.haml000066400000000000000000000022611407657076200213000ustar00rootroot00000000000000= h("&&&&&&&&&&&") # This is an ActionView Helper... should load - foo = capture do # This ActionView Helper is designed for ERB, but should work with haml %div %p.title Title %p.text Woah this is really crazy I mean wow, man. - 3.times do = foo %p foo - tab_up %p reeeeeeeeeeeeeeeeeeeeeeeeeeeeeeally loooooooooooooooooong - tab_down .woah #funky = capture_haml do %div %h1 Big! %p Small / Invisible = capture do .dilly %p foo %h1 bar = surround '(', ')' do %strong parentheses! = precede '*' do %span.small Not really click = succeed '.' do %a{:href=>"thing"} here %p baz - haml_buffer.tabulation = 10 %p boom - concat "foo\n" - haml_buffer.tabulation = 0 = list_of({:google => 'http://www.google.com'}) do |name, link| %a{ :href => link }= name %p - haml_concat "foo" %div - haml_concat "bar" - haml_concat "boom" baz - haml_concat "boom, again" - haml_tag :table do - haml_tag :tr do - haml_tag :td, {:class => 'cell'} do - haml_tag :strong, "strong!" - haml_concat "data" - haml_tag :td do - haml_concat "more_data" - haml_tag :hr - haml_tag :div, '' hamlit-2.15.1/test/haml/templates/helpful.haml000066400000000000000000000004651407657076200213010ustar00rootroot00000000000000%div[@article] %h1= @article.title %div= @article.body #id[@article] id .class[@article] class #id.class[@article] id class %div{:class => "article full"}[@article]= "boo" %div{'class' => "article full"}[@article]= "moo" %div.articleFull[@article]= "foo" %span[@not_a_real_variable_and_will_be_nil] Boo hamlit-2.15.1/test/haml/templates/just_stuff.haml000066400000000000000000000032551407657076200220360ustar00rootroot00000000000000!!! XML !!! XML ISO-8859-1 !!! XML UtF-8 Foo bar !!! !!! 1.1 !!! 1.1 Strict !!! Strict foo bar !!! FRAMESET %strong{:apos => "Foo's bar!"} Boo! == Embedded? false! == Embedded? #{true}! - embedded = true == Embedded? #{embedded}! == Embedded? #{"twice! #{true}"}! == Embedded? #{"one"} af"t"er #{"another"}! %p== Embedded? false! %p== Embedded? #{true}! - embedded = true %p== Embedded? #{embedded}! %p== Embedded? #{"twice! #{true}"}! %p== Embedded? #{"one"} af"t"er #{"another"}! = "stuff followed by whitespace" - if true %strong block with whitespace %p \Escape \- character \%p foo \yee\ha \ don't lstrip me / Short comment / This is a block comment cool, huh? %strong there can even be sub-tags! = "Or script!" -# Haml comment -# Nested Haml comment - raise 'dead' %p{ :class => "" } class attribute should appear! %p{ :gorbachev => nil } this attribute shouldn't appear /[if lte IE6] conditional comment! /[if gte IE7] %p Block conditional comment %div %h1 Cool, eh? /[if gte IE5.2] Woah a period. = "test" | "test" | -# Hard tabs shouldn't throw errors. - case :foo - when :bar %br Blah - when :foo %br - case :foo - when :bar %meta{ :foo => 'blah'} - when :foo %meta{ :foo => 'bar'} %img %hr %link %script Inline content %br Nested content %p.foo{:class => true ? 'bar' : 'baz'}[@article] Blah %p.foo{:class => false ? 'bar' : ''}[@article] Blah %p.foo{:class => %w[bar baz]}[@article] Blah %p.qux{:class => 'quux'}[@article] Blump %p#foo{:id => %w[bar baz]}[@article] Whee == #{"Woah inner quotes"} %p.dynamic_quote{:quotes => "single '", :dyn => 1 + 2} %p.dynamic_self_closing{:dyn => 1 + 2}/ %body :plain hello %div %img hamlit-2.15.1/test/haml/templates/list.haml000066400000000000000000000001351407657076200206070ustar00rootroot00000000000000!Not a Doctype! %ul %li a %li b %li c %li d %li e %li f %li g %li h %li i hamlit-2.15.1/test/haml/templates/nuke_inner_whitespace.haml000066400000000000000000000004641407657076200242120ustar00rootroot00000000000000%p %q< Foo %p %q{:a => 1 + 1}< Foo %p %q<= "Foo\nBar" %p %q{:a => 1 + 1}<= "Foo\nBar" %p %q< Foo Bar %p %q{:a => 1 + 1}< Foo Bar %p %q< %div Foo Bar %p %q{:a => 1 + 1}< %div Foo Bar -# Regression test %p %q<= "foo" %q{:a => 1 + 1} bar hamlit-2.15.1/test/haml/templates/nuke_outer_whitespace.haml000066400000000000000000000026201407657076200242310ustar00rootroot00000000000000%p %p %q> Foo %p %p %q{:a => 1 + 1}> Foo %p %p %q> Foo %p %p %q{:a => 1 + 1}> Foo %p %p %q> = "Foo" %p %p %q{:a => 1 + 1}> = "Foo" %p %p %q>= "Foo" %p %p %q{:a => 1 + 1}>= "Foo" %p %p %q> = "Foo\nBar" %p %p %q{:a => 1 + 1}> = "Foo\nBar" %p %p %q>= "Foo\nBar" %p %p %q{:a => 1 + 1}>= "Foo\nBar" %p %p - tab_up foo %q> Foo bar - tab_down %p %p - tab_up foo %q{:a => 1 + 1}> Foo bar - tab_down %p %p - tab_up foo %q> Foo bar - tab_down %p %p - tab_up foo %q{:a => 1 + 1}> Foo bar - tab_down %p %p - tab_up foo %q> = "Foo" bar - tab_down %p %p - tab_up foo %q{:a => 1 + 1}> = "Foo" bar - tab_down %p %p - tab_up foo %q>= "Foo" bar - tab_down %p %p - tab_up foo %q{:a => 1 + 1}>= "Foo" bar - tab_down %p %p - tab_up foo %q> = "Foo\nBar" bar - tab_down %p %p - tab_up foo %q{:a => 1 + 1}> = "Foo\nBar" bar - tab_down %p %p - tab_up foo %q>= "Foo\nBar" bar - tab_down %p %p - tab_up foo %q{:a => 1 + 1}>= "Foo\nBar" bar - tab_down %p %p %q> %p %p %q>/ %p %p %q{:a => 1 + 1}> %p %p %q{:a => 1 + 1}>/ hamlit-2.15.1/test/haml/templates/original_engine.haml000066400000000000000000000007141407657076200227700ustar00rootroot00000000000000!!! %html %head %title Stop. haml time #content %h1 This is a title! %p Lorem ipsum dolor sit amet, consectetur adipisicing elit %p{:class => 'foo'} Cigarettes! %h2 Man alive! %ul.things %li Slippers %li Shoes %li Bathrobe %li Coffee %pre This is some text that's in a pre block! Let's see what happens when it's rendered! What about now, since we're on a new line? hamlit-2.15.1/test/haml/templates/partial_layout.haml000066400000000000000000000001661407657076200226710ustar00rootroot00000000000000%h1 Partial layout used with for block: = render :layout => 'layout_for_partial' do %p Some content within a layout hamlit-2.15.1/test/haml/templates/partial_layout_erb.erb000066400000000000000000000002061407657076200233430ustar00rootroot00000000000000

    Partial layout used with for block:

    <%= render :layout => 'layout_for_partial' do -%> Some content within a layout <% end %> hamlit-2.15.1/test/haml/templates/partialize.haml000066400000000000000000000000411407657076200217740ustar00rootroot00000000000000= render :file => "#{name}.haml" hamlit-2.15.1/test/haml/templates/partials.haml000066400000000000000000000002051407657076200214510ustar00rootroot00000000000000- @foo = 'value one' %p @foo = = @foo - @foo = 'value two' %p @foo = = @foo = test_partial "partial" %p @foo = = @foo hamlit-2.15.1/test/haml/templates/render_layout.haml000066400000000000000000000000511407657076200225050ustar00rootroot00000000000000= render :layout => 'layout' do During hamlit-2.15.1/test/haml/templates/silent_script.haml000066400000000000000000000012661407657076200225240ustar00rootroot00000000000000%div %h1 I can count! - (1..20).each do |i| = i %h1 I know my ABCs! %ul - ('a'..'z').each do |i| %li= i %h1 I can catch errors! - begin - raise "foo" - rescue RuntimeError => e = "Oh no! \"#{e}\" happened!" %p "false" is: - if false = "true" - else = "false" - if true - 5.times do |i| - if i % 2 == 1 Odd! - else Even! - unless true Testing else indent - case 1 - when 2 Also testing else indent - else = "This can't happen!" - 13 | .foo %strong foobar - 5.times | do | |a| | %strong= a .test - "foo | bar | baz" | %p boom hamlit-2.15.1/test/haml/templates/standard.haml000066400000000000000000000031741407657076200214420ustar00rootroot00000000000000!!! %html{:xmlns => "http://www.w3.org/1999/xhtml", "xml:lang" => "en-US", "lang" => "en-US"} %head %title Hampton Catlin Is Totally Awesome %meta{"http-equiv" => "Content-Type", :content => "text/html; charset=utf-8"} %body / You're In my house now! .header Yes, ladies and gentileman. He is just that egotistical. Fantastic! This should be multi-line output The question is if this would translate! Ahah! = 1 + 9 + 8 + 2 #numbers should work and this should be ignored #body= " Quotes should be loved! Just like people!" - 120.times do |number| = number Wow.| %p{:code => 1 + 2} = "Holy cow " + | "multiline " + | "tags! " + | "A pipe (|) even!" | = [1, 2, 3].collect { |n| "PipesIgnored|" }.join = [1, 2, 3].collect { |n| | n.to_s | }.join("|") | - bar = 17 %div.silent{:foo => bar} - foo = String.new - foo << "this" - foo << " shouldn't" - foo << " evaluate" = foo + " but now it should!" -# Woah crap a comment! -# That was a line that shouldn't close everything. %ul.really.cool - ('a'..'f').each do |a| %li= a #combo.of_divs_with_underscore= @should_eval = "with this text" = "foo".each_line do |line| - nil .footer %strong.shout= "This is a really long ruby quote. It should be loved and wrapped because its more than 50 characters. This value may change in the future and this test may look stupid. \nSo, I'm just making it *really* long. God, I hope this works" hamlit-2.15.1/test/haml/templates/standard_ugly.haml000066400000000000000000000031741407657076200225020ustar00rootroot00000000000000!!! %html{:xmlns => "http://www.w3.org/1999/xhtml", "xml:lang" => "en-US", "lang" => "en-US"} %head %title Hampton Catlin Is Totally Awesome %meta{"http-equiv" => "Content-Type", :content => "text/html; charset=utf-8"} %body / You're In my house now! .header Yes, ladies and gentileman. He is just that egotistical. Fantastic! This should be multi-line output The question is if this would translate! Ahah! = 1 + 9 + 8 + 2 #numbers should work and this should be ignored #body= " Quotes should be loved! Just like people!" - 120.times do |number| = number Wow.| %p{:code => 1 + 2} = "Holy cow " + | "multiline " + | "tags! " + | "A pipe (|) even!" | = [1, 2, 3].collect { |n| "PipesIgnored|" }.join = [1, 2, 3].collect { |n| | n.to_s | }.join("|") | - bar = 17 %div.silent{:foo => bar} - foo = String.new - foo << "this" - foo << " shouldn't" - foo << " evaluate" = foo + " but now it should!" -# Woah crap a comment! -# That was a line that shouldn't close everything. %ul.really.cool - ('a'..'f').each do |a| %li= a #combo.of_divs_with_underscore= @should_eval = "with this text" = "foo".each_line do |line| - nil .footer %strong.shout= "This is a really long ruby quote. It should be loved and wrapped because its more than 50 characters. This value may change in the future and this test may look stupid. \nSo, I'm just making it *really* long. God, I hope this works" hamlit-2.15.1/test/haml/templates/tag_parsing.haml000066400000000000000000000004151407657076200221330ustar00rootroot00000000000000%div.tags %foo 1 %FOO 2 %fooBAR 3 %fooBar 4 %foo_bar 5 %foo-bar 6 %foo:bar 7 %foo.bar 8 %fooBAr_baz:boom_bar 9 %foo13 10 %foo2u 11 %div.classes %p.foo.bar#baz#boom .fooBar a .foo-bar b .foo_bar c .FOOBAR d .foo16 e .123 f .foo2u g hamlit-2.15.1/test/haml/templates/very_basic.haml000066400000000000000000000000321407657076200217560ustar00rootroot00000000000000!!! %html %head %body hamlit-2.15.1/test/haml/templates/whitespace_handling.haml000066400000000000000000000064571407657076200236510ustar00rootroot00000000000000#whitespace_test = test_partial "text_area", :value => "Oneline" = test_partial "text_area", :value => "Two\nlines" ~ test_partial "text_area", :value => "Oneline" ~ test_partial "text_area", :value => "Two\nlines" #flattened~ test_partial "text_area", :value => "Two\nlines" .hithere ~ "Foo bar" ~ "
    foo bar
    " ~ "
    foo\nbar
    " %p~ "
    foo\nbar
    " %p~ "foo\nbar" .foo ~ 13 ~ "".each_line do |l| - haml_concat l.strip #whitespace_test = test_partial "text_area", :value => "Oneline" = test_partial "text_area", :value => "Two\nlines" = find_and_preserve test_partial("text_area", :value => "Oneline") = find_and_preserve test_partial("text_area", :value => "Two\nlines") #flattened= find_and_preserve test_partial("text_area", :value => "Two\nlines") .hithere = find_and_preserve("Foo bar") = find_and_preserve("
    foo bar
    ") = find_and_preserve("
    foo\nbar
    ") %p= find_and_preserve("
    foo\nbar
    ") %p= find_and_preserve("foo\nbar") %pre :preserve ___ ,o88888 ,o8888888' ,:o:o:oooo. ,8O88Pd8888" ,.::.::o:ooooOoOoO. ,oO8O8Pd888'" ,.:.::o:ooOoOoOO8O8OOo.8OOPd8O8O" , ..:.::o:ooOoOOOO8OOOOo.FdO8O8" , ..:.::o:ooOoOO8O888O8O,COCOO" , . ..:.::o:ooOoOOOO8OOOOCOCO" . ..:.::o:ooOoOoOO8O8OCCCC"o . ..:.::o:ooooOoCoCCC"o:o . ..:.::o:o:,cooooCo"oo:o: ` . . ..:.:cocoooo"'o:o:::' .` . ..::ccccoc"'o:o:o:::' :.:. ,c:cccc"':.:.:.:.:.' ..:.:"'`::::c:"'..:.:.:.:.:.' http://www.chris.com/ASCII/ ...:.'.:.::::"' . . . . .' .. . ....:."' ` . . . '' . . . ...."' .. . ."' -hrr- . It's a planet! %strong This shouldn't be bold! %strong This should! %textarea :preserve ___ ___ ___ ___ /\__\ /\ \ /\__\ /\__\ /:/ / /::\ \ /::| | /:/ / /:/__/ /:/\:\ \ /:|:| | /:/ / /::\ \ ___ /::\~\:\ \ /:/|:|__|__ /:/ / /:/\:\ /\__\ /:/\:\ \:\__\ /:/ |::::\__\ /:/__/ \/__\:\/:/ / \/__\:\/:/ / \/__/~~/:/ / \:\ \ \::/ / \::/ / /:/ / \:\ \ /:/ / /:/ / /:/ / \:\ \ /:/ / /:/ / /:/ / \:\__\ \/__/ \/__/ \/__/ \/__/ Many thanks to http://www.network-science.de/ascii/ %strong indeed! .foo = find_and_preserve(13) %pre :preserve __ ______ __ ______ .----.| |--.|__ |.----.| |--..--------.| __ | | __|| ||__ || __|| < | || __ | |____||__|__||______||____||__|__||__|__|__||______| %pre :preserve foo bar hamlit-2.15.1/test/haml/templates/with_bom.haml000066400000000000000000000000071407657076200214420ustar00rootroot00000000000000BOMGhamlit-2.15.1/test/hamlit/000077500000000000000000000000001407657076200153315ustar00rootroot00000000000000hamlit-2.15.1/test/hamlit/attribute_parser_test.rb000066400000000000000000000115531407657076200223010ustar00rootroot00000000000000describe Hamlit::AttributeParser do describe '.parse' do def assert_parse(expected, haml) actual = Hamlit::AttributeParser.parse(haml) if expected.nil? assert_nil actual else assert_equal expected, actual end end it { assert_parse({}, '') } it { assert_parse({}, '{}') } describe 'invalid hash' do it { assert_parse(nil, ' hash ') } it { assert_parse(nil, 'hash, foo: bar') } it { assert_parse(nil, ' {hash} ') } it { assert_parse(nil, ' { hash, foo: bar } ') } end describe 'dynamic key' do it { assert_parse(nil, 'foo => bar') } it { assert_parse(nil, '[] => bar') } it { assert_parse(nil, '[1,2,3] => bar') } end describe 'foo: bar' do it { assert_parse({ '_' => '1' }, '_:1,') } it { assert_parse({ 'foo' => 'bar' }, ' foo: bar ') } it { assert_parse({ 'a' => 'b', 'c' => ':d' }, 'a: b, c: :d') } it { assert_parse({ 'a' => '[]', 'c' => '"d"' }, 'a: [], c: "d"') } it { assert_parse({ '_' => '1' }, ' { _:1, } ') } it { assert_parse({ 'foo' => 'bar' }, ' { foo: bar } ') } it { assert_parse({ 'a' => 'b', 'c' => ':d' }, ' { a: b, c: :d } ') } it { assert_parse({ 'a' => '[]', 'c' => '"d"' }, ' { a: [], c: "d" } ') } end describe ':foo => bar' do it { assert_parse({ 'foo' => ':bar' }, ' :foo => :bar ') } it { assert_parse({ '_' => '"foo"' }, ':_=>"foo"') } it { assert_parse({ 'a' => '[]', 'c' => '""', 'b' => '"#{3}"' }, ':a => [], c: "", :b => "#{3}"') } it { assert_parse({ 'foo' => ':bar' }, ' { :foo => :bar } ') } it { assert_parse({ '_' => '"foo"' }, ' { :_=>"foo" } ') } it { assert_parse({ 'a' => '[]', 'c' => '""', 'b' => '"#{3}"' }, ' { :a => [], c: "", :b => "#{3}" } ') } it { assert_parse(nil, ':"f#{o}o" => bar') } it { assert_parse(nil, ':"#{f}oo" => bar') } it { assert_parse(nil, ':"#{foo}" => bar') } end describe '"foo" => bar' do it { assert_parse({ 'foo' => '[1]' }, '"foo"=>[1]') } it { assert_parse({ 'foo' => 'nya' }, " 'foo' => nya ") } it { assert_parse({ 'foo' => 'bar' }, '%q[foo] => bar ') } it { assert_parse({ 'foo' => '[1]' }, ' { "foo"=>[1] } ') } it { assert_parse({ 'foo' => 'nya' }, " { 'foo' => nya } ") } it { assert_parse({ 'foo' => 'bar' }, ' { %q[foo] => bar } ') } it { assert_parse(nil, '"f#{o}o" => bar') } it { assert_parse(nil, '"#{f}oo" => bar') } it { assert_parse(nil, '"#{foo}" => bar') } it { assert_parse({ 'f#{o}o' => 'bar' }, '%q[f#{o}o] => bar ') } it { assert_parse({ 'f#{o}o' => 'bar' }, ' { %q[f#{o}o] => bar, } ') } it { assert_parse(nil, '%Q[f#{o}o] => bar ') } end if RUBY_VERSION >= '2.2.0' describe '"foo": bar' do it { assert_parse({ 'foo' => '()' }, '"foo":()') } it { assert_parse({ 'foo' => 'nya' }, " 'foo': nya ") } it { assert_parse({ 'foo' => '()' }, ' { "foo":() , }') } it { assert_parse({ 'foo' => 'nya' }, " { 'foo': nya , }") } it { assert_parse(nil, '"f#{o}o": bar') } it { assert_parse(nil, '"#{f}oo": bar') } it { assert_parse(nil, '"#{foo}": bar') } end end describe 'nested array' do it { assert_parse({ 'foo' => '[1,2,]' }, 'foo: [1,2,],') } it { assert_parse({ 'foo' => '[1,2,[3,4],5]' }, 'foo: [1,2,[3,4],5],') } it { assert_parse({ 'foo' => '[1,2,[3,4],5]', 'bar' => '[[1,2],]'}, 'foo: [1,2,[3,4],5],bar: [[1,2],],') } it { assert_parse({ 'foo' => '[1,2,]' }, ' { foo: [1,2,], } ') } it { assert_parse({ 'foo' => '[1,2,[3,4],5]' }, ' { foo: [1,2,[3,4],5], } ') } it { assert_parse({ 'foo' => '[1,2,[3,4],5]', 'bar' => '[[1,2],]'}, ' { foo: [1,2,[3,4],5],bar: [[1,2],], } ') } end describe 'nested hash' do it { assert_parse({ 'foo' => '{ }', 'bar' => '{}' }, 'foo: { }, bar: {}') } it { assert_parse({ 'foo' => '{ bar: baz, hoge: fuga, }' }, 'foo: { bar: baz, hoge: fuga, }, ') } it { assert_parse({ 'data' => '{ confirm: true, disable: false }', 'hello' => '{ world: foo, }' }, 'data: { confirm: true, disable: false }, :hello => { world: foo, },') } it { assert_parse({ 'foo' => '{ }', 'bar' => '{}' }, ' { foo: { }, bar: {} } ') } it { assert_parse({ 'foo' => '{ bar: baz, hoge: fuga, }' }, ' { foo: { bar: baz, hoge: fuga, }, } ') } it { assert_parse({ 'data' => '{ confirm: true, disable: false }', 'hello' => '{ world: foo, }' }, ' { data: { confirm: true, disable: false }, :hello => { world: foo, }, } ') } end describe 'nested method' do it { assert_parse({ 'foo' => 'bar(a, b)', 'hoge' => 'piyo(a, b,)' }, 'foo: bar(a, b), hoge: piyo(a, b,),') } it { assert_parse({ 'foo' => 'bar(a, b)', 'hoge' => 'piyo(a, b,)' }, ' { foo: bar(a, b), hoge: piyo(a, b,), } ') } end end if RUBY_ENGINE != 'truffleruby' # truffleruby doesn't have Ripper.lex end hamlit-2.15.1/test/hamlit/cli_test.rb000066400000000000000000000006371407657076200174720ustar00rootroot00000000000000require 'hamlit/cli' describe Hamlit::CLI do describe '#temple' do def redirect_output out, $stdout = $stdout, StringIO.new yield ensure $stdout = out end it 'does not crash when compiling a tag' do redirect_output do f = Tempfile.open('hamlit') f.write('%input{ hash }') f.close Hamlit::CLI.new.temple(f.path) end end end end hamlit-2.15.1/test/hamlit/dynamic_merger_test.rb000066400000000000000000000043361407657076200217100ustar00rootroot00000000000000describe Hamlit::DynamicMerger do describe '#call' do def assert_compile(expected, input) actual = Hamlit::DynamicMerger.new.compile(input) assert_equal expected, actual end def assert_noop(input) actual = Hamlit::DynamicMerger.new.compile(input) assert_equal input, actual end def strlit(body) "%Q\0#{body}\0" end specify { assert_compile([:static, 'foo'], [:multi, [:static, 'foo']]) } specify { assert_compile([:dynamic, 'foo'], [:multi, [:dynamic, 'foo']]) } specify { assert_noop([:multi, [:static, 'foo'], [:newline]]) } specify { assert_noop([:multi, [:dynamic, 'foo'], [:newline]]) } specify { assert_noop([:multi, [:static, "foo\n"], [:newline]]) } specify { assert_noop([:multi, [:static, 'foo'], [:dynamic, "foo\n"], [:newline]]) } specify { assert_noop([:multi, [:static, "foo\n"], [:dynamic, 'foo'], [:newline]]) } specify do assert_compile([:dynamic, strlit("\#{foo}foo\n")], [:multi, [:dynamic, 'foo'], [:static, "foo\n"], [:newline]]) end specify do assert_compile([:multi, [:dynamic, strlit("\#{foo}foo\n\n")], [:newline], [:code, 'foo'], ], [:multi, [:dynamic, 'foo'], [:static, "foo\n\n"], [:newline], [:newline], [:newline], [:code, 'foo'], ]) end specify do assert_compile([:multi, [:dynamic, strlit("\#{foo}foo\n")], [:code, 'bar'], [:dynamic, strlit("\#{foo}foo\n")], ], [:multi, [:dynamic, 'foo'], [:static, "foo\n"], [:newline], [:code, 'bar'], [:dynamic, 'foo'], [:static, "foo\n"], [:newline], ]) end specify do assert_compile([:multi, [:newline], [:dynamic, strlit("foo\n\#{foo}")]], [:multi, [:newline], [:newline], [:static, "foo\n"], [:dynamic, 'foo']]) end specify { assert_compile([:static, "\n"], [:multi, [:static, "\n"]]) } specify { assert_compile([:newline], [:multi, [:newline]]) } end end hamlit-2.15.1/test/hamlit/engine/000077500000000000000000000000001407657076200165765ustar00rootroot00000000000000hamlit-2.15.1/test/hamlit/engine/attributes_test.rb000066400000000000000000000510611407657076200223530ustar00rootroot00000000000000require_relative '../../test_helper' describe Hamlit::Engine do include RenderHelper describe 'id attributes' do describe 'compatilibity' do it { assert_haml(%q|#a|) } it { assert_haml(%q|#a{ id: nil }|) } it { assert_haml(%q|#a{ id: nil }(id=nil)|) } it { assert_haml(%q|#a{ id: false }|) } it { assert_haml(%q|#a{ id: 'b' }|) } it { assert_haml(%q|#b{ id: 'a' }|) } it { assert_haml(%q|%a{ 'id' => 60 }|) } if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.4.0') it { assert_haml(%q|%p{class: "a #{["1", "2", "3"].join}"} foo|) } end it { assert_haml(%q|#a{ id: 'b' }(id=id)|, locals: { id: 'c' }) } it { assert_haml(%q|#c{ id: a = 'a' }(id=id)|, locals: { id: 'b' }) } it { assert_haml(%q|#d#c{ id: a = 'b' }(id=id)|, locals: { id: 'a' }) } it { assert_haml(%q|#d#c{ id: %w[b e] }(id=id)|, locals: { id: 'a' }) } it { assert_haml(%q|%div{ hash }|, locals: { hash: { id: 'a' } }) } it { assert_haml(%q|#b{ hash }|, locals: { hash: { id: 'a' } }) } it { assert_haml(%q|#b{ hash }(id='c')|, locals: { hash: { id: 'a' }, id: 'c' }) } it { assert_haml(%q|#b{ hash }(id=id)|, locals: { hash: { id: 'a' }, id: 'c' }) } it { assert_haml(<<-HAML.unindent) } .haml#info{ "data": { "content": "/:|}", "haml-info": { "url": "https://haml.info", } } } Haml HAML end describe 'incompatibility' do it { assert_render(%Q|
    \n|, %q|#a{ id: [] }|) } it { assert_render(%Q|
    \n|, %q|%div{ id: [nil, false] }|) } it { assert_render(%Q|
    \n|, %q|#d#c{ id: [] }(id=id)|, locals: { id: 'a' }) } it { assert_render(%Q|
    \n|, %q|%div{ id: nil }|) } it { assert_render(%Q|\n|, %q|%input{ id: false }|) } it { assert_render(%Q|\n|, %q|%input{ id: val }|, locals: { val: false }) } it { assert_render(%Q|\n|, %q|%input{ hash }|, locals: { hash: { id: false } }) } end end describe 'class attributes' do describe 'compatibility' do it { assert_haml(%q|.bar.foo|) } it { assert_haml(%q|.foo.bar|) } it { assert_haml(%q|%div(class='bar foo')|) } it { assert_haml(%q|%div(class='foo bar')|) } it { assert_haml(%q|%div{ class: 'bar foo' }|) } it { assert_haml(%q|.b{ class: 'a' }|) } it { assert_haml(%q|.a{ class: 'b a' }|) } it { assert_haml(%q|.b.a{ class: 'b a' }|) } it { assert_haml(%q|.b{ class: 'b a' }|) } it { assert_haml(%q|.a{ class: klass }|, locals: { klass: 'b a' }) } it { assert_haml(%q|.b{ class: klass }|, locals: { klass: 'b a' }) } it { assert_haml(%q|.b.a{ class: klass }|, locals: { klass: 'b a' }) } it { assert_haml(%q|.b{ class: 'c a' }|) } it { assert_haml(%q|.b{ class: 'a c' }|) } it { assert_haml(%q|.a{ class: [] }|) } it { assert_haml(%q|.a{ class: %w[c b] }|) } it { assert_haml(%q|.a.c(class='b')|) } it { assert_haml(%q|%a{ 'class' => 60 }|) } it { assert_haml(%q|%div{ class: 'b a' }(class=klass)|, locals: { klass: 'b a' }) } it { assert_haml(%q|%div(class=klass){ class: 'b a' }|, locals: { klass: 'b a' }) } it { assert_haml(%q|.a.d(class=klass){ class: 'c d' }|, locals: { klass: 'b a' }) } it { assert_haml(%q|.a.d(class=klass)|, locals: { klass: 'b a' }) } it { assert_haml(%q|.a{:class => klass}|, locals: { klass: nil }) } it { assert_haml(%q|.a{:class => nil}(class=klass)|, locals: { klass: nil }) } it { assert_haml(%q|.a{:class => nil}|) } it { assert_haml(%q|.a{:class => false}|) } it { assert_haml(%q|.b{ hash, class: 'a' }|, locals: { hash: { class: nil } }) } it { assert_haml(%q|.b{ hash, :class => 'a' }|, locals: { hash: { class: nil } }) } it { assert_haml(%q|.b{ hash, 'class' => 'a' }|, locals: { hash: { class: nil } }) } it { assert_haml(%q|.a{ hash }|, locals: { hash: { class: 'd' } }) } it { assert_haml(%q|.b{ hash, class: 'a' }(class='c')|, locals: { hash: { class: 'd' } }) } it { assert_haml(%q|.b{ hash, class: 'a' }(class=klass)|, locals: { hash: { class: 'd' }, klass: nil }) } it { assert_haml(%q|%div{ class: 'b a' }|) } it { assert_haml(%q|%div{ class: klass }|, locals: { klass: 'b a' }) } it { assert_haml(%q|%div(class='b a')|) } it { assert_haml(%q|%div(class=klass)|, locals: { klass: 'b a' }) } it { assert_haml(%q|%div{ class: [false, 'a', nil] }|) } it { assert_haml(%q|%div{ class: %q[b a] }|) } it { assert_haml(%q|%div{ class: %q[b a b] }|) } it { assert_haml(%q|%span.c2{class: ["c1", "c3", :c2]}|) } it { assert_haml(%q|%span{class: [1, nil, false, true]}|) } it do assert_haml(<<-HAML.unindent) - v = [1, nil, false, true] %span{class: v} HAML end it do assert_haml(<<-HAML.unindent) - h1 = {class: 'c1', id: ['id1', 'id3']} - h2 = {class: [{}, 'c2'], id: 'id2'} %span#main.content{h1, h2} hello HAML end end describe 'incompatibility' do it { assert_render(%Q|
    \n|, %q|%div{ class: nil }|) } it { assert_render(%Q|
    \n|, %q|%div{ class: false }|) } it { assert_render(%Q|
    \n|, %q|%div{ class: false }|) } it { assert_render(%Q|
    \n|, %q|%div{ class: val }|, locals: { val: false }) } it { assert_render(%Q|
    \n|, %q|%div{ hash }|, locals: { hash: { class: false } }) } end end describe 'data attributes' do it { assert_haml(%q|#foo.bar{ data: { disabled: val } }|, locals: { val: false }) } it { skip; assert_haml(%q|%div{:data => hash}|, locals: { hash: { :a => { :b => 'c' } }.tap { |h| h[:d] = h } }) } it { skip; assert_haml(%q|%div{ hash }|, locals: { hash: { data: { :a => { :b => 'c' } }.tap { |h| h[:d] = h } } }) } it { assert_haml(%q|%div{:data => {:foo_bar => 'blip', :baz => 'bang'}}|) } it { assert_haml(%q|%div{ data: { raw_src: 'foo' } }|) } it { assert_haml(%q|%a{ data: { value: [count: 1] } }|) } it { assert_haml(%q|%a{ 'data-disabled' => true }|) } it { assert_haml(%q|%a{ :'data-disabled' => true }|) } it { assert_haml(%q|%a{ data: { nil => 3 } }|) } it { assert_haml(%q|%a{ data: 3 }|) } it { assert_haml(%q|%a(data=3)|) } it { assert_haml(%q|%a{ 'data-bar' => 60 }|) } it { assert_haml(%q|%a{ data: { overlay_modal: 'foo' } }|) } it { assert_haml(%q|%a{ data: { overlay_modal: true } }|) } it { assert_haml(%q|%a{ data: { overlay_modal: false } }|) } it { assert_haml(%q|%a{ data: true }|) } it { assert_haml(%q|%a{ data: { nil => true } }|) } it { assert_haml(%q|%a{ data: { false => true } }|) } it { skip; assert_haml(%q|%a{ { data: { 'foo-bar' => 1 } }, data: { foo: { bar: 2 } } }|) } it { assert_haml(%q|%a{ { data: { foo: { bar: 2 } } }, data: { 'foo-bar' => 2 } }|) } it { assert_haml(%q|%a{ { data: { :'foo-bar' => 1 } }, data: { 'foo-bar' => 2 } }|) } it do assert_haml(<<-HAML.unindent) - old = { disabled: true, checked: false, href: false, 'hello-world' => '<>/' } - new = { disabled: false, checked: true, href: '<>/', hello: {}, 'hello_hoge' => true, foo: { 'bar&baz' => 'hoge' } } - hash = { data: { href: true, hash: true } } %a(data=new){ hash, data: old } HAML end it do assert_haml(<<-HAML.unindent) - h1 = { data: 'should be overwritten' } - h2 = { data: nil } %div{ h1, h2 } HAML end end describe 'boolean attributes' do it { assert_haml(%q|%input{ disabled: nil }|) } it { assert_haml(%q|%input{ disabled: false }|) } it { assert_haml(%q|%input{ disabled: true }|) } it { assert_haml(%q|%input{ disabled: 'false' }|) } it { assert_haml(%q|%input{ disabled: val = nil }|) } it { assert_haml(%q|%input{ disabled: val = false }|) } it { assert_haml(%q|%input{ disabled: val = true }|) } it { assert_haml(%q|%input{ disabled: val = 'false' }|) } it { assert_haml(%q|%input{ disabled: nil }(disabled=true)|) } it { assert_haml(%q|%input{ disabled: false }(disabled=true)|) } it { assert_haml(%q|%input{ disabled: true }(disabled=false)|) } it { assert_haml(%q|%a{ hash }|, locals: { hash: { disabled: false } }) } it { assert_haml(%q|%a{ hash }|, locals: { hash: { disabled: nil } }) } it { assert_haml(%q|input(disabled=true){ disabled: nil }|) } it { assert_haml(%q|input(disabled=true){ disabled: false }|) } it { assert_haml(%q|input(disabled=false){ disabled: true }|) } it { assert_haml(%q|%input(disabled=val){ disabled: false }|, locals: { val: true }) } it { assert_haml(%q|%input(disabled=val){ disabled: false }|, locals: { val: false }) } it { assert_haml(%q|%input(disabled=nil)|) } it { assert_haml(%q|%input(disabled=false)|) } it { assert_haml(%q|%input(disabled=true)|) } it { assert_haml(%q|%input(disabled='false')|) } it { assert_haml(%q|%input(disabled=val)|, locals: { val: 'false' }) } it { assert_haml(%q|%input(disabled='false'){ disabled: true }|) } it { assert_haml(%q|%input(disabled='false'){ disabled: false }|) } it { assert_haml(%q|%input(disabled='false'){ disabled: nil }|) } it { assert_haml(%q|%input(disabled=''){ disabled: nil }|) } it { assert_haml(%q|%input(checked=true)|) } it { assert_haml(%q|%input(checked=true)|, format: :xhtml) } it { assert_haml(%q|%input{ 'data-overlay_modal' => nil }|) } it { assert_haml(%q|%input{ 'data-overlay_modal' => false }|) } it { assert_haml(%q|%input{ 'data-overlay_modal' => true }|) } it { assert_haml(%q|%input{ 'data-overlay_modal' => 'false' }|) } it { assert_haml(%q|%input{ :'data-overlay_modal' => val = nil }|) } it { assert_haml(%q|%input{ :'data-overlay_modal' => val = false }|) } it { assert_haml(%q|%input{ :'data-overlay_modal' => val = true }|) } it { assert_haml(%q|%input{ :'data-overlay_modal' => val = 'false' }|) } it { assert_haml(%q|%a{ hash }|, locals: { hash: { 'data-overlay_modal' => false } }) } it { assert_haml(%q|%a{ hash }|, locals: { hash: { 'data-overlay_modal' => true } }) } it { assert_haml(%q|%a{ 'disabled' => 60 }|) } end describe 'common attributes' do describe 'compatibility' do it { assert_haml(%Q|%a{ href: '/search?foo=bar&hoge=' }|) } it { assert_haml(%Q|- h = {foo: 1, 'foo' => 2}\n%span{ h }|) } it { assert_haml(%q|%span(foo='new'){ foo: 'old' }|, locals: { new: 'new', old: 'old' }) } it { assert_haml(%q|%span(foo=new){ foo: 'old' }|, locals: { new: 'new', old: 'old' }) } it { assert_haml(%q|%span(foo=new){ foo: old }|, locals: { new: 'new', old: 'old' }) } it { assert_haml(%q|%span{ foo: 'old' }(foo='new')|, locals: { new: 'new', old: 'old' }) } it { assert_haml(%q|%span{ foo: 'old' }(foo=new)|, locals: { new: 'new', old: 'old' }) } it { assert_haml(%q|%span{ foo: old }(foo=new)|, locals: { new: 'new', old: 'old' }) } it do assert_haml(<<-HAML.unindent) - h1 = { foo: 1 } - h2 = { foo: 2 } %div{ h1, h2 } HAML end it do assert_haml(<<-'HAML'.unindent) - h = { "class\0with null" => 'is not class' } %div{ h } HAML end it { assert_haml(%q|%a{ 'href' => 60 }|) } end describe 'incompatibility' do it { assert_render(%Q|\n|, %q|%a{ href: "'\"" }|) } it { assert_render(%Q|\n|, %q|%input{ value: nil }|) } it { assert_render(%Q|\n|, %q|%input{ value: false }|) } it { assert_render(%Q|\n|, %q|%input{ value: val }|, locals: { val: false }) } it { assert_render(%Q|\n|, %q|%input{ hash }|, locals: { hash: { value: false } }) } it do assert_render(%Q|
    \n|, <<-HAML.unindent) - h1 = { foo: 'should be overwritten' } - h2 = { foo: nil } %div{ h1, h2 } HAML end end end describe 'object reference' do ::TestObject = Struct.new(:id) unless defined?(::TestObject) it { assert_render(%Q|\n|, %q|%a[foo]|, locals: { foo: TestObject.new(10) }) } it { assert_render(%Q|\n|, %q|%a[foo, nil]|, locals: { foo: TestObject.new(10) }) } it { assert_render(%Q|\n|, %q|%a[foo]|, locals: { foo: TestObject.new(nil) }) } it { assert_render(%Q|\n|, %q|%a[foo, 'pre']|, locals: { foo: TestObject.new(10) }) } it { assert_render(%Q|
    \n|, %q|.static#static[TestObject.new(10)]|) } it { assert_render(%Q|
    \n|, %q|.static#static[nil]|) } it do assert_render( %Q|\n|, %q|%a.static#static[foo, 'pre']{ id: dynamic, class: dynamic }|, locals: { foo: TestObject.new(10), dynamic: 'dynamic' }, ) end end describe 'engine options' do describe 'attr_quote' do it { assert_render(%Q|\n|, %q|%a{ href: '/' }|) } it { assert_render(%Q|\n|, %q|%a{ href: '/' }|, attr_quote: ?') } it { assert_render(%Q|\n|, %q|%a{ href: '/' }|, attr_quote: ?*) } it { assert_render(%Q|\n|, %q|%a{ id: '/' }|, attr_quote: ?") } it { assert_render(%Q|\n|, %q|%a{ id: val }|, attr_quote: ?", locals: { val: '/' }) } it { assert_render(%Q|\n|, %q|%a{ hash }|, attr_quote: ?", locals: { hash: { id: '/' } }) } it { assert_render(%Q|\n|, %q|%a{ class: '/' }|, attr_quote: ?") } it { assert_render(%Q|\n|, %q|%a{ class: val }|, attr_quote: ?", locals: { val: '/' }) } it { assert_render(%Q|\n|, %q|%a{ hash }|, attr_quote: ?", locals: { hash: { class: '/' } }) } it { assert_render(%Q|\n|, %q|%a{ data: '/' }|, attr_quote: ?") } it { assert_render(%Q|\n|, %q|%a{ data: val }|, attr_quote: ?", locals: { val: '/' }) } it { assert_render(%Q|\n|, %q|%a{ data: { url: '/' } }|, attr_quote: ?") } it { assert_render(%Q|\n|, %q|%a{ data: val }|, attr_quote: ?", locals: { val: { url: '/' } }) } it { assert_render(%Q|\n|, %q|%a{ hash }|, attr_quote: ?", locals: { hash: { data: { url: '/' } } }) } it { assert_render(%Q|\n|, %q|%a{ disabled: '/' }|, attr_quote: ?") } it { assert_render(%Q|\n|, %Q|%a{ disabled: val }|, attr_quote: ?", locals: { val: '/' }) } it { assert_render(%Q|\n|, %Q|%a{ hash }|, attr_quote: ?", locals: { hash: { disabled: '/' } }) } it { assert_render(%Q|\n|, %Q|%a{ hash }|, attr_quote: ?", format: :xhtml, locals: { hash: { disabled: true } }) } it { assert_render(%Q|\n|, %q|%a{ href: '/' }|, attr_quote: ?") } it { assert_render(%Q|\n|, %q|%a{ href: val }|, attr_quote: ?", locals: { val: '/' }) } it { assert_render(%Q|\n|, %q|%a{ hash }|, attr_quote: ?", locals: { hash: { href: '/' } }) } end describe 'escape_attrs' do it { assert_render(%Q|\n|, %q|%a{ id: '&<>"/' }|, escape_attrs: false) } it { assert_render(%Q|\n|, %Q|%a{ id: val }|, escape_attrs: false, locals: { val: '&<>"/' }) } it { assert_render(%Q|\n|, %Q|%a{ hash }|, escape_attrs: false, locals: { hash: { id: '&<>"/' } }) } it { assert_render(%Q|\n|, %q|%a{ id: '&<>"/' }|, escape_attrs: true) } it { assert_render(%Q|\n|, %Q|%a{ id: val }|, escape_attrs: true, locals: { val: '&<>"/' }) } it { assert_render(%Q|\n|, %Q|%a{ hash }|, escape_attrs: true, locals: { hash: { id: '&<>"/' } }) } it { assert_render(%Q|\n|, %q|%a{ class: '&<>"/' }|, escape_attrs: false) } it { assert_render(%Q|\n|, %Q|%a{ class: val }|, escape_attrs: false, locals: { val: '&<>"/' }) } it { assert_render(%Q|\n|, %Q|%a{ hash }|, escape_attrs: false, locals: { hash: { class: '&<>"/' } }) } it { assert_render(%Q|\n|, %q|%a{ class: '&<>"/' }|, escape_attrs: true) } it { assert_render(%Q|\n|, %Q|%a{ class: val }|, escape_attrs: true, locals: { val: '&<>"/' }) } it { assert_render(%Q|\n|, %Q|%a{ hash }|, escape_attrs: true, locals: { hash: { class: '&<>"/' } }) } it { assert_render(%Q|\n|, %q|%a{ data: '&<>"/' }|, escape_attrs: false) } it { assert_render(%Q|\n|, %Q|%a{ data: val }|, escape_attrs: false, locals: { val: '&<>"/' }) } it { assert_render(%Q|\n|, %Q|%a{ hash }|, escape_attrs: false, locals: { hash: { data: '&<>"/' } }) } it { assert_render(%Q|\n|, %q|%a{ data: '&<>"/' }|, escape_attrs: true) } it { assert_render(%Q|\n|, %Q|%a{ data: val }|, escape_attrs: true, locals: { val: '&<>"/' }) } it { assert_render(%Q|\n|, %Q|%a{ hash }|, escape_attrs: true, locals: { hash: { data: '&<>"/' } }) } it { assert_render(%Q|\n|, %q|%a{ disabled: '&<>"/' }|, escape_attrs: false) } it { assert_render(%Q|\n|, %Q|%a{ disabled: val }|, escape_attrs: false, locals: { val: '&<>"/' }) } it { assert_render(%Q|\n|, %Q|%a{ hash }|, escape_attrs: false, locals: { hash: { disabled: '&<>"/' } }) } it { assert_render(%Q|\n|, %q|%a{ disabled: '&<>"/' }|, escape_attrs: true) } it { assert_render(%Q|\n|, %Q|%a{ disabled: val }|, escape_attrs: true, locals: { val: '&<>"/' }) } it { assert_render(%Q|\n|, %Q|%a{ hash }|, escape_attrs: true, locals: { hash: { disabled: '&<>"/' } }) } it { assert_render(%Q|\n|, %q|%a{ href: '&<>"/' }|, escape_attrs: false) } it { assert_render(%Q|\n|, %Q|%a{ href: val }|, escape_attrs: false, locals: { val: '&<>"/' }) } it { assert_render(%Q|\n|, %Q|%a{ hash }|, escape_attrs: false, locals: { hash: { href: '&<>"/' } }) } it { assert_render(%Q|\n|, %q|%a{ href: '&<>"/' }|, escape_attrs: true) } it { assert_render(%Q|\n|, %Q|%a{ href: val }|, escape_attrs: true, locals: { val: '&<>"/' }) } it { assert_render(%Q|\n|, %Q|%a{ hash }|, escape_attrs: true, locals: { hash: { href: '&<>"/' } }) } end describe 'format' do it { assert_render(%Q|\n|, %q|%a{ disabled: true }|, format: :html) } it { assert_render(%Q|\n|, %q|%a{ disabled: val }|, format: :html, locals: { val: true }) } it { assert_render(%Q|\n|, %q|%a{ hash }|, format: :html, locals: { hash: { disabled: true } }) } it { assert_render(%Q|\n|, %q|%a{ disabled: true }|, format: :xhtml) } it { assert_render(%Q|\n|, %q|%a{ disabled: val }|, format: :xhtml, locals: { val: true }) } it { assert_render(%Q|\n|, %q|%a{ hash }|, format: :xhtml, locals: { hash: { disabled: true } }) } end end end hamlit-2.15.1/test/hamlit/engine/comment_test.rb000066400000000000000000000030061407657076200216230ustar00rootroot00000000000000describe Hamlit::Engine do include RenderHelper describe 'comment' do it 'renders html comment' do assert_render(%Q|\n|, '/ comments') end it 'strips html comment ignoring around spcaes' do assert_render(%Q|\n|, '/ comments ') end it 'accepts backslash-only line in a comment' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) HTML / \ HAML end it 'renders a deeply indented comment starting with backslash' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) HTML / \ a / a HAML end it 'ignores multiline comment' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) ok HTML -# if true - raise 'ng' = invalid script too deep indent ok HAML end it 'renders conditional comment' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) HTML /[[if IE]] %span hello world HAML end it 'renders conditional comment' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) HTML /[if lt IE 9] hello HAML end end end hamlit-2.15.1/test/hamlit/engine/doctype_test.rb000066400000000000000000000006701407657076200216340ustar00rootroot00000000000000describe Hamlit::Engine do include RenderHelper describe 'doctype' do it 'renders html5 doctype' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML !!! HAML end it 'renders xml doctype' do assert_render(<<-HTML.unindent, <<-HAML.unindent, format: :xhtml) HTML !!! XML HAML end end end hamlit-2.15.1/test/hamlit/engine/indent_test.rb000066400000000000000000000013601407657076200214430ustar00rootroot00000000000000describe Hamlit::Engine do include RenderHelper describe 'tab indent' do it 'accepts tab indentation' do assert_render(<<-HTML.unindent, <<-HAML.unindent)

    HTML %p \t%a HAML end it 'accepts N-space indentation' do assert_render(<<-HTML.unindent, <<-HAML.unindent)

    foo

    HTML %p %span foo HAML end it 'accepts N-tab indentation' do assert_render(<<-HTML.unindent, <<-HAML.unindent)

    foo

    HTML %p \t%span \t\tfoo HAML end end end hamlit-2.15.1/test/hamlit/engine/multiline_test.rb000066400000000000000000000014371407657076200221710ustar00rootroot00000000000000describe Hamlit::Engine do include RenderHelper describe 'multiline' do it 'joins multi-lines ending with pipe' do assert_render(<<-HTML.unindent, <<-HAML.unindent) a b HTML a | b | HAML end it 'renders multi lines' do assert_render(<<-HTML.unindent, <<-HAML.unindent) abc 'd' HTML = 'a' + | 'b' + | 'c' | 'd' HAML end it 'accepts invalid indent' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    12
    3
    HTML %span %div = '1' + | '2' | %div 3 HAML end end end hamlit-2.15.1/test/hamlit/engine/new_attribute_test.rb000066400000000000000000000052371407657076200230450ustar00rootroot00000000000000describe Hamlit::Engine do include RenderHelper describe 'new attributes' do it 'renders attributes' do assert_render(<<-HTML.unindent, <<-HAML.unindent)

    bar

    HTML %p(class='foo') bar HAML end it 'renders multiple attributes' do assert_render(<<-HTML.unindent, <<-HAML.unindent)

    bar

    HTML %p(a=1 b=2) bar HAML end it 'renders hyphenated attributes properly' do assert_render(<<-HTML.unindent, <<-HAML.unindent)

    bar

    HTML %p(data-foo='bar') bar HAML end it 'renders multiply hyphenated attributes properly' do assert_render(<<-HTML.unindent, <<-HAML.unindent)

    bar

    HTML %p(data-x-foo='bar') bar HAML end describe 'html escape' do it 'escapes attribute values on static attributes' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) HTML %a(title="'") %a(title = "'\"") %a(href='/search?foo=bar&hoge=') HAML end it 'escapes attribute values on dynamic attributes' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) HTML - title = "'\"" - href = '/search?foo=bar&hoge=' %a(title=title) %a(href=href) HAML end end describe 'element class with attribute class' do it 'does not generate double classes' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    HTML .item(class='first') HAML end it 'does not generate double classes for a variable' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    HTML - val = 'val' .element(class=val) HAML end end describe 'element id with attribute id' do it 'concatenates ids with underscore' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    HTML #item(id='first') HAML end it 'concatenates ids with underscore for a variable' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    HTML - val = 'first' #item(id=val) HAML end end end end hamlit-2.15.1/test/hamlit/engine/old_attribute_test.rb000066400000000000000000000326011407657076200230250ustar00rootroot00000000000000require_relative '../../test_helper' describe Hamlit::Engine do include RenderHelper describe 'old attributes' do it 'renders attributes' do assert_render(<<-HTML.unindent, <<-HAML.unindent) bar HTML %span{class: 'foo'} bar HAML end it 'renders attributes' do assert_render(<<-HTML.unindent, <<-HAML.unindent) bar HTML %span{ data: 2 } bar HAML end it 'renders attributes' do assert_render(<<-HTML.unindent, <<-HAML.unindent) bar HTML %span{ :class => 'foo' } bar HAML end it 'renders attributes' do assert_render(<<-HTML.unindent, <<-HAML.unindent) bar HTML %span{ :class => 'foo', id: 'bar' } bar HAML end it 'renders attributes' do assert_render(<<-HTML.unindent, <<-HAML.unindent) bar HTML %span{ :'data-disabled' => true } bar HAML end it 'accepts method call including comma' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) HTML %body{ class: "#{"ab".gsub(/a/, 'b')}", data: { confirm: 'really?', disabled: true }, id: 'c'.gsub(/c/, 'a') } HAML end it 'accepts tag content' do assert_render(<<-HTML.unindent, <<-HAML.unindent) bar HTML %span{ class: 'foo' } bar HAML end it 'renders multi-byte chars as static attribute value' do assert_render(<<-HTML.unindent, <<-HAML.unindent) こんにちは HTML %img{ alt: 'こんにちは' } HAML end it 'sorts static attributes by name' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML %span{ :foo => "bar", :hoge => "piyo"} %span{ :hoge => "piyo", :foo => "bar"} HAML end describe 'runtime attributes' do it 'renders runtime hash attribute' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML - hash = { foo: 'bar' } %span{ hash } HAML end it 'renders multiples hashes' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML - h1 = { a: 'b' } - h2 = { c: 'd' } - h3 = { e: 'f' } %span{ h1, h2, h3 } HAML end it 'renders multiples hashes and literal hash' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML - h1 = { a: 'b' } - h2 = { c: 'd' } - h3 = { e: 'f' } %span{ h1, h2, h3, g: 'h', i: 'j' } HAML end it 'does not crash when nil is given' do if /java/ === RUBY_PLATFORM skip 'maybe due to Ripper of JRuby' end if RUBY_ENGINE == 'truffleruby' skip 'truffleruby raises NoMethodError' end assert_raises ArgumentError do render_hamlit("%div{ nil }") end end end describe 'joinable attributes' do it 'joins class with a space' do assert_render(<<-HTML.unindent, <<-HAML.unindent)

    HTML - val = ['a', 'b', 'c'] %p{ class: val } %p{ class: %w[a b c] } %p{ class: ['a', 'b', 'c'] } HAML end it 'joins attribute class and element class' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    HTML .foo{ class: ['bar'] } .foo{ class: ['bar', 'foo'] } .foo{ class: ['bar', nil] } .foo{ class: ['bar', 'baz'] } HAML end it 'joins id with an underscore' do assert_render(<<-HTML.unindent, <<-HAML.unindent)

    HTML - val = ['a', 'b', 'c'] %p{ id: val } %p{ id: %w[a b c] } %p{ id: ['a', 'b', 'c'] } HAML end it 'does not join others' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML %a{ data: { value: [count: 1] } } HAML end end describe 'deletable attributes' do it 'deletes attributes whose value is nil or false' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML - hash = { checked: false } %input{ hash } %input{ checked: false } %input{ checked: nil } - checked = nil %input{ checked: checked } - checked = false %input{ checked: checked } HAML end it 'deletes some limited attributes with dynamic value' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    HTML - val = false #foo.bar{ autofocus: val } #foo.bar{ checked: val } #foo.bar{ data: { disabled: val } } #foo.bar{ disabled: val } #foo.bar{ formnovalidate: val } #foo.bar{ multiple: val } #foo.bar{ readonly: val } #foo.bar{ required: val } HAML end it 'does not delete non-boolean attributes, for optimization' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML %a{ href: false } - val = false %a{ href: val } - hash = { href: false } %a{ hash } %a{ disabled: false } - val = false %a{ disabled: val } - hash = { disabled: false } %a{ hash } %a{ href: nil } - val = nil %a{ href: val } - hash = { href: nil } %a{ hash } %a{ disabled: nil } - val = nil %a{ disabled: val } - hash = { disabled: nil } %a{ hash } HAML end end describe 'html escape' do it 'escapes attribute values on static attributes' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) HTML %a{title: "'"} %a{title: "'\""} %a{href: '/search?foo=bar&hoge='} HAML end it 'escapes attribute values on dynamic attributes' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) HTML - title = "'\"" - href = '/search?foo=bar&hoge=' %a{title: title} %a{href: href} HAML end it 'escapes attribute values on hash attributes' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) HTML - title = { title: "'\"" } - href = { href: '/search?foo=bar&hoge=' } %a{ title } %a{ href } HAML end end describe 'nested data attributes' do it 'renders data attribute by hash' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML - hash = { bar: 'baz' } %span.foo{ data: hash } HAML end it 'renders true attributes' do assert_render(<<-HTML.unindent, <<-HAML.unindent) bar HTML %span{ data: { disabled: true } } bar HAML end it 'renders nested hash whose value is variable' do assert_render(<<-HTML.unindent, <<-HAML.unindent) bar HTML - hash = { disabled: true } %span{ data: hash } bar HAML end it 'changes an underscore in a nested key to a hyphen' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    HTML %div{ data: { raw_src: 'foo' } } HAML end it 'changes an underscore in a nested dynamic attribute' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    HTML - hash = { raw_src: 'foo' } %div{ data: hash } HAML end end describe 'nested aria attributes' do it 'renders aria attribute by hash' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML - hash = { bar: 'baz' } %span.foo{ aria: hash } HAML end it 'renders true attributes' do assert_render(<<-HTML.unindent, <<-HAML.unindent) bar HTML %span{ aria: { disabled: true } } bar HAML end it 'renders nested hash whose value is variable' do assert_render(<<-HTML.unindent, <<-HAML.unindent) bar HTML - hash = { disabled: true } %span{ aria: hash } bar HAML end it 'changes an underscore in a nested key to a hyphen' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    HTML %div{ aria: { raw_src: 'foo' } } HAML end it 'changes an underscore in a nested dynamic attribute' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    HTML - hash = { raw_src: 'foo' } %div{ aria: hash } HAML end end if RUBY_ENGINE != 'truffleruby' # aria attribute is not working in truffleruby describe 'element class with attribute class' do it 'does not generate double classes' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    HTML .item{ class: 'first' } HAML end it 'does not generate double classes for a variable' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    HTML - val = 'val' .element{ class: val } HAML end it 'does not generate double classes for hash attributes' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    HTML - hash = { class: 'val' } .element{ hash } HAML end end describe 'element id with attribute id' do it 'does not generate double ids' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    HTML #item{ id: 'first' } HAML end it 'does not generate double ids for a variable' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    HTML - val = 'first' #item{ id: val } HAML end it 'does not generate double ids for hash attributes' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    HTML - hash = { id: 'first' } #item{ hash } HAML end it 'does not generate double ids and classes for hash attributes' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    HTML - hash = { id: 'first', class: 'foo' } #item.bar{ hash } HAML end end if RUBY_VERSION >= "2.2.0" describe 'Ruby 2.2 syntax' do it 'renders static attributes' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML %meta{ content: 'IE=edge', 'http-equiv': 'X-UA-Compatible' } HAML end it 'renders dynamic attributes' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML - hash = { content: 'IE=edge' } %meta{ hash, 'http-equiv': 'X-UA-Compatible' } HAML end end end end end hamlit-2.15.1/test/hamlit/engine/script_test.rb000066400000000000000000000060501407657076200214670ustar00rootroot00000000000000describe Hamlit::Engine do include RenderHelper describe 'script' do it 'renders one-line script' do assert_render(<<-HTML.unindent, <<-HAML.unindent) 3 12 HTML = 1 + 2 %span= 3 * 4 HAML end it 'renders dynamic interpolated string' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) hello nya world HTML - nya = 'nya' = "hello #{nya} world" HAML end it 'renders array with escape_html: false' do assert_render(<<-HTML.unindent, <<-HAML.unindent, escape_html: false) ["<", ">"] HTML = ['<', '>'] HAML end it 'renders one-line script with comment' do assert_render(<<-HTML.unindent, <<-HAML.unindent) ## ["#", "#"] HTML = # comment_only = '#' + "#" # = 3 # = ['#', "#"] # comment HAML end it 'renders multi-lines script' do assert_render(<<-HTML.unindent, <<-HAML.unindent) 3 4 / 2 -1 HTML %span = 1 + 2 4 / 2 %a= 3 - 4 HAML end it 'renders block script' do assert_render(<<-HTML.unindent, <<-HAML.unindent) 0 1 2 34 HTML = 3.times do |i| = i 4 HAML end it 'renders tag internal block script' do assert_render(<<-HTML.unindent, <<-HAML.unindent) 0 1 HTML %span = 1.times do |i| = i HAML end it 'renders block and a variable with spaces' do assert_render(<<-HTML.unindent, <<-HAML.unindent) 0 HTML - 1.times do | i | = i HAML end it 'accepts a continuing script' do assert_render(<<-HTML.unindent, <<-HAML.unindent) 3 HTML - obj = Object.new; def obj.foo(a, b); a + b; end = obj.foo(1, 2) HAML end it 'renders !=' do assert_render(<<-HTML.unindent.strip, <<-HAML.unindent, escape_html: false) <"&> <"&> HTML != '<"&>' != '<"&>'.tap do |str| -# no operation HAML end it 'renders &=' do assert_render(<<-HTML.unindent.strip, <<-HAML.unindent, escape_html: false) <"&> <"&> HTML &= '<"&>' &= '<"&>'.tap do |str| -# no operation HAML end it 'regards ~ operator as =' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) <code>hello world</code> HTML ~ "hello\nworld" HAML end it 'renders comment-only nested script' do assert_render('1', <<-HAML.unindent) = 1.times do # comment - # comment only HAML end it 'renders inline script with comment' do assert_render(%Q|3\n|, %q|%span= 1 + 2 # comments|) end end end hamlit-2.15.1/test/hamlit/engine/silent_script_test.rb000066400000000000000000000100651407657076200230460ustar00rootroot00000000000000describe Hamlit::Engine do include RenderHelper describe 'silent script' do it 'renders nothing' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML - _ = nil - _ = 3 - _ = 'foo' HAML end it 'renders silent script' do assert_render(<<-HTML.unindent, <<-HAML.unindent) 5 HTML - foo = 3 - bar = 2 = foo + bar HAML end it 'renders nested block' do assert_render(<<-HTML.unindent, <<-HAML.unindent) 0 1 2 3 4 HTML - 2.times do |i| = i 2 - 3.upto(4).each do |i| = i HAML end it 'renders if' do assert_render(<<-HTML.unindent, <<-HAML.unindent) ok HTML - if true ok HAML end it 'renders if-else' do assert_render(<<-HTML.unindent, <<-HAML.unindent) ok ok HTML - if true ok - else ng - if false ng - else ok HAML end it 'renders nested if-else' do assert_render(<<-HTML.unindent, <<-HAML.unindent) ok HTML %span - if false ng - else ok HAML end it 'renders empty elsif statement' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML %span - if false - elsif false HAML end it 'renders empty else statement' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML %span - if false ng - else HAML end it 'renders empty when statement' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML %span - case - when false HAML end it 'accept if inside if-else' do assert_render(<<-HTML.unindent, <<-HAML.unindent) ok HTML - if false - if true ng - else ok HAML end it 'renders if-elsif' do assert_render(<<-HTML.unindent, <<-HAML.unindent) ok ok HTML - if false - elsif true ok - if false - elsif false - else ok HAML end it 'renders case-when' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) ok HTML - case 'foo' - when /\Ao/ ng - when /\Af/ ok - else ng HAML end it 'renders case-when with multiple candidates' do assert_render(<<-HTML.unindent, <<-HAML.unindent) ok HTML - case 'a' - when 'a', 'b' ok HAML end it 'renders begin-rescue' do assert_render(<<-HTML.unindent, <<-HAML.unindent) hello world HTML - begin - raise 'error' - rescue hello - ensure world HAML end it 'renders rescue with error' do assert_render(<<-HTML.unindent, <<-HAML.unindent) hello HTML - begin - raise 'error' - rescue RuntimeError => _e hello HAML end it 'joins a next line if a current line ends with ","' do assert_render(<<-HTML.unindent, "- foo = [', \n ']\n= foo") [", "] HTML end it 'accepts illegal indent in continuing code' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    3
    HTML %span %div - obj = Object.new; def obj.foo(a, b); a + b; end - num = obj.foo(1, 2) = num HAML end it 'renders comment-only nested silent script' do assert_render('', <<-HAML.unindent) - if true - # comment only HAML end end end hamlit-2.15.1/test/hamlit/engine/tag_test.rb000066400000000000000000000075761407657076200207540ustar00rootroot00000000000000describe Hamlit::Engine do include RenderHelper describe 'tag' do it 'renders one-line tag' do assert_render(<<-HTML.unindent, <<-HAML.unindent) hello HTML %span hello HAML end it 'accepts multi-line =' do assert_render(<<-HTML.unindent, <<-HAML.unindent) o HTML %span= 'hello'.gsub('hell', '') HAML end it 'renders multi-line tag' do assert_render(<<-HTML.unindent, <<-HAML.unindent) hello HTML %span hello HAML end it 'renders a nested tag' do assert_render(<<-HTML.unindent, <<-HAML.unindent) hello world HTML %span %b hello %i %small world HAML end it 'renders multi-line texts' do assert_render(<<-HTML.unindent, <<-HAML.unindent) hello world HTML %span %b hello world HAML end it 'ignores empty lines' do assert_render(<<-HTML.unindent, <<-HAML.unindent) hello HTML %span %b hello HAML end it 'renders classes' do assert_render(<<-HTML.unindent, <<-HAML.unindent) hello HTML %span.foo-1.bar_A hello HAML end it 'renders ids only last one' do assert_render(<<-HTML.unindent, <<-HAML.unindent) hello HTML %span#Bar_0#bar- hello HAML end it 'renders ids and classes' do assert_render(<<-HTML.unindent, <<-HAML.unindent) hello HTML %span#a.b#c.d hello HAML end it 'renders implicit div tag starting with id' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    HTML #hello.world HAML end it 'renders implicit div tag starting with class' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    foo
    HTML .world#hello foo HAML end it 'renders large-case tag' do assert_render(<<-HTML.unindent, <<-HAML.unindent) foo HTML %SPAN foo HAML end it 'renders h1 tag' do assert_render(<<-HTML.unindent, <<-HAML.unindent)

    foo

    HTML %h1 foo HAML end it 'renders tag including hyphen or underscore' do assert_render(<<-HTML.unindent, <<-HAML.unindent) <-_>foo HTML %-_ foo HAML end it 'does not render silent script just after a tag' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) raise 'a' HTML %span- raise 'a' HAML end it 'renders a text just after attributes' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) a HTML %span{a: 2}a HAML end it 'strips a text' do assert_render(<<-HTML.unindent, <<-HAML.unindent) foo HTML %span foo HAML end it 'ignores spaces after tag' do assert_render(<<-HTML.unindent, "%span \n a") a HTML end it 'parses self-closing tag' do assert_render(<<-HTML.unindent, <<-HAML.unindent, format: :xhtml)
    HTML %div/ %div HAML end end end hamlit-2.15.1/test/hamlit/engine/text_test.rb000066400000000000000000000123601407657076200211500ustar00rootroot00000000000000describe Hamlit::Engine do include RenderHelper describe 'text' do it 'renders string interpolation' do skip 'escape is not working well in truffleruby' if RUBY_ENGINE == 'truffleruby' assert_render(<<-HTML.unindent, <<-'HAML'.unindent) a3aa" ["1", 2] b " ! a{:a=>3} HTML #{ "a#{3}a" }a" #{["1", 2]} b " ! a#{{ a: 3 }} HAML end it 'escapes all operators by backslash' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) a = 'a' - HTML = 'a' - \= 'a' \- HAML end it 'renders == operator' do skip 'escape is not working well in truffleruby' if RUBY_ENGINE == 'truffleruby' assert_render(<<-HTML.unindent, <<-'HAML'.unindent) = = <a> HTML === == = == == #{''} HAML end it 'renders !== operator' do skip 'escape is not working well in truffleruby' if RUBY_ENGINE == 'truffleruby' assert_render(<<-HTML.unindent, <<-'HAML'.unindent) <a> = = HTML == #{''} !== #{''} !=== !== = HAML end it 'leaves empty spaces after backslash' do assert_render(" a\n", '\ a') end it 'renders spaced - properly' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent)
    foo
    - bar
    - baz
    HTML %div foo .test - bar .test - baz HAML end describe 'inline operator' do it 'renders ! operator' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) HTML %span!#{''} %span! #{''} ! #{''} HAML end it 'renders & operator' do skip 'escape is not working well in truffleruby' if RUBY_ENGINE == 'truffleruby' assert_render(<<-HTML.unindent, <<-'HAML'.unindent) <nyaa> <nyaa> <nyaa> HTML %span& #{''} %span&#{''} & #{''} HAML end it 'renders !, & operator right before a non-space character' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent)     !hello !hello HTML   \  !hello \!hello HAML end it 'renders &, ! operator inside a tag' do assert_render(<<-HTML.unindent, <<-HAML.unindent)   nbsp; nbsp; !hello hello hello HTML %span   %span  %span& nbsp; %span !hello %span!hello %span! hello HAML end it 'does not accept backslash operator' do assert_render(<<-'HTML'.unindent, <<-'HAML'.unindent) \ foo HTML %span\ foo HAML end it 'renders != operator' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML %span!= '' HAML end it 'renders !== operator' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) HTML %span!==#{''} %span!== #{''} !==#{''} !== #{''} HAML end it 'renders &= operator' do assert_render(<<-HTML.unindent, <<-HAML.unindent) <nyaa> HTML %span&= '' HAML end it 'renders &== operator' do skip 'escape is not working well in truffleruby' if RUBY_ENGINE == 'truffleruby' assert_render(<<-HTML.unindent, <<-'HAML'.unindent) = = <p> HTML &=== &== = &== #{'

    '} HAML end it 'renders ~ operator' do assert_render(<<-HTML.unindent, <<-HAML.unindent, escape_html: false) 1 HTML %span~ 1 HAML end end describe 'string interpolation' do it { assert_render("\n", '#{}') } it { assert_render("1\n", '1#{}') } it { assert_render("12\n", '1#{2}') } it { assert_render("}1\n", '}#{1}') } it { assert_render("12\n", '#{1}2') } it { assert_render("12345\n", '1#{ "2#{3}4" }5') } it { assert_render("123456789\n", '#{1}2#{3}4#{5}6#{7}8#{9}') } it { assert_render(%Q{'"!@$%^&*|=1112\n}, %q{'"!@$%^&*|=#{1}1#{1}2}) } it { assert_render("あ1\n", 'あ#{1}') } it { assert_render("あいう\n", 'あ#{"い"}う') } it { assert_render("a<b>c\n", 'a#{""}c') } if RUBY_ENGINE != 'truffleruby' # escape is not working in truffleruby end end end hamlit-2.15.1/test/hamlit/engine/whitespace_test.rb000066400000000000000000000050151407657076200223170ustar00rootroot00000000000000describe Hamlit::Engine do include RenderHelper describe 'whitespace removal' do it 'removes outer whitespace by >' do assert_render(<<-HTML.unindent, <<-HAML.unindent) ab c d e f HTML %span> a %span b %span c %span> d %span e %span f HAML end it 'removes outer whitespace by > from inside of block' do assert_render(<<-HTML.unindent, <<-HAML.unindent) a b c HTML %span a - if true %span> b %span c HAML end it 'removes whitespaces inside block script' do assert_render(<<-HTML.unindent, <<-HAML.unindent) foofoo2bar HTML %span< = 2.times do = 'foo' %span> bar HAML end it 'removes whitespace inside script inside silent script' do assert_render(<<-HTML.unindent, <<-HAML.unindent)

    foofoofoo
    HTML .bar< - 3.times do = 'foo' HAML end it 'removes whitespace inside script recursively' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    bar1bar1bar1bar12
    HTML .foo< - 1.times do = 2.times do - 2.times do = 1.times do = 'bar' HAML end it 'does not remove whitespace after string interpolation' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent)
    helloworld
    HTML %div< #{'hello'} world HAML end it 'removes whitespace inside script inside silent script' do assert_render(<<-HTML.unindent, <<-HAML.unindent)
    12
    HTML .bar< - 1.times do = '1' = '2' HAML end it 'does not nuke internal recursively' do assert_render(%Q|
    \nhello\n
    |, <<-HAML.unindent) %div>< %span> hello HAML end it 'does not nuke inside script' do assert_render(%Q|
    \nhello\n1
    |, <<-HAML.unindent) %div>< = 1.times do %span> hello HAML end end end hamlit-2.15.1/test/hamlit/error_test.rb000066400000000000000000000024061407657076200200500ustar00rootroot00000000000000describe Hamlit::Engine do describe 'HamlSyntaxError' do it 'raises on runtime' do code = Hamlit::Engine.new.call(" %a") assert_raises(Hamlit::HamlSyntaxError) do eval code end end it 'returns error with lines before error' do code = Hamlit::Engine.new.call("\n\n %a") begin eval code rescue Hamlit::HamlSyntaxError => e assert_equal(2, e.line) end end describe 'Hamlit v1 syntax' do it 'returns an error with proper line number' do code = Hamlit::Engine.new.call(<<-HAML.unindent) %span - if true %div{ data: { hello: 'world', } } HAML begin eval code rescue Hamlit::HamlSyntaxError => e assert_equal(3, e.line) end end end end describe 'FilterNotFound' do it 'raises on runtime' do code = Hamlit::Engine.new.call(":k0kubun") assert_raises(Hamlit::FilterNotFound) do eval code end end it 'returns error with lines before error' do code = Hamlit::Engine.new.call("\n\n:k0kubun") begin eval code rescue Hamlit::FilterNotFound => e assert_equal(2, e.line) end end end end hamlit-2.15.1/test/hamlit/filters/000077500000000000000000000000001407657076200170015ustar00rootroot00000000000000hamlit-2.15.1/test/hamlit/filters/cdata_test.rb000066400000000000000000000007711407657076200214460ustar00rootroot00000000000000describe Hamlit::Filters do include RenderHelper describe '#compile' do it 'renders cdata' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML :cdata foo bar HAML end it 'parses string interpolation' do assert_render(<<-HTML.unindent, <<-HAML.unindent) bar ]]> HTML :cdata foo #{'<&>'} bar HAML end end end hamlit-2.15.1/test/hamlit/filters/coffee_test.rb000066400000000000000000000025341407657076200216200ustar00rootroot00000000000000describe Hamlit::Filters do include RenderHelper describe '#compile' do it 'renders coffee filter' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML :coffee foo = -> alert('hello') HAML end it 'renders coffeescript filter' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML :coffeescript foo = -> alert('hello') HAML end it 'renders coffeescript filter' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) HTML :coffee foo = -> alert("#{'<&>'}") HAML end end unless /java/ === RUBY_PLATFORM # execjs is not working with Travis JRuby environment end hamlit-2.15.1/test/hamlit/filters/css_test.rb000066400000000000000000000012051407657076200211530ustar00rootroot00000000000000describe Hamlit::Filters do include RenderHelper describe '#compile' do it 'renders css' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML :css .foo { width: 100px; } HAML end it 'parses string interpolation' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML :css .foo { content: "#{'<&>'}"; } HAML end end end hamlit-2.15.1/test/hamlit/filters/erb_test.rb000066400000000000000000000005001407657076200211300ustar00rootroot00000000000000describe Hamlit::Filters do include RenderHelper describe '#compile' do it 'renders erb filter' do assert_render(<<-HTML.unindent, <<-HAML.unindent) ok HTML :erb <% if true %> ok <% else %> ng <% end %> HAML end end end hamlit-2.15.1/test/hamlit/filters/javascript_test.rb000066400000000000000000000031361407657076200225360ustar00rootroot00000000000000describe Hamlit::Filters do include RenderHelper describe '#compile' do it 'just renders script tag for empty filter' do assert_render(<<-HTML.unindent, <<-HAML.unindent) before after HTML before :javascript after HAML end it 'compiles javascript filter' do assert_render(<<-HTML.unindent, <<-HAML.unindent) before after HTML before :javascript alert('hello'); after HAML end it 'accepts illegal indentation' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML :javascript if { alert('hello'); } :javascript if { alert('hello'); } HAML end it 'accepts illegal indentation' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML :javascript if { alert('a'); } HAML end it 'parses string interpolation' do assert_render(<<-HTML.unindent, <<-HAML.unindent) HTML :javascript var a = "#{'<&>'}"; HAML end end end hamlit-2.15.1/test/hamlit/filters/markdown_test.rb000066400000000000000000000020041407657076200222030ustar00rootroot00000000000000describe Hamlit::Filters do include RenderHelper describe '#compile' do it 'renders markdown filter' do if /java/ === RUBY_PLATFORM && !system('which pandoc > /dev/null') skip 'pandoc is required to test :markdown filter' end assert_render(<<-HTML.unindent, <<-HAML.unindent)

    Hamlit

    Yet another haml implementation

    HTML :markdown # Hamlit Yet another haml implementation HAML end it 'renders markdown filter with string interpolation' do if /java/ === RUBY_PLATFORM && !system('which pandoc > /dev/null') skip 'pandoc is required to test :markdown filter' end assert_render(<<-HTML.unindent, <<-'HAML'.unindent)

    <&> Yet another haml implementation

    HTML - project = '' :markdown # #{project} #{'<&>'} Yet another haml implementation HAML end end end hamlit-2.15.1/test/hamlit/filters/plain_test.rb000066400000000000000000000010031407657076200214620ustar00rootroot00000000000000describe Hamlit::Filters do include RenderHelper describe '#compile' do it 'does not escape content without interpolation' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) 5 HTML :coffee jQuery ($) -> console.log('#{__LINE__}') console.log('#{__LINE__}') = __LINE__ HAML end it 'renders dynamic filter' do assert_render(<<-HTML.unindent, <<-HAML.unindent) 5 HTML :coffee jQuery ($) -> console.log('3') console.log('4') = __LINE__ HAML end end unless /java/ === RUBY_PLATFORM # execjs is not working with Travis JRuby environment describe 'css filter' do it 'renders static filter' do assert_render(<<-HTML.unindent, <<-HAML.unindent) 6 HTML :css body { width: 3px; height: 4px; } = __LINE__ HAML end it 'renders dynamic filter' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) 6 HTML :css body { width: #{__LINE__}px; height: #{__LINE__}px; } = __LINE__ HAML end it 'renders dynamic filter with trailing newlines' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) 8 HTML :css body { width: #{__LINE__}px; height: #{__LINE__}px; } = __LINE__ HAML end end describe 'javascript filter' do it 'renders static filter' do assert_render(<<-HTML.unindent, <<-HAML.unindent) 5 HTML :javascript console.log("2"); console.log("3"); = __LINE__ HAML end it 'renders dynamic filter' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) 5 HTML :javascript console.log("#{__LINE__}"); console.log("#{__LINE__}"); = __LINE__ HAML end end unless /java/ === RUBY_PLATFORM # execjs is not working with Travis JRuby environment describe 'plain filter' do it 'renders line numbers with an empty line correctly' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) hello 4 HTML :plain hello = __LINE__ HAML end it 'renders line numbers with a script line correctly' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) hello 3 4 HTML :plain hello = 3 = __LINE__ HAML end it 'renders line numbers with interpolation' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) hello 3 4 HTML :plain hello#{} = 3 = __LINE__ HAML end end describe 'preserve filter' do it 'renders line numbers correctly' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) hello 4 HTML :preserve hello = __LINE__ HAML end end describe 'ruby filter' do it 'renders line numbers correctly' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) 4 HTML :ruby _ = 1 = __LINE__ HAML end end end describe 'dynamic merger' do it 'renders optimized string' do assert_render(<<-HTML.unindent, <<-'HAML'.unindent) foo1 2 3bar 5baz HTML foo#{__LINE__} #{__LINE__} #{__LINE__}bar - 1.to_s #{__LINE__}baz HAML end end end if RUBY_ENGINE != 'truffleruby' # negetive line numbers are broken in truffleruby hamlit-2.15.1/test/hamlit/optimization_test.rb000066400000000000000000000027211407657076200214450ustar00rootroot00000000000000require_relative '../test_helper' describe 'optimization' do def compiled_code(haml) Hamlit::Engine.new.call(haml) end describe 'static analysis' do it 'renders static value for href statically' do haml = %|%a{ href: 1 }| assert_equal true, compiled_code(haml).include?(%|href='1'|) end it 'renders static script statically' do haml = <<-HAML.unindent %span 1 HAML assert_equal true, compiled_code(haml).include?(%q|\n1\n|) end it 'renders inline static script statically' do haml = %|%span= 1| assert_equal true, compiled_code(haml).include?(%|1|) end end describe 'string interpolation' do it 'renders a static part of string literal statically' do haml = %q|%input{ value: "jruby#{9000}#{dynamic}" }| assert_equal true, compiled_code(haml).include?(%|value='jruby9000|) haml = %q|%span= "jruby#{9000}#{dynamic}"| assert_equal true, compiled_code(haml).include?(%|jruby9000|) end it 'optimizes script' do haml = %q|= "jruby#{ "#{9000}" }#{dynamic}"| assert_equal true, compiled_code(haml).include?(%|jruby9000|) end it 'detects a static part recursively' do haml = %q|%input{ value: "#{ "hello#{ hello }" }" }| assert_equal true, compiled_code(haml).include?(%|value='hello|) end end end if RUBY_ENGINE != 'truffleruby' # truffleruby does not implement major Ripper features hamlit-2.15.1/test/hamlit/rails_template_test.rb000066400000000000000000000112721407657076200217250ustar00rootroot00000000000000# Explicitly requiring rails_template because rails initializers is not executed here. require 'hamlit/rails_template' describe Hamlit::RailsTemplate do def render(haml) ActionView::Template.register_template_handler(:haml, Hamlit::RailsTemplate.new) base = Class.new(ActionView::Base) do def compiled_method_container self.class end end.new(ActionView::LookupContext.new(''), {}, ActionController::Base.new) base.render(inline: haml, type: :haml) end specify 'html escape' do assert_equal %Q|<script>alert("a");</script>\n|, render(<<-HAML.unindent) = '' HAML assert_equal %Q|\n|, render(<<-HAML.unindent) = ''.html_safe HAML skip 'escape is not working well in truffleruby' if RUBY_ENGINE == 'truffleruby' assert_equal %Q|<script>alert("a");</script>\n|, render(<<-'HAML'.unindent) #{''} HAML assert_equal %Q|\n|, render(<<-'HAML'.unindent) #{''.html_safe} HAML end specify 'attribute escape' do assert_equal %Q|
    \n|, render(<<-HAML.unindent) %a{ href: '' } HAML assert_equal %Q|\n|, render(<<-HAML.unindent) %a{ href: '