pax_global_header00006660000000000000000000000064140212617030014506gustar00rootroot0000000000000052 comment=d1b6679ca290dd7f3505dd254bc28ff7bbd2465c ruby-prawn-svg-0.32.0/000077500000000000000000000000001402126170300144735ustar00rootroot00000000000000ruby-prawn-svg-0.32.0/.github/000077500000000000000000000000001402126170300160335ustar00rootroot00000000000000ruby-prawn-svg-0.32.0/.github/workflows/000077500000000000000000000000001402126170300200705ustar00rootroot00000000000000ruby-prawn-svg-0.32.0/.github/workflows/test.yml000066400000000000000000000006251402126170300215750ustar00rootroot00000000000000name: test on: [push, pull_request] jobs: rake: runs-on: ubuntu-latest strategy: fail-fast: false matrix: ruby: [2.3, 2.4, 2.5, 2.6, 2.7, '3.0'] steps: - uses: actions/checkout@v2 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: bundler-cache: true ruby-version: ${{ matrix.ruby }} - name: Run tests run: bundle exec rake ruby-prawn-svg-0.32.0/.gitignore000066400000000000000000000001641402126170300164640ustar00rootroot00000000000000.DS_Store spec/sample_output/*.pdf prawn-svg-*.gem Gemfile.lock .rvmrc .*.swp .ruby-version vendor/bundle/ .bundle/ ruby-prawn-svg-0.32.0/.rspec000066400000000000000000000000371402126170300156100ustar00rootroot00000000000000--format documentation --color ruby-prawn-svg-0.32.0/Gemfile000066400000000000000000000010631402126170300157660ustar00rootroot00000000000000source "http://rubygems.org" # Declare your gem's dependencies in prawn-svg.gemspec. # Bundler will treat runtime dependencies like base dependencies, and # development dependencies will be added by default to the :development group. gemspec # Declare any dependencies that are still in development here instead of in # your gemspec. These might include edge Rails or gems from your path or # Git. Remember to move these dependencies to your gemspec before releasing # your gem to rubygems.org. # To use debugger # gem 'ruby-debug19', :require => 'ruby-debug' ruby-prawn-svg-0.32.0/LICENSE000066400000000000000000000020631402126170300155010ustar00rootroot00000000000000The MIT License Copyright 2010-2019 Roger Nesbitt 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. ruby-prawn-svg-0.32.0/README.md000066400000000000000000000152361402126170300157610ustar00rootroot00000000000000# prawn-svg [![Gem Version](https://badge.fury.io/rb/prawn-svg.svg)](https://badge.fury.io/rb/prawn-svg) ![Build Status](https://github.com/mogest/prawn-svg/actions/workflows/test.yml/badge.svg?branch=master) An SVG renderer for the Prawn PDF library. This will take an SVG document as input and render it into your PDF. Find out more about the Prawn PDF library at: http://github.com/prawnpdf/prawn prawn-svg is compatible with all versions of Prawn from 0.11.1 onwards, including the 1.x and 2.x series. The minimum Ruby version required is 2.3.0. ## Using prawn-svg ```ruby Prawn::Document.generate("test.pdf") do svg '' end ``` prawn-svg will do something sensible if you call it with only an SVG document, but you can also pass the following options to tailor its operation: Option | Data type | Description ----------- | --------- | ----------- :at | [integer, integer] | Specify the location on the page you want the SVG to appear. :position | :left, :center, :right, integer | If :at not specified, specifies the horizontal position to show the SVG. Defaults to :left. :vposition | :top, :center, :bottom, integer | If :at not specified, specifies the vertical position to show the SVG. Defaults to current cursor position. :width | integer | Desired width of the SVG. Defaults to horizontal space available. :height | integer | Desired height of the SVG. Defaults to vertical space available. :enable_web_requests | boolean | If true, prawn-svg will make http and https requests to fetch images. Defaults to true. :enable_file_requests_with_root | string | If not nil, prawn-svg will serve `file:` URLs from your local disk if the file is located under the specified directory. It is very dangerous to specify the root path ("/") if you're not fully in control of your input SVG. Defaults to `nil` (off). :cache_images | boolean | If true, prawn-svg will cache the result of all URL requests. Defaults to false. :fallback_font_name | string | A font name which will override the default fallback font of Times-Roman. If this value is set to nil, prawn-svg will ignore a request for an unknown font and log a warning. ## Examples ```ruby # Render the logo contained in the file logo.svg at 100, 100 with a width of 300 svg IO.read("logo.svg"), at: [100, 100], width: 300 # Render the logo at the current Y cursor position, centered in the current bounding box svg IO.read("logo.svg"), position: :center # Render the logo at the current Y cursor position, and serve file: links relative to its directory root_path = "/apps/myapp/current/images" svg IO.read("#{root_path}/logo.svg"), enable_file_requests_with_root: root_path ``` ## Supported features prawn-svg supports most but not all of the full SVG 1.1 specification. It currently supports: - <line>, <polyline>, <polygon>, <circle> and <ellipse> - <rect>. Rounded rects are supported, but only one radius is applied to all corners. - <path> supports all commands defined in SVG 1.1, although the implementation of elliptical arc is a bit rough at the moment. - ``, `` and `` with attributes `x`, `y`, `dx`, `dy`, `rotate`, 'textLength', 'lengthAdjust', and with extra properties `text-anchor`, `text-decoration` (underline only), `font-size`, `font-family`, `font-weight`, `font-style`, `letter-spacing` - <svg>, <g> and <symbol> - <use> - <style> (see CSS section below) - <image> with http:, https:, data:image/\*;base64 and `file:` schemes (`file:` is disabled by default for security reasons, see Options section above) - <clipPath> - `` - `` and `` are implemented on Prawn 2.2.0+ with attributes `gradientUnits` and `gradientTransform` (spreadMethod and stop-opacity are unimplemented.) - `` and ``, although prawn-svg cannot handle any data that is not SVG so `` tags are always ignored. - properties: `clip-path`, `color`, `display`, `fill`, `fill-opacity`, `fill-rule`, `opacity`, `overflow`, `stroke`, `stroke-dasharray`, `stroke-linecap`, `stroke-opacity`, `stroke-width` - properties on lines, polylines, polygons and paths: `marker-end`, `marker-mid`, `marker-start` - attributes on all elements: `class`, `id`, `style`, `transform`, `xml:space` - the viewBox attribute on <svg> and `` elements - the preserveAspectRatio attribute on <svg>, <image> and `` elements - transform methods: `translate`, `translateX`, `translateY`, `rotate`, `scale`, `skewX`, `skewY`, `matrix` - colors: HTML standard names, #xxx, #xxxxxx, rgb(1, 2, 3), rgb(1%, 2%, 3%) - measurements specified in pt, cm, dm, ft, in, m, mm, yd, pc, % - fonts: generic CSS fonts, built-in PDF fonts, and any TTF fonts in your fonts path, specified in any of the measurements above plus `em` or `rem` ## CSS prawn-svg supports CSS, both in ` SVG end it "is correctly converted to a call stack" do element.process expect(element.calls).to eq [ ["fill_color", ["000000"], {}, []], ["transformation_matrix", [1, 0, 0, 1, 0, 0], {}, []], ["transformation_matrix", [1, 0, 0, 1, 0, 0], {}, []], ["save", [], {}, []], ["restore", [], {}, []], ["save", [], {}, []], ["fill_color", ["0000ff"], {}, []], ["fill", [], {}, [ ["rectangle", [[0.0, 200.0], 10.0, 10.0], {}, []] ]], ["restore", [], {}, []], ["save", [], {}, []], ["fill_color", ["008000"], {}, []], ["fill", [], {}, [ ["rectangle", [[10.0, 200.0], 10.0, 10.0], {}, []] ]], ["restore", [], {}, []], ["save", [], {}, []], ["fill_color", ["ff0000"], {}, []], ["fill", [], {}, [ ["rectangle", [[20.0, 200.0], 10.0, 10.0], {}, []] ]], ["restore", [], {}, []], ["save", [], {}, []], ["fill_color", ["ffff00"], {}, []], ["fill", [], {}, [ ["rectangle", [[30.0, 200.0], 10.0, 10.0], {}, []] ]], ["restore", [], {}, []] ] end end context "with option :position" do let(:svg) { IO.read("#{root}/spec/sample_svg/cubic01a.svg") } it "aligns the image as requested" do Prawn::Document.generate("#{root}/spec/sample_output/_with_position.pdf") do |prawn| width = prawn.bounds.width / 3 prawn.svg svg, :width => width, :position => :left prawn.svg svg, :width => width, :position => :center prawn.svg svg, :width => width, :position => :right prawn.svg svg, :width => width, :position => 50 prawn.svg svg, :width => width end end end context "with option :vposition" do let(:svg) { IO.read("#{root}/spec/sample_svg/cubic01a.svg") } it "aligns the image as requested" do Prawn::Document.generate("#{root}/spec/sample_output/_with_vposition.pdf") do |prawn| width = prawn.bounds.width / 3 prawn.svg svg, :width => width, :position => :left, :vposition => :bottom prawn.svg svg, :width => width, :position => :center, :vposition => :center prawn.svg svg, :width => width, :position => :right, :vposition => :top prawn.svg svg, :width => width, :position => 50, :vposition => 50 end end end describe "sample file rendering" do files = Dir["#{root}/spec/sample_svg/*.svg"] it "has at least 10 SVG sample files to test" do files.length.should >= 10 end files.each do |file| it "renders the #{File.basename file} sample file without warnings or crashing" do expect(Net::HTTP).to_not receive(:get) warnings = nil Prawn::Document.generate("#{root}/spec/sample_output/#{File.basename file}.pdf") do |prawn| r = prawn.svg IO.read(file), :at => [0, prawn.bounds.top], :width => prawn.bounds.width, :enable_file_requests_with_root => File.dirname(__FILE__) do |doc| doc.url_loader.add_to_cache("https://raw.githubusercontent.com/mogest/prawn-svg/master/spec/sample_images/mushroom-wide.jpg", IO.read("#{root}/spec/sample_images/mushroom-wide.jpg")) doc.url_loader.add_to_cache("https://raw.githubusercontent.com/mogest/prawn-svg/master/spec/sample_images/mushroom-long.jpg", IO.read("#{root}/spec/sample_images/mushroom-long.jpg")) end warnings = r[:warnings].reject {|w| w =~ /Verdana/ && w =~ /is not a known font/ || w =~ /(render gradients$|waiting on the Prawn project)/} end warnings.should == [] end end end describe "multiple file rendering" do it "renders multiple files on to the same PDF" do Prawn::Document.generate("#{root}/spec/sample_output/_multiple.pdf") do |prawn| width = prawn.bounds.width y = prawn.bounds.top - 12 prawn.draw_text "This is multiple SVGs being output to the same PDF", :at => [0, y] y -= 12 prawn.svg IO.read("#{root}/spec/sample_svg/arcs01.svg"), :at => [0, y], :width => width / 2 prawn.svg IO.read("#{root}/spec/sample_svg/circle01.svg"), :at => [width / 2, y], :width => width / 2 y -= 120 prawn.draw_text "Here are some more PDFs below", :at => [0, y] y -= 12 prawn.svg IO.read("#{root}/spec/sample_svg/quad01.svg"), :at => [0, y], :width => width / 3 prawn.svg IO.read("#{root}/spec/sample_svg/rect01.svg"), :at => [width / 3, y], :width => width / 3 prawn.svg IO.read("#{root}/spec/sample_svg/rect02.svg"), :at => [width / 3 * 2, y], :width => width / 3 end end end end ruby-prawn-svg-0.32.0/spec/prawn/000077500000000000000000000000001402126170300165545ustar00rootroot00000000000000ruby-prawn-svg-0.32.0/spec/prawn/svg/000077500000000000000000000000001402126170300173535ustar00rootroot00000000000000ruby-prawn-svg-0.32.0/spec/prawn/svg/attributes/000077500000000000000000000000001402126170300215415ustar00rootroot00000000000000ruby-prawn-svg-0.32.0/spec/prawn/svg/attributes/opacity_spec.rb000066400000000000000000000046121402126170300245530ustar00rootroot00000000000000require 'spec_helper' describe Prawn::SVG::Attributes::Opacity do class OpacityTestElement include Prawn::SVG::Attributes::Opacity attr_accessor :properties, :state def initialize @properties = ::Prawn::SVG::Properties.new @state = ::Prawn::SVG::State.new end def clamp(value, min_value, max_value) [[value, min_value].max, max_value].min end end let(:element) { OpacityTestElement.new } describe "#parse_opacity_attributes_and_call" do subject { element.parse_opacity_attributes_and_call } context "with no opacity specified" do it "does nothing" do expect(element).not_to receive(:add_call_and_enter) subject end end context "with opacity" do it "sets fill and stroke opacity" do element.properties.opacity = '0.4' expect(element).to receive(:add_call_and_enter).with('transparent', 0.4, 0.4) subject expect(element.state.fill_opacity).to eq 0.4 expect(element.state.stroke_opacity).to eq 0.4 end end context "with just fill opacity" do it "sets fill opacity and sets stroke opacity to 1" do element.properties.fill_opacity = '0.4' expect(element).to receive(:add_call_and_enter).with('transparent', 0.4, 1) subject expect(element.state.fill_opacity).to eq 0.4 expect(element.state.stroke_opacity).to eq 1 end end context "with an existing fill/stroke opacity" do it "multiplies the new opacity by the old" do element.state.fill_opacity = 0.5 element.state.stroke_opacity = 0.8 element.properties.fill_opacity = '0.4' element.properties.stroke_opacity = '0.5' expect(element).to receive(:add_call_and_enter).with('transparent', 0.2, 0.4) subject expect(element.state.fill_opacity).to eq 0.2 expect(element.state.stroke_opacity).to eq 0.4 end end context "with stroke, fill, and opacity all specified" do it "choses the lower of them" do element.properties.fill_opacity = '0.4' element.properties.stroke_opacity = '0.6' element.properties.opacity = '0.5' expect(element).to receive(:add_call_and_enter).with('transparent', 0.4, 0.5) subject expect(element.state.fill_opacity).to eq 0.4 expect(element.state.stroke_opacity).to eq 0.5 end end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/attributes/transform_spec.rb000066400000000000000000000026251402126170300251200ustar00rootroot00000000000000require 'spec_helper' describe Prawn::SVG::Attributes::Transform do class TransformTestElement include Prawn::SVG::Attributes::Transform attr_accessor :attributes, :warnings def initialize @warnings = [] @attributes = {} end end let(:element) { TransformTestElement.new } subject { element.send :parse_transform_attribute_and_call } context "when a non-identity matrix is requested" do let(:transform) { 'translate(-5.5)' } it "passes the transform and executes the returned matrix" do expect(element).to receive(:parse_transform_attribute).with(transform).and_return([1, 2, 3, 4, 5, 6]) expect(element).to receive(:add_call_and_enter).with('transformation_matrix', 1, 2, 3, 4, 5, 6) element.attributes['transform'] = transform subject end end context "when an identity matrix is requested" do let(:transform) { 'translate(0)' } it "does not execute any commands" do expect(element).to receive(:parse_transform_attribute).with(transform).and_return([1, 0, 0, 1, 0, 0]) expect(element).not_to receive(:add_call_and_enter) element.attributes['transform'] = transform subject end end context "when transform is blank" do it "does nothing" do expect(element).not_to receive(:parse_transform_attribute) expect(element).not_to receive(:add_call_and_enter) subject end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/calculators/000077500000000000000000000000001402126170300216675ustar00rootroot00000000000000ruby-prawn-svg-0.32.0/spec/prawn/svg/calculators/aspect_ratio_spec.rb000066400000000000000000000066441402126170300257150ustar00rootroot00000000000000require File.dirname(__FILE__) + '/../../../spec_helper' describe Prawn::SVG::Calculators::AspectRatio do def test(*args) aspect = Prawn::SVG::Calculators::AspectRatio.new(*args) [[aspect.width, aspect.height], [aspect.x, aspect.y]] end it "handles none" do expect(test "none", [50,80], [100,100]).to eq [[50, 80], [0, 0]] expect(test "none", [100,100], [50,80]).to eq [[100, 100], [0, 0]] end context "using meet" do context "with smaller containers than objects" do let(:coords) { [[50,80], [100,100]] } it "correctly calculates the result" do expect(test "xMidYMid meet", *coords).to eq [[50, 50], [0, 15]] expect(test "xMinYMin meet", *coords).to eq [[50, 50], [0, 0]] expect(test "xMaxYMax meet", *coords).to eq [[50, 50], [0, 30]] end end context "with bigger containers than objects" do let(:coords) { [[100,80], [50,50]] } it "correctly calculates the result" do expect(test "xMidYMid meet", *coords).to eq [[80, 80], [10, 0]] expect(test "xMinYMin meet", *coords).to eq [[80, 80], [0, 0]] expect(test "xMaxYMax meet", *coords).to eq [[80, 80], [20, 0]] end end context "with bigger square containers" do let(:coords) { [[100,100], [50,80]] } it "correctly calculates the result" do expect(test "xMidYMid meet", *coords).to eq [[62.5, 100], [18.75, 0]] expect(test "xMinYMin meet", *coords).to eq [[62.5, 100], [0, 0]] expect(test "xMaxYMax meet", *coords).to eq [[62.5, 100], [37.5, 0]] end end context "with oddly shaped containers" do let(:coords) { [[100,20], [50,50]] } it "correctly calculates the result" do expect(test "xMidYMid meet", *coords).to eq [[20, 20], [40, 0]] expect(test "xMinYMin meet", *coords).to eq [[20, 20], [0, 0]] expect(test "xMaxYMax meet", *coords).to eq [[20, 20], [80, 0]] end end end context "using slice" do context "with smaller containers than objects" do let(:coords) { [[50,80], [100,100]] } it "correctly calculates the result" do expect(test "xMidYMid slice", *coords).to eq [[80, 80], [-15, 0]] expect(test "xMinYMin slice", *coords).to eq [[80, 80], [0, 0]] expect(test "xMaxYMax slice", *coords).to eq [[80, 80], [-30, 0]] end end context "with bigger containers than objects" do let(:coords) { [[100,80], [50,50]] } it "correctly calculates the result" do expect(test "xMidYMid slice", *coords).to eq [[100, 100], [0, -10]] expect(test "xMinYMin slice", *coords).to eq [[100, 100], [0, 0]] expect(test "xMaxYMax slice", *coords).to eq [[100, 100], [0, -20]] end end context "with oddly shaped containers" do let(:coords) { [[100,20], [50,50]] } it "correctly calculates the result" do expect(test "xMidYMid slice", *coords).to eq [[100, 100], [0, -40]] expect(test "xMinYMin slice", *coords).to eq [[100, 100], [0, 0]] expect(test "xMaxYMax slice", *coords).to eq [[100, 100], [0, -80]] end end end it "defaults to 'xMidYMid meet' if nothing is supplied" do expect(test "", [50,80], [100,100]).to eq test "xMidYMid meet", [50,80], [100,100] end it "defaults to 'xMidYMid meet' if something invalid is supplied" do expect(test "completely invalid", [50,80], [100,100]).to eq test "xMidYMid meet", [50,80], [100,100] end end ruby-prawn-svg-0.32.0/spec/prawn/svg/calculators/document_sizing_spec.rb000066400000000000000000000125261402126170300264350ustar00rootroot00000000000000require File.dirname(__FILE__) + '/../../../spec_helper' describe Prawn::SVG::Calculators::DocumentSizing do let(:attributes) do {"width" => "150", "height" => "200", "viewBox" => "0 -30 300 800", "preserveAspectRatio" => "xMaxYMid meet"} end let(:bounds) { [1200, 800] } let(:sizing) { Prawn::SVG::Calculators::DocumentSizing.new(bounds, attributes) } describe "#initialize" do it "takes bounds and a set of attributes and calls set_from_attributes" do expect(sizing.instance_variable_get :@bounds).to eq bounds expect(sizing.instance_variable_get :@document_width).to eq "150" end end describe "#set_from_attributes" do let(:sizing) { Prawn::SVG::Calculators::DocumentSizing.new(bounds) } it "sets ivars from the passed-in attributes hash" do sizing.set_from_attributes(attributes) expect(sizing.instance_variable_get :@document_width).to eq "150" expect(sizing.instance_variable_get :@document_height).to eq "200" expect(sizing.instance_variable_get :@view_box).to eq "0 -30 300 800" expect(sizing.instance_variable_get :@preserve_aspect_ratio).to eq "xMaxYMid meet" end end describe "#calculate" do it "calculates the document sizing measurements for a given set of inputs" do sizing.calculate expect(sizing.x_offset).to eq(-75 / 0.25) expect(sizing.y_offset).to eq(-30) expect(sizing.x_scale).to eq 0.25 expect(sizing.y_scale).to eq 0.25 expect(sizing.viewport_width).to eq 300 expect(sizing.viewport_height).to eq 800 expect(sizing.output_width).to eq 150 expect(sizing.output_height).to eq 200 end it "scales again based on requested width" do sizing.requested_width = 75 sizing.calculate expect(sizing.x_scale).to eq 0.125 expect(sizing.y_scale).to eq 0.125 expect(sizing.viewport_width).to eq 300 expect(sizing.viewport_height).to eq 800 expect(sizing.output_width).to eq 75 expect(sizing.output_height).to eq 100 end it "scales again based on requested height" do sizing.requested_height = 100 sizing.calculate expect(sizing.x_scale).to eq 0.125 expect(sizing.y_scale).to eq 0.125 expect(sizing.viewport_width).to eq 300 expect(sizing.viewport_height).to eq 800 expect(sizing.output_width).to eq 75 expect(sizing.output_height).to eq 100 end it "correctly handles % values being passed in" do sizing.document_width = sizing.document_height = "50%" sizing.calculate expect(sizing.output_width).to eq 600 expect(sizing.output_height).to eq 400 end context "when SVG does not specify width and height" do context "when a viewBox is specified" do let(:attributes) { {"viewBox" => "0 0 100 200"} } it "defaults to 100% width and uses the viewbox ratio for height" do sizing.calculate expect(sizing.viewport_width).to eq 100 expect(sizing.viewport_height).to eq 200 expect(sizing.output_width).to eq 1200 expect(sizing.output_height).to eq 2400 end end context "when a requested width and height are supplied" do let(:attributes) { {} } it "uses the requested width and height" do sizing.requested_width = 550 sizing.requested_height = 400 sizing.calculate expect(sizing.viewport_width).to eq 550 expect(sizing.viewport_height).to eq 400 expect(sizing.output_width).to eq 550 expect(sizing.output_height).to eq 400 end end context "when a viewBox and a requested width/height are supplied" do let(:attributes) { {"viewBox" => "0 0 100 200"} } it "uses the requested width and height" do sizing.requested_width = 550 sizing.requested_height = 400 sizing.calculate expect(sizing.viewport_width).to eq 100 expect(sizing.viewport_height).to eq 200 expect(sizing.output_width).to eq 550 expect(sizing.output_height).to eq 400 end end context "when a viewBox and a requested width is supplied" do let(:attributes) { {"viewBox" => "0 0 100 200"} } it "uses the requested width and calculates the height based on the viewBox" do sizing.requested_width = 550 sizing.calculate expect(sizing.viewport_width).to eq 100 expect(sizing.viewport_height).to eq 200 expect(sizing.output_width).to eq 550 expect(sizing.output_height).to eq 1100 end end context "when a viewBox and a requested height is supplied" do let(:attributes) { {"viewBox" => "0 0 100 200"} } it "uses the requested height and calculates the width based on the viewBox" do sizing.requested_height = 400 sizing.calculate expect(sizing.viewport_width).to eq 100 expect(sizing.viewport_height).to eq 200 expect(sizing.output_width).to eq 200 expect(sizing.output_height).to eq 400 end end context "when neither viewBox nor requested width/height specified" do let(:attributes) { {} } it "defaults to 100%" do sizing.calculate expect(sizing.output_width).to eq 1200 expect(sizing.output_height).to eq 800 end end end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/calculators/pixels_spec.rb000066400000000000000000000047551402126170300245450ustar00rootroot00000000000000require 'spec_helper' describe Prawn::SVG::Calculators::Pixels do class TestPixelsCalculator include Prawn::SVG::Calculators::Pixels def computed_properties Struct.new(:numerical_font_size).new(16) end [:x, :y, :pixels, :x_pixels, :y_pixels].each { |method| public method } end let(:viewport_sizing) do instance_double(Prawn::SVG::Calculators::DocumentSizing, viewport_width: 600, viewport_height: 400, viewport_diagonal: 500, :requested_width= => nil, :requested_height= => nil) end let(:document_sizing) do instance_double(Prawn::SVG::Calculators::DocumentSizing, output_height: 800) end let(:state) { instance_double(Prawn::SVG::State, viewport_sizing: viewport_sizing) } let(:document) { instance_double(Prawn::SVG::Document, sizing: document_sizing) } subject { TestPixelsCalculator.new } before do allow(subject).to receive(:state).and_return(state) allow(subject).to receive(:document).and_return(document) end describe "#pixels" do it "converts a variety of measurement units to points" do expect(subject.pixels(32)).to eq 32.0 expect(subject.pixels(32.0)).to eq 32.0 expect(subject.pixels("32")).to eq 32.0 expect(subject.pixels("32unknown")).to eq 32.0 expect(subject.pixels("32px")).to eq 32.0 expect(subject.pixels("32pt")).to eq 32.0 expect(subject.pixels("32in")).to eq 32.0 * 72 expect(subject.pixels("32pc")).to eq 32.0 * 15 expect(subject.pixels("4em")).to eq 4 * 16 expect(subject.pixels("4ex")).to eq 4 * 8 expect(subject.pixels("32mm")).to be_within(0.0001).of(32 * 72 * 0.0393700787) expect(subject.pixels("32cm")).to be_within(0.0001).of(32 * 72 * 0.393700787) expect(subject.pixels("50%")).to eq 250 end end describe "#x_pixels" do it "uses the viewport width for percentages" do expect(subject.x_pixels("50")).to eq 50 expect(subject.x_pixels("50%")).to eq 300 end end describe "#y_pixels" do it "uses the viewport height for percentages" do expect(subject.y_pixels("50")).to eq 50 expect(subject.y_pixels("50%")).to eq 200 end end describe "#x" do it "performs the same as #x_pixels" do expect(subject.x("50")).to eq 50 expect(subject.x("50%")).to eq 300 end end describe "#y" do it "performs the same as #y_pixels but subtracts the pixels from the page height" do expect(subject.y("50")).to eq 800 - 50 expect(subject.y("50%")).to eq 800 - 200 end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/color_spec.rb000066400000000000000000000040551402126170300220340ustar00rootroot00000000000000require File.dirname(__FILE__) + '/../../spec_helper' describe Prawn::SVG::Color do describe "::color_to_hex" do it "converts #xxx to a hex value" do Prawn::SVG::Color.color_to_hex("#9ab").should == "99aabb" end it "converts #xxxxxx to a hex value" do Prawn::SVG::Color.color_to_hex("#9ab123").should == "9ab123" end it "converts an html colour name to a hex value" do Prawn::SVG::Color.color_to_hex("White").should == "ffffff" end it "converts an rgb string to a hex value" do Prawn::SVG::Color.color_to_hex("rgb(16, 32, 48)").should == "102030" Prawn::SVG::Color.color_to_hex("rgb(-5, 50%, 120%)").should == "007fff" end it "scans the string and finds the first colour it can parse" do Prawn::SVG::Color.color_to_hex("function(#someurl, 0) nonexistent rgb( 3 ,4,5 ) white").should == "030405" end it "ignores url()s" do expect(Prawn::SVG::Color.color_to_hex("url(#someplace) red")).to eq 'ff0000' end it "returns black if the color doesn't exist" do expect(Prawn::SVG::Color.color_to_hex("blurble")).to eq '000000' end it "returns nil if there's no fallback after a url()" do expect(Prawn::SVG::Color.color_to_hex("url(#someplace)")).to be nil end end describe "::parse" do let(:gradients) { {"flan" => flan_gradient, "drob" => drob_gradient} } let(:flan_gradient) { double } let(:drob_gradient) { double } it "returns a list of all colors parsed, ignoring impossible or non-existent colors" do results = Prawn::SVG::Color.parse("url(#nope) url(#flan) blurble green #123", gradients) expect(results).to eq [ flan_gradient, Prawn::SVG::Color::Hex.new("008000"), Prawn::SVG::Color::Hex.new("112233") ] end it "appends black to the list if there aren't any url() references" do results = Prawn::SVG::Color.parse("blurble green", gradients) expect(results).to eq [ Prawn::SVG::Color::Hex.new("008000"), Prawn::SVG::Color::Hex.new("000000") ] end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/css/000077500000000000000000000000001402126170300201435ustar00rootroot00000000000000ruby-prawn-svg-0.32.0/spec/prawn/svg/css/font_family_parser_spec.rb000066400000000000000000000015121402126170300253640ustar00rootroot00000000000000require 'spec_helper' RSpec.describe Prawn::SVG::CSS::FontFamilyParser do describe "#parse" do it "correctly handles quotes and escaping" do tests = { "" => [], "font" => ["font"], "font name, other font" => ["font name", "other font"], "'font name', other font" => ["font name", "other font"], "'font, name', other font" => ["font, name", "other font"], '"font name", other font' => ["font name", "other font"], '"font, name", other font' => ["font, name", "other font"], 'weird \\" name' => ['weird " name'], 'weird\\, name' => ["weird, name"], ' stupid , spacing ' => ["stupid", "spacing"], } tests.each do |string, expected| expect(Prawn::SVG::CSS::FontFamilyParser.parse(string)).to eq expected end end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/css/selector_parser_spec.rb000066400000000000000000000031741402126170300247030ustar00rootroot00000000000000require 'spec_helper' RSpec.describe Prawn::SVG::CSS::SelectorParser do describe "::parse" do it "parses a simple selector" do expect(described_class.parse("div")).to eq [{name: "div"}] expect(described_class.parse(".c1")).to eq [{class: ["c1"]}] end it "parses a complex selector" do result = described_class.parse("div#count .c1.c2 > span.large + div~.other:first-child *:nth-child(3)") expect(result).to eq [ {name: "div", id: ["count"]}, {combinator: :descendant, class: ["c1", "c2"]}, {combinator: :child, name: "span", class: ["large"]}, {combinator: :adjacent, name: "div"}, {combinator: :siblings, class: ["other"], pseudo_class: ["first-child"]}, {combinator: :descendant, name: "*", pseudo_class: ["nth-child(3)"]}, ] end it "parses attributes" do expect(described_class.parse("[abc]")).to eq [{attribute: [["abc", nil, nil]]}] expect(described_class.parse("[abc=123]")).to eq [{attribute: [["abc", '=', '123']]}] expect(described_class.parse("[abc^=123]")).to eq [{attribute: [["abc", '^=', '123']]}] expect(described_class.parse("[ abc ^= 123 ]")).to eq [{attribute: [["abc", '^=', '123']]}] expect(described_class.parse("[abc^='123']")).to eq [{attribute: [["abc", '^=', '123']]}] expect(described_class.parse("[abc^= '123' ]")).to eq [{attribute: [["abc", '^=', '123']]}] expect(described_class.parse("[abc^= '123\\'456' ]")).to eq [{attribute: [["abc", '^=', '123\'456']]}] expect(described_class.parse('[abc^= "123\\"456" ]')).to eq [{attribute: [["abc", '^=', '123"456']]}] end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/css/stylesheets_spec.rb000066400000000000000000000076741402126170300240740ustar00rootroot00000000000000require 'spec_helper' RSpec.describe Prawn::SVG::CSS::Stylesheets do describe "typical usage" do let(:svg) { <<-SVG } SVG it "associates styles with elements" do result = Prawn::SVG::CSS::Stylesheets.new(CssParser::Parser.new, REXML::Document.new(svg)).load width_and_styles = result.map { |k, v| [k.attributes["width"].to_i, v] }.sort_by(&:first) expected = [ [1, [["fill", "#ff0000", false]]], [2, [["fill", "#ff0000", false], ["fill", "#330000", false], ["fill", "#440000", false], ["fill", "#220000", false]]], [3, [["fill", "#ff0000", false], ["fill", "#00ff00", false]]], [4, [["fill", "#ff0000", false], ["fill", "#330000", false], ["fill", "#440000", false], ["fill", "#00ff00", false]]], ] expected << [5, [["fill", "#ff0000", false], ["fill", "#330000", false], ["fill", "#330000", false], ["fill", "#440000", false], ["fill", "#00ff00", false]]] expected.concat [ [6, [["fill", "#ff0000", false], ["fill", "#441234", false], ["fill", "#0000ff", false]]], [7, [["fill", "#550000", false]]], [8, [["fill", "#660000", false]]], [9, [["fill", "#770000", false]]], [10, [["fill", "#880000", false]]], [11, [["fill", "#990000", false]]], [12, [["fill", "#aa0000", false]]], [13, [["fill", "#bb0000", false]]], [14, [["fill", "#cc0000", false]]], [15, [["fill", "#dd0000", false]]], [16, [["fill", "#ee0000", false]]], ] expect(width_and_styles).to eq(expected) end end describe "style tag parsing" do let(:svg) do <<-SVG SVG end it "scans the document for style tags and adds the style information to the css parser" do css_parser = instance_double(CssParser::Parser) expect(css_parser).to receive(:add_block!).with("a\n before>\n x y\n inside <>>\n k j\n after\nz") expect(css_parser).to receive(:add_block!).with("hello") allow(css_parser).to receive(:each_rule_set) Prawn::SVG::CSS::Stylesheets.new(css_parser, REXML::Document.new(svg)).load end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/document_spec.rb000066400000000000000000000017701402126170300225350ustar00rootroot00000000000000require File.dirname(__FILE__) + '/../../spec_helper' describe Prawn::SVG::Document do let(:bounds) { [100, 100] } let(:options) { {} } describe "#initialize" do context "when unparsable XML is provided" do let(:svg) { "this isn't SVG data" } it "raises an exception" do expect { Prawn::SVG::Document.new(svg, bounds, options) }.to raise_error Prawn::SVG::Document::InvalidSVGData, "The data supplied is not a valid SVG document." end end context "when the user passes in a filename instead of SVG data" do let(:svg) { "some_file.svg" } it "raises an exception letting them know what they've done" do expect { Prawn::SVG::Document.new(svg, bounds, options) }.to raise_error Prawn::SVG::Document::InvalidSVGData, "The data supplied is not a valid SVG document. It looks like you've supplied a filename instead; use IO.read(filename) to get the data before you pass it to prawn-svg." end end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/elements/000077500000000000000000000000001402126170300211675ustar00rootroot00000000000000ruby-prawn-svg-0.32.0/spec/prawn/svg/elements/base_spec.rb000066400000000000000000000146541402126170300234520ustar00rootroot00000000000000require 'spec_helper' describe Prawn::SVG::Elements::Base do let(:svg) { "" } let(:document) { Prawn::SVG::Document.new(svg, [800, 600], {}, font_registry: Prawn::SVG::FontRegistry.new("Helvetica" => {:normal => nil})) } let(:parent_calls) { [] } let(:element) { Prawn::SVG::Elements::Base.new(document, document.root, parent_calls, fake_state) } describe "#initialize" do let(:svg) { '' } it "adds itself to the elements_by_id hash if an id attribute is supplied" do element expect(document.elements_by_id["hello"]).to eq element end end describe "#process" do it "calls #parse and #apply so subclasses can parse the element" do expect(element).to receive(:parse).ordered expect(element).to receive(:apply).ordered element.process end describe "applying calls from the standard attributes" do let(:svg) do <<-SVG SVG end it "appends the relevant calls" do element.process expect(element.base_calls).to eq [ ["transformation_matrix", [2, 0, 0, 2, 0, 0], {}, [ ["transparent", [0.5, 1], {}, [ ["fill_color", ["ff0000"], {}, []], ["stroke_color", ["0000ff"], {}, []], ["line_width", [5.0], {}, []], ["fill_and_stroke", [], {}, []] ]] ]] ] end end describe "fills and strokes" do before { element.process } subject { element.base_calls.last } context "with neither fill nor stroke" do let(:svg) { '' } it { is_expected.to eq ['end_path', [], {}, []] } end context "with a fill only" do let(:svg) { '' } it { is_expected.to eq ['fill', [], {}, []] } end context "with a stroke only" do let(:svg) { '' } it { is_expected.to eq ['stroke', [], {}, []] } end context "with fill and stroke" do let(:svg) { '' } it { is_expected.to eq ['fill_and_stroke', [], {}, []] } end context "with fill with evenodd fill rule" do let(:svg) { '' } it { is_expected.to eq ['fill', [], {fill_rule: :even_odd}, []] } end end it "appends calls to the parent element" do expect(element).to receive(:apply) do element.send :add_call, "test", "argument", kw: 'argument' end element.process expect(element.parent_calls).to eq [["fill", [], {}, [["test", ["argument"], {kw: 'argument'}, []]]]] end it "quietly absorbs a SkipElementQuietly exception" do expect(element).to receive(:parse).and_raise(Prawn::SVG::Elements::Base::SkipElementQuietly) expect(element).to_not receive(:apply) element.process expect(document.warnings).to be_empty end it "absorbs a SkipElementError exception, logging a warning" do expect(element).to receive(:parse).and_raise(Prawn::SVG::Elements::Base::SkipElementError, "hello") expect(element).to_not receive(:apply) element.process expect(document.warnings).to eq ["hello"] end end describe "#apply_colors" do before do element.send(:extract_attributes_and_properties) end subject { element.send :apply_colors } it "doesn't change anything if no fill attribute provided" do expect(element).to_not receive(:add_call) subject end it "doesn't change anything if 'inherit' fill attribute provided" do element.properties.fill = 'inherit' expect(element).to_not receive(:add_call) subject end it "doesn't change anything if 'none' fill attribute provided" do element.properties.fill = 'none' expect(element).to_not receive(:add_call) subject end it "uses the fill attribute's color" do expect(element).to receive(:add_call).with('fill_color', 'ff0000') element.properties.fill = 'red' subject end it "uses black if the fill attribute's color is unparseable" do expect(element).to receive(:add_call).with('fill_color', '000000') element.properties.fill = 'blarble' subject end it "uses the color attribute if 'currentColor' fill attribute provided" do expect(element).to receive(:add_call).with('fill_color', 'ff0000') element.properties.fill = 'currentColor' element.state.computed_properties.color = 'red' subject end context "with a color attribute defined on a parent element" do let(:svg) { '' } let(:element) { Prawn::SVG::Elements::Root.new(document, document.root, parent_calls) } let(:flattened_calls) { flatten_calls(element.base_calls) } it "uses the parent's color element if 'currentColor' fill attribute provided" do element.process expect(flattened_calls).to include ['fill_color', ['ff0000'], {}] expect(flattened_calls).not_to include ['fill_color', ['00ff00'], {}] end end it "computes to 'none' if UnresolvableURLWithNoFallbackError is raised" do expect(element).to_not receive(:add_call) element.properties.fill = 'url()' subject expect(element.computed_properties.fill).to eq 'none' end end describe "stylesheets" do let(:svg) { <<-SVG } SVG it "applies stylesheet styling but style attributes take precedence" do document = Prawn::SVG::Document.new(svg, [100, 100], {}) calls = [] element = Prawn::SVG::Elements::Root.new(document, document.root, calls) element.process fill_colors = calls.select { |cmd, _, _| cmd == 'fill_color' }.map { |_, args, _| args.first } expect(fill_colors).to eq ['000000', 'ff0000', '008000', 'ffff00'] end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/elements/gradient_spec.rb000066400000000000000000000103601402126170300243230ustar00rootroot00000000000000require 'spec_helper' describe Prawn::SVG::Elements::Gradient do let(:document) { Prawn::SVG::Document.new(svg, [800, 600], {width: 800, height: 600}) } let(:element) { Prawn::SVG::Elements::Gradient.new(document, document.root, [], fake_state) } before do allow(element).to receive(:assert_compatible_prawn_version) element.process end describe "object bounding box with linear gradient" do let(:svg) do <<-SVG SVG end it "is stored in the document gradients table" do expect(document.gradients["flag"]).to eq element end it "returns correct gradient arguments for an element" do arguments = element.gradient_arguments(double(bounding_box: [100, 100, 200, 0])) expect(arguments).to eq( from: [100.0, 100.0], to: [120.0, 0.0], stops: [[0, "ff0000"], [0.25, "ff0000"], [0.5, "ffffff"], [0.75, "0000ff"], [1, "0000ff"]], apply_transformations: true, ) end it "returns nil if the element doesn't have a bounding box" do arguments = element.gradient_arguments(double(bounding_box: nil)) expect(arguments).to be nil end end describe "object bounding box with radial gradient" do let(:svg) do <<-SVG SVG end it "is stored in the document gradients table" do expect(document.gradients["flag"]).to eq element end it "returns correct gradient arguments for an element" do arguments = element.gradient_arguments(double(bounding_box: [100, 100, 200, 0])) expect(arguments).to eq( from: [150, 80], to: [100, 80], r1: 0, r2: Math.sqrt((0.8 * 100) ** 2 + (0.8 * 100) ** 2), stops: [[0, "ff0000"], [0.25, "ff0000"], [0.5, "ffffff"], [0.75, "0000ff"], [1, "0000ff"]], apply_transformations: true, ) end end describe "user space on use with linear gradient" do let(:svg) do <<-SVG SVG end it "returns correct gradient arguments for an element" do arguments = element.gradient_arguments(double) expect(arguments).to eq( from: [100.0, 100.0], to: [200.0, 0.0], stops: [[0, "ff0000"], [1, "0000ff"]], apply_transformations: true, ) end end describe "user space on use with radial gradient" do let(:svg) do <<-SVG SVG end it "returns correct gradient arguments for an element" do arguments = element.gradient_arguments(double) expect(arguments).to eq( from: [100.0, 100.0], to: [200.0, 0.0], r1: 0, r2: 150, stops: [[0, "ff0000"], [1, "0000ff"]], apply_transformations: true, ) end end context "when gradientTransform is specified" do let(:svg) do <<-SVG SVG end it "passes in the transform via the apply_transformations option" do arguments = element.gradient_arguments(double(bounding_box: [0, 0, 10, 10])) expect(arguments).to eq( from: [0, 0], to: [10, 10], stops: [[0, "ff0000"], [1, "0000ff"]], apply_transformations: [2, 0, 0, 2, 10, 0], ) end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/elements/line_spec.rb000066400000000000000000000027061402126170300234620ustar00rootroot00000000000000require 'spec_helper' RSpec.describe Prawn::SVG::Elements::Line do let(:document) { Prawn::SVG::Document.new(svg, [800, 600], {width: 800, height: 600}) } subject do Prawn::SVG::Elements::Line.new(document, document.root, [], fake_state) end context "with attributes specified" do let(:svg) { '' } it "renders the line" do subject.process expect(subject.base_calls).to eq [ ["stroke_color", ["000000"], {}, []], ["stroke", [], {}, [ ["move_to", [[5.0, 590.0]], {}, []], ["line_to", [[15.0, 580.0]], {}, []]] ] ] end end context "with no attributes nor stroke specified" do let(:svg) { '' } it "outlines a path from 0,0 to 0,0" do subject.process expect(subject.base_calls).to eq [ ["end_path", [], {}, [ ["move_to", [[0, 600]], {}, []], ["line_to", [[0, 600]], {}, []]] ] ] end end context "with a fill specified" do let(:svg) { '' } it "ignores the fill" do subject.process expect(subject.base_calls).to eq [ ["fill_color", ["0000ff"], {}, []], ["stroke_color", ["ff0000"], {}, []], ["stroke", [], {}, [ ["move_to", [[0, 600]], {}, []], ["line_to", [[15.0, 580.0]], {}, []]] ] ] end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/elements/marker_spec.rb000066400000000000000000000057141402126170300240160ustar00rootroot00000000000000require 'spec_helper' RSpec.describe Prawn::SVG::Elements::Marker do let(:svg) do <<-SVG SVG end let(:document) { Prawn::SVG::Document.new(svg, [800, 600], {width: 800, height: 600}) } let(:state) { Prawn::SVG::State.new } let(:line_element) do Prawn::SVG::Elements::Line.new(document, document.root.elements[2], [], state) end subject do Prawn::SVG::Elements::Marker.new(document, document.root.elements[1], [], state) end before do state.viewport_sizing = document.sizing end describe "#parse" do it "forces display none" do subject.parse expect(subject.properties.display).to eq 'none' end end describe "#apply_marker" do it "adds the line and its marker to the call stack" do subject.process line_element.process # We didn't use a marker-* attribute on the tag, that's # why the apply_marker method wasn't automatically called as part # of the line_element.process call above. subject.apply_marker(line_element, point: [10, 10], angle: 45) # This example follows the example in the SVG 1.1 documentation # in section 11.6.3. expect(line_element.base_calls).to eq [ ["stroke_color", ["000000"], {}, []], ["line_width", [100.0], {}, []], ["stroke", [], {}, [ ["move_to", [[0.0, 600.0]], {}, []], ["line_to", [[10.0, 590.0]], {}, []] ] ], ["save", [], {}, []], ["transformation_matrix", [1, 0, 0, 1, 10, -10], {}, []], ["rotate", [-45], {origin: [0, 600.0]}, [ ["transformation_matrix", [100.0, 0, 0, 100.0, 0, 0], {}, []], ["transformation_matrix", [1, 0, 0, 1, -0.0, 1.5], {}, []], ["rectangle", [[-0.5, 600.0], 4.0, 3.0], {}, []], ["clip", [], {}, []], ["transformation_matrix", [0.3, 0, 0, 0.3, 0, 0], {}, []], ["transparent", [1.0, 1.0], {}, [ ["stroke_color", ["000000"], {}, []], ["line_width", [100.0], {}, []], ["cap_style", [:butt], {}, []], ["undash", [], {}, []], ["save", [], {}, []], ["fill", [], {}, [ ["join_style", [:bevel], {}, []], ["move_to", [[0.0, 600.0]], {}, []], ["line_to", [[10.0, 595.0]], {}, []], ["line_to", [[0.0, 590.0]], {}, []], ["close_path", [], {}, []] ] ], ["restore", [], {}, []], ] ] ] ], ["restore", [], {}, []] ] end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/elements/path_spec.rb000066400000000000000000000204571402126170300234720ustar00rootroot00000000000000require 'spec_helper' describe Prawn::SVG::Elements::Path do let(:source) { double(name: "path", attributes: {}) } let(:state) { Prawn::SVG::State.new } let(:path) { Prawn::SVG::Elements::Path.new(nil, source, [], state) } before do allow(path).to receive(:attributes).and_return("d" => d) end describe "command parsing" do context "with a valid path" do let(:d) { "m12.34 -56.78 1 2M4 5 12-34 -.5.7+3 2.3e3 4e4 4e+4 L31,-2e-5L 6,7 Z ZZa50 50 0 100 100" } it "correctly parses" do calls = [] allow(path).to receive(:parse_path_command) {|*args| calls << args} path.parse expect(calls).to eq [ ["m", [[12.34, -56.78], [1, 2]]], ["M", [[4, 5], [12, -34], [-0.5, 0.7], [3, 2.3e3], [4e4, 4e4]]], ["L", [[31, -2e-5]]], ["L", [[6, 7]]], ["Z", []], ["Z", []], ["Z", []], ["a", [[50, 50, 0, 1, 0, 0, 100]]], ] end end context "with m and M commands" do let(:d) { "M 1,2 3,4 m 5,6 7,8" } it "treats subsequent points to m/M command as relative/absolute depending on command" do [ ["M", [[1,2],[3,4]]], ["L", [[3,4]]], ["m", [[5,6],[7,8]]], ["l", [[7,8]]] ].each do |args| expect(path).to receive(:parse_path_command).with(*args).and_call_original end path.parse end end context "with an empty path" do let(:d) { "" } it "correctly parses" do expect(path).not_to receive(:run_path_command) path.parse end end context "with a path with invalid characters" do let(:d) { "M 10 % 20" } it "raises" do expect { path.parse }.to raise_error(Prawn::SVG::Elements::Base::SkipElementError) end end context "with a path with numerical data before a command letter" do let(:d) { "M 10 % 20" } it "raises" do expect { path.parse }.to raise_error(Prawn::SVG::Elements::Base::SkipElementError) end end end context "when given an M path" do subject { path.parse; path.commands } context "with typical arguments" do let(:d) { "M 100 200 M 200 300 m 10 20" } it "issues a move command" do expect(subject).to eq [ Prawn::SVG::Elements::Path::Move.new([100.0, 200.0]), Prawn::SVG::Elements::Path::Move.new([200.0, 300.0]), Prawn::SVG::Elements::Path::Move.new([210.0, 320.0]), ] end end context "with only one argument" do let(:d) { "M 100 200 M 100" } it "bails out" do expect(subject).to eq [ Prawn::SVG::Elements::Path::Move.new([100.0, 200.0]) ] end end context "with no arguments" do let(:d) { "M 100 200 M" } it "bails out" do expect(subject).to eq [ Prawn::SVG::Elements::Path::Move.new([100.0, 200.0]) ] end end end context "when given an L path" do subject { path.parse; path.commands } context "with typical arguments" do let(:d) { "M 100 200 L 200 300 l 10 20" } it "issues a line command" do expect(subject).to eq [ Prawn::SVG::Elements::Path::Move.new([100.0, 200.0]), Prawn::SVG::Elements::Path::Line.new([200.0, 300.0]), Prawn::SVG::Elements::Path::Line.new([210.0, 320.0]), ] end end context "with only one argument" do let(:d) { "M 100 200 L 100" } it "bails out" do expect(subject).to eq [ Prawn::SVG::Elements::Path::Move.new([100.0, 200.0]) ] end end end context "when given a C path" do subject { path.parse; path.commands } context "with typical arguments" do let(:d) { "M 100 200 C 10 20 30 40 200 300" } it "issues a curve command" do expect(subject).to eq [ Prawn::SVG::Elements::Path::Move.new([100.0, 200.0]), Prawn::SVG::Elements::Path::Curve.new([200.0, 300.0], [10, 20], [30, 40]), ] end end context "with incomplete arguments" do let(:d) { "M 100 200 C 10 20 30 40 50" } it "bails out" do expect(subject).to eq [ Prawn::SVG::Elements::Path::Move.new([100.0, 200.0]) ] end end end context "when given an S path" do subject { path.parse; path.commands } context "with typical arguments" do let(:d) { "M 100 200 S 30 40 200 300" } it "issues a curve command" do expect(subject).to eq [ Prawn::SVG::Elements::Path::Move.new([100.0, 200.0]), Prawn::SVG::Elements::Path::Curve.new([200.0, 300.0], [100, 200], [30, 40]), ] end end context "with incomplete arguments" do let(:d) { "M 100 200 S 30 40 50" } it "bails out" do expect(subject).to eq [ Prawn::SVG::Elements::Path::Move.new([100.0, 200.0]) ] end end end context "when given a Q path" do subject { path.parse; path.commands } context "with typical arguments" do let(:d) { "M 0 0 Q 600 300 300 600" } it "issues a curve command" do expect(subject).to eq [ Prawn::SVG::Elements::Path::Move.new([0, 0]), Prawn::SVG::Elements::Path::Curve.new([300.0, 600.0], [400, 200], [500, 400]) ] end end context "with incomplete arguments" do let(:d) { "M 100 200 Q 30 40 50" } it "bails out" do expect(subject).to eq [ Prawn::SVG::Elements::Path::Move.new([100.0, 200.0]) ] end end end context "when given a T path" do subject { path.parse; path.commands } context "with typical arguments" do let(:d) { "M 0 0 T 300 600" } it "issues a curve command" do expect(subject).to eq [ Prawn::SVG::Elements::Path::Move.new([0, 0]), Prawn::SVG::Elements::Path::Curve.new([300.0, 600.0], [0, 0], [100, 200]) ] end end context "with incomplete arguments" do let(:d) { "M 100 200 T 30" } it "bails out" do expect(subject).to eq [ Prawn::SVG::Elements::Path::Move.new([100.0, 200.0]) ] end end end context "when given an A path" do subject { path.parse; path.commands } context "that is pretty normal" do let(:d) { "M 100 200 A 10 10 0 0 1 200 200" } it "uses bezier curves to approximate an arc path" do expect(subject).to eq [ Prawn::SVG::Elements::Path::Move.new([100.0, 200.0]), Prawn::SVG::Elements::Path::Curve.new([150.0, 150.0], [100.0, 172.57081148225683], [122.57081148225683, 150.0]), Prawn::SVG::Elements::Path::Curve.new([200.0, 200.0], [177.42918851774317, 150.0], [200.0, 172.57081148225683]) ] end end context "with an identical start and end point" do let(:d) { "M 100 200 A 30 30 0 0 1 100 200" } it "ignores the path" do expect(subject).to eq [ Prawn::SVG::Elements::Path::Move.new([100.0, 200.0]), ] end end context "with an rx of 0" do let(:d) { "M 100 200 A 0 10 0 0 1 200 200" } it "substitutes a line_to" do expect(subject).to eq [ Prawn::SVG::Elements::Path::Move.new([100.0, 200.0]), Prawn::SVG::Elements::Path::Line.new([200.0, 200.0]) ] end end context "with an ry of 0" do let(:d) { "M 100 200 A 10 0 0 0 1 200 200" } it "substitutes a line_to" do expect(subject).to eq [ Prawn::SVG::Elements::Path::Move.new([100.0, 200.0]), Prawn::SVG::Elements::Path::Line.new([200.0, 200.0]) ] end end context "with incomplete arguments" do let(:d) { "M 100 200 A 10 20 30 L 10 20" } it "bails out" do expect(subject).to eq [ Prawn::SVG::Elements::Path::Move.new([100.0, 200.0]) ] end end context "with highly-compressed flags" do let(:d) { "M100,100a50 50 0 100 100" } it "correctly parses them" do expect(subject).to eq [ Prawn::SVG::Elements::Path::Move.new([100.0, 100.0]), Prawn::SVG::Elements::Path::Curve.new([50.0, 150.0], [72.57081148225681, 100.0], [50.0, 122.57081148225681]), Prawn::SVG::Elements::Path::Curve.new([99.99999999999999, 200.0], [50.0, 177.42918851774317], [72.5708114822568, 200.0]) ] end end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/elements/polygon_spec.rb000066400000000000000000000024641402126170300242230ustar00rootroot00000000000000require 'spec_helper' RSpec.describe Prawn::SVG::Elements::Polygon do let(:document) { Prawn::SVG::Document.new(svg, [800, 600], {width: 800, height: 600}) } subject do Prawn::SVG::Elements::Polygon.new(document, document.root, [], Prawn::SVG::State.new) end context "with a valid points attribute" do let(:svg) { '' } it "renders the polygon" do subject.process expect(subject.base_calls).to eq [ ["fill", [], {}, [ ["move_to", [[10.0, 590.0]], {}, []], ["line_to", [[20.0, 580.0]], {}, []], ["line_to", [[30.0, 570.0]], {}, []], ["close_path", [], {}, []]] ] ] end end context "with a polygon that has an odd number of arguments" do let(:svg) { '' } it "ignores the last one" do subject.process expect(subject.base_calls).to eq [ ["fill", [], {}, [ ["move_to", [[10.0, 590.0]], {}, []], ["line_to", [[20.0, 580.0]], {}, []], ["close_path", [], {}, []]] ] ] end end context "with a polygon that has no arguments" do let(:svg) { '' } it "renders nothing" do subject.process expect(subject.base_calls).to eq [] end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/elements/polyline_spec.rb000066400000000000000000000023601402126170300243620ustar00rootroot00000000000000require 'spec_helper' RSpec.describe Prawn::SVG::Elements::Polyline do let(:document) { Prawn::SVG::Document.new(svg, [800, 600], {width: 800, height: 600}) } subject do Prawn::SVG::Elements::Polyline.new(document, document.root, [], Prawn::SVG::State.new) end context "with a valid points attribute" do let(:svg) { '' } it "renders the polyline" do subject.process expect(subject.base_calls).to eq [ ["fill", [], {}, [ ["move_to", [[10.0, 590.0]], {}, []], ["line_to", [[20.0, 580.0]], {}, []], ["line_to", [[30.0, 570.0]], {}, []]] ] ] end end context "with a polyline that has an odd number of arguments" do let(:svg) { '' } it "ignores the last one" do subject.process expect(subject.base_calls).to eq [ ["fill", [], {}, [ ["move_to", [[10.0, 590.0]], {}, []], ["line_to", [[20.0, 580.0]], {}, []]] ] ] end end context "with a polyline that has no arguments" do let(:svg) { '' } it "renders nothing" do subject.process expect(subject.base_calls).to eq [] end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/elements/text_spec.rb000066400000000000000000000221551402126170300235170ustar00rootroot00000000000000require File.dirname(__FILE__) + '/../../../spec_helper' describe Prawn::SVG::Elements::Text do let(:document) { Prawn::SVG::Document.new(svg, [800, 600], {}, font_registry: Prawn::SVG::FontRegistry.new("Helvetica" => {:normal => nil}, "Courier" => {normal: nil}, 'Times-Roman' => {normal: nil})) } let(:element) { Prawn::SVG::Elements::Text.new(document, document.root, [], fake_state) } let(:default_style) { {:size=>16, :style=>:normal, :text_anchor=>'start', :at=>[:relative, :relative], :offset=>[0,0]} } describe "xml:space preserve" do let(:svg) { %(some\n\t text) } context "when xml:space is preserve" do let(:attributes) { ' xml:space="preserve"' } it "converts newlines and tabs to spaces, and preserves spaces" do element.process expect(flatten_calls(element.calls)).to include ["draw_text", ["some text"], {:size=>16, :style=>:normal, :text_anchor=>'start', :at=>[:relative, :relative], :offset=>[0,0]}] end end context "when xml:space is unspecified" do let(:attributes) { '' } it "strips space" do element.process expect(flatten_calls(element.calls)).to include ["draw_text", ["some text"], {:size=>16, :style=>:normal, :text_anchor=>'start', :at=>[:relative, :relative], :offset=>[0,0]}] end end end describe "conventional whitespace handling" do let(:svg) do <<-SVG Some text here More text Even more leading goodness ok SVG end it "correctly apportions white space between the tags" do element.process calls = element.calls.flatten expect(calls).to include "Some text here " expect(calls).to include "More text" expect(calls).to include "Even more" expect(calls).to include " leading goodness " expect(calls).to include "ok" end end describe "when text-anchor is specified" do let(:svg) { 'Text' } let(:element) { Prawn::SVG::Elements::Container.new(document, document.root, [], fake_state) } it "should inherit text-anchor from parent element" do element.process expect(element.calls.flatten).to include(:size => 12.0, :style => :normal, :text_anchor => "middle", :at => [50.0, 586.0], :offset => [0,0]) end end describe "letter-spacing" do let(:svg) { 'spaced' } it "calls character_spacing with the requested size" do element.process expect(element.base_calls).to eq [ ["text_group", [], {}, [ ["font", ["Helvetica"], {style: :normal}, []], ["character_spacing", [5.0], {}, [ ["draw_text", ["spaced"], default_style, []] ]] ]] ] end end describe "underline" do let(:svg) { 'underlined' } it "marks the element to be underlined" do element.process expect(element.base_calls).to eq [ ["text_group", [], {},[ ["font", ["Helvetica"], {:style=>:normal}, []], ["draw_text", ["underlined"], default_style.merge(decoration: 'underline'), []] ]] ] end end describe "fill/stroke modes" do context "with a stroke and no fill" do let(:svg) { 'stroked' } it "calls text_rendering_mode with the requested options" do element.process expect(element.base_calls).to eq [ ["text_group", [], {}, [ ["stroke_color", ["ff0000"], {}, []], ["font", ["Helvetica"], {style: :normal}, []], ["text_rendering_mode", [:stroke], {}, [ ["draw_text", ["stroked"], default_style, []] ]] ]] ] end end context "with a mixture of everything" do let(:svg) { 'stroked bothneither' } it "calls text_rendering_mode with the requested options" do element.process expect(element.base_calls).to eq [ ["text_group", [], {}, [ ["stroke_color", ["ff0000"], {}, []], ["font", ["Helvetica"], {style: :normal}, []], ["text_rendering_mode", [:stroke], {}, [ ["draw_text", ["stroked "], default_style, []], ["save", [], {}, []], ["fill_color", ["000000"], {}, []], ["font", ["Helvetica"], {style: :normal}, []], ["text_rendering_mode", [:fill_stroke], {}, [ ["draw_text", ["both"], default_style, []] ]], ["restore", [], {}, []], ["save", [], {}, []], ["font", ["Helvetica"], {style: :normal}, []], ["text_rendering_mode", [:invisible], {}, [ ["draw_text", ["neither"], default_style, []] ]], ["restore", [], {}, []], ]] ]] ] end end end describe "font finding" do context "with a font that exists" do let(:svg) { 'hello' } it "finds the font and uses it" do element.process expect(flatten_calls(element.base_calls)).to include ['font', ['Courier'], {style: :normal}] end end context "with a font that doesn't exist" do let(:svg) { 'hello' } it "uses the fallback font" do element.process expect(flatten_calls(element.base_calls)).to include ['font', ['Times-Roman'], {style: :normal}] end context "when there is no fallback font" do before { document.font_registry.installed_fonts.delete("Times-Roman") } it "doesn't call the font method and logs a warning" do element.process expect(element.base_calls.flatten).to_not include 'font' expect(document.warnings.first).to include "is not a known font" end end end end describe "" do let(:svg) { 'my reference text' } let(:element) { Prawn::SVG::Elements::Root.new(document, document.root, [], fake_state) } it "references the text" do element.process expect(flatten_calls(element.base_calls)[9..11]).to eq [ ["fill_color", ["ff0000"], {}], ["font", ["Helvetica"], {:style=>:normal}], ["draw_text", ["my reference text"], {:size=>16, :style=>:normal, :text_anchor=>"start", :at=>[10.0, :relative], :offset=>[0,0]}], ] end end describe "dx and dy attributes" do let(:svg) { 'Hi there, this is a good test' } it "correctly calculates the positions of the text" do element.process expect(flatten_calls(element.base_calls)).to eq [ ["text_group", [], {}], ["font", ["Helvetica"], {:style=>:normal}], ["draw_text", ["H"], {:size=>16, :style=>:normal, :text_anchor=>"start", :at=>[10.0, :relative], :offset=>[30.0, 2.0]}], ["draw_text", ["i"], {:size=>16, :style=>:normal, :text_anchor=>"start", :at=>[20.0, :relative], :offset=>[50.0, 0]}], ["draw_text", [" there, this is a good test"], {:size=>16, :style=>:normal, :text_anchor=>"start", :at=>[:relative, :relative], :offset=>[80.0, 0]}] ] end end describe "rotate attribute" do let(:svg) { 'Hi this ok!' } it "correctly calculates the positions of the text" do element.process expect(flatten_calls(element.base_calls)).to eq [ ["text_group", [], {}], ["font", ["Helvetica"], {:style=>:normal}], ["draw_text", ["H"], {:size=>16, :style=>:normal, :text_anchor=>"start", :at=>[:relative, :relative], :offset=>[0, 0], :rotate=>-10.0}], ["draw_text", ["i"], {:size=>16, :style=>:normal, :text_anchor=>"start", :at=>[:relative, :relative], :offset=>[0, 0], :rotate=>-20.0}], ["draw_text", [" "], {:size=>16, :style=>:normal, :text_anchor=>"start", :at=>[:relative, :relative], :offset=>[0, 0], :rotate=>-30.0}], ["save", [], {}], ["font", ["Helvetica"], {:style=>:normal}], ["draw_text", ["this"], {:size=>16, :style=>:normal, :text_anchor=>"start", :at=>[:relative, :relative], :offset=>[0, 0]}], ["restore", [], {}], ["draw_text", [" "], {:size=>16, :style=>:normal, :text_anchor=>"start", :at=>[:relative, :relative], :offset=>[0, 0], :rotate=>-80.0}], ["draw_text", ["o"], {:size=>16, :style=>:normal, :text_anchor=>"start", :at=>[:relative, :relative], :offset=>[0, 0], :rotate=>-90.0}], ["draw_text", ["k"], {:size=>16, :style=>:normal, :text_anchor=>"start", :at=>[:relative, :relative], :offset=>[0, 0], :rotate=>-100.0}], ["draw_text", ["!"], {:size=>16, :style=>:normal, :text_anchor=>"start", :at=>[:relative, :relative], :offset=>[0, 0], :rotate=>-100.0}] ] end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/font_registry_spec.rb000066400000000000000000000070431402126170300236140ustar00rootroot00000000000000require 'spec_helper' RSpec.describe Prawn::SVG::FontRegistry do describe "#load" do let(:pdf) { Prawn::Document.new } let(:font_registry) { Prawn::SVG::FontRegistry.new(pdf.font_families) } it "matches a built in font" do font_registry.load("blah, 'courier', nothing").name.should == 'Courier' end it "matches a default font" do font_registry.load("serif").name.should == 'Times-Roman' font_registry.load("blah, serif").name.should == 'Times-Roman' font_registry.load("blah, serif , test").name.should == 'Times-Roman' end if Prawn::SVG::FontRegistry.new({}).installed_fonts["Verdana"] it "matches a font installed on the system" do font_registry.load("verdana, sans-serif").name.should == 'Verdana' font_registry.load("VERDANA, sans-serif").name.should == 'Verdana' font_registry.load("something, \"Times New Roman\", serif").name.should == "Times New Roman" font_registry.load("something, Times New Roman, serif").name.should == "Times New Roman" end else it "not running font test because we couldn't find Verdana installed on the system" end it "returns nil if it can't find any such font" do font_registry.load("blah, thing").should be_nil font_registry.load("").should be_nil end end describe "#installed_fonts" do let(:ttf) { instance_double(Prawn::SVG::TTF, family: "Awesome Font", subfamily: "Italic") } let(:ttf2) { instance_double(Prawn::SVG::TTF, family: "Awesome Font", subfamily: "Regular") } before { Prawn::SVG::FontRegistry.external_font_families.clear } let(:pdf) do doc = Prawn::Document.new doc.font_families.update({ "Awesome Font" => {:italic => "second.ttf", :normal => "file.ttf"} }) doc end let(:font_registry) { Prawn::SVG::FontRegistry.new(pdf.font_families) } it "does not override existing entries in pdf when loading external fonts" do expect(Prawn::SVG::FontRegistry).to receive(:font_path).and_return(["x"]) expect(Dir).to receive(:[]).with("x/**/*").and_return(["file.ttf", "second.ttf"]) expect(Prawn::SVG::TTF).to receive(:new).with("file.ttf").and_return(ttf) expect(Prawn::SVG::TTF).to receive(:new).with("second.ttf").and_return(ttf2) expect(File).to receive(:file?).at_least(:once).and_return(true) Prawn::SVG::FontRegistry.load_external_fonts font_registry.installed_fonts existing_font = font_registry.installed_fonts["Awesome Font"] expect(existing_font).to eq(:italic => "second.ttf",:normal => "file.ttf") end end describe "::load_external_fonts" do let(:ttf) { instance_double(Prawn::SVG::TTF, family: "Awesome Font", subfamily: "Italic") } let(:ttf2) { instance_double(Prawn::SVG::TTF, family: "Awesome Font", subfamily: "Regular") } before { Prawn::SVG::FontRegistry.external_font_families.clear } it "scans the font path and loads in some fonts" do expect(Prawn::SVG::FontRegistry).to receive(:font_path).and_return(["x"]) expect(Dir).to receive(:[]).with("x/**/*").and_return(["file.ttf", "second.ttf"]) expect(Prawn::SVG::TTF).to receive(:new).with("file.ttf").and_return(ttf) expect(Prawn::SVG::TTF).to receive(:new).with("second.ttf").and_return(ttf2) expect(File).to receive(:file?).at_least(:once).and_return(true) Prawn::SVG::FontRegistry.load_external_fonts result = Prawn::SVG::FontRegistry.external_font_families expect(result).to eq("Awesome Font" => {:italic => "file.ttf", :normal => "second.ttf"}) end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/font_spec.rb000066400000000000000000000012231402126170300216560ustar00rootroot00000000000000require File.dirname(__FILE__) + '/../../spec_helper' describe Prawn::SVG::Font do describe "#initialize" do it "maps generic font name to built-in font" do font_registry = Prawn::SVG::FontRegistry.new({}) font = Prawn::SVG::Font.new('sans-serif', :normal, :normal, font_registry: font_registry) font.name.should == 'Helvetica' end it "preserves generic font name if mapped" do font_registry = Prawn::SVG::FontRegistry.new('sans-serif' => { normal: 'Times-Roman' }) font = Prawn::SVG::Font.new('sans-serif', :normal, :normal, font_registry: font_registry) font.name.should == 'sans-serif' end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/interface_spec.rb000066400000000000000000000110511402126170300226500ustar00rootroot00000000000000require 'spec_helper' describe Prawn::SVG::Interface do let(:bounds) { double(width: 800, height: 600, absolute_left: 0, absolute_top: 0) } let(:prawn) { instance_double(Prawn::Document, font_families: {}, bounds: bounds, cursor: 600) } let(:svg) { '' } describe "#initialize" do describe "invalid option detection" do it "rejects invalid options when debug is on" do allow(Prawn).to receive(:debug).and_return(true) expect { Prawn::SVG::Interface.new(svg, prawn, :invalid => "option") }.to raise_error(Prawn::Errors::UnknownOption) end it "does nothing if an invalid option is given and debug is off" do Prawn::SVG::Interface.new(svg, prawn, :invalid => "option") end end end describe "#draw" do context "when the sizing object indicates the sizes are invalid" do let(:interface) { Prawn::SVG::Interface.new('', prawn, {}) } it "doesn't draw anything and adds a warning" do interface.draw expect(interface.document.warnings).to eq ["Zero or negative sizing data means this SVG cannot be rendered"] end end describe "rewrites" do before do [:save_font, :bounding_box].each { |message| allow(prawn).to receive(message).and_yield } allow(prawn).to receive_messages([:move_to, :line_to, :close_path, :fill_color, :stroke_color, :transformation_matrix, :restore_graphics_state]) allow(prawn).to receive(:save_graphics_state) { |&block| block.call if block } end context "when fill_and_stroke is issued" do context "and fill rule is not set" do let(:interface) { Prawn::SVG::Interface.new('', prawn, {}) } it "adds content 'B'" do expect(prawn).to receive(:rectangle).with([0, 100], 10, 10) expect(prawn).to receive(:add_content).with("W n") expect(prawn).to receive(:add_content).with("B") interface.draw end end context "and fill rule is evenodd" do let(:interface) { Prawn::SVG::Interface.new('', prawn, {}) } it "adds content 'B*'" do expect(prawn).to receive(:rectangle).with([0, 100], 10, 10) expect(prawn).to receive(:add_content).with("W n") expect(prawn).to receive(:add_content).with("B*") interface.draw end end end end end describe "#position" do subject { interface.position } context "when options[:at] supplied" do let(:interface) { Prawn::SVG::Interface.new(svg, prawn, at: [1, 2], position: :left) } it "returns options[:at]" do expect(subject).to eq [1, 2] end end context "when only a position is supplied" do let(:interface) { Prawn::SVG::Interface.new(svg, prawn, position: position) } context "(:left)" do let(:position) { :left } it { is_expected.to eq [0, 600] } end context "(:center)" do let(:position) { :center } it { is_expected.to eq [275, 600] } end context "(:right)" do let(:position) { :right } it { is_expected.to eq [550, 600] } end context "a number" do let(:position) { 25.5 } it { is_expected.to eq [25.5, 600] } end end context "when a vposition is supplied" do let(:interface) { Prawn::SVG::Interface.new(svg, prawn, vposition: vposition) } context "(:top)" do let(:vposition) { :top } it { is_expected.to eq [0, 600] } end context "(:center)" do let(:vposition) { :center } it { is_expected.to eq [0, 350] } end context "(:bottom)" do let(:vposition) { :bottom } it { is_expected.to eq [0, 100] } end context "a number" do let(:vposition) { 25.5 } it { is_expected.to eq [0, 600 - 25.5] } end end end describe "#sizing and #resize" do let(:interface) { Prawn::SVG::Interface.new(svg, prawn, {}) } it "allows the advanced user to resize the SVG after learning about its dimensions" do expect(interface.sizing.output_width).to eq 250 expect(interface.sizing.output_height).to eq 100 interface.resize(width: 500) expect(interface.sizing.output_width).to eq 500 expect(interface.sizing.output_height).to eq 200 end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/loaders/000077500000000000000000000000001402126170300210045ustar00rootroot00000000000000ruby-prawn-svg-0.32.0/spec/prawn/svg/loaders/data_spec.rb000066400000000000000000000027371402126170300232650ustar00rootroot00000000000000require 'spec_helper' RSpec.describe Prawn::SVG::Loaders::Data do let(:uri) { URI(url) } subject { Prawn::SVG::Loaders::Data.new.from_url(url) } context "with a valid image/png data URL" do let(:url) { "data:image/png;base64,aGVsbG8=" } it "loads the data" do expect(subject).to eq "hello" end end context "with a valid image/jpeg data URL" do let(:url) { "data:image/jpeg;base64,aGVsbG8=" } it "loads the data" do expect(subject).to eq "hello" end end context "with a data URL that has extra metadata" do let(:url) { "data:image/png;base64;metadata;here,aGVsbG8=" } it "loads the data" do expect(subject).to eq "hello" end end context "with a data URL that's uppercase" do let(:url) { "DATA:IMAGE/PNG;BASE64;METADATA;HERE,aGVsbG8=" } it "loads the data" do expect(subject).to eq "hello" end end context "with a URL that's not a data scheme" do let(:url) { "http://some.host" } it "returns nil" do expect(subject).to be nil end end context "with a data URL that's not an image" do let(:url) { "data:application/pdf;base64,aGVsbG8=" } it "raises" do expect { subject }.to raise_error Prawn::SVG::UrlLoader::Error, /image/ end end context "with a data URL that's not base64 encoded" do let(:url) { "data:image/png;base32,agvsbg" } it "raises" do expect { subject }.to raise_error Prawn::SVG::UrlLoader::Error, /base64/ end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/loaders/file_spec.rb000066400000000000000000000077611402126170300232750ustar00rootroot00000000000000require 'spec_helper' RSpec.describe Prawn::SVG::Loaders::File do let(:root_path) { "." } let(:fake_root_path) { "/some" } let(:file_loader) { Prawn::SVG::Loaders::File.new(root_path) } subject { file_loader.from_url(url) } context "when an invalid path is supplied" do let(:root_path) { "/does/not/exist" } it "raises with an ArgumentError" do expect { subject }.to raise_error ArgumentError, /is not a directory/ end end context "when a relative path is supplied" do let(:url) { "relative/./path" } it "loads the file" do expect(File).to receive(:expand_path).with(".").and_return(fake_root_path) expect(File).to receive(:expand_path).with("relative/./path", fake_root_path).and_return("#{fake_root_path}/relative/path") expect(Dir).to receive(:exist?).with(fake_root_path).and_return(true) expect(File).to receive(:exist?).with("#{fake_root_path}/relative/path").and_return(true) expect(IO).to receive(:binread).with("#{fake_root_path}/relative/path").and_return("data") expect(subject).to eq 'data' end end context "when an absolute path without file scheme is supplied" do let(:url) { "/some/absolute/./path" } it "loads the file" do expect(File).to receive(:expand_path).with(".").and_return(fake_root_path) expect(File).to receive(:expand_path).with(url, fake_root_path).and_return("/some/absolute/path") expect(Dir).to receive(:exist?).with(fake_root_path).and_return(true) expect(File).to receive(:exist?).with("/some/absolute/path").and_return(true) expect(IO).to receive(:binread).with("/some/absolute/path").and_return("data") expect(subject).to eq 'data' end end context "when an absolute path with file scheme is supplied" do let(:url) { "file:///some/absolute/./path%20name" } it "loads the file" do expect(File).to receive(:expand_path).with(".").and_return(fake_root_path) expect(File).to receive(:expand_path).with("/some/absolute/./path name", fake_root_path).and_return("/some/absolute/path name") expect(Dir).to receive(:exist?).with(fake_root_path).and_return(true) expect(File).to receive(:exist?).with("/some/absolute/path name").and_return(true) expect(IO).to receive(:binread).with("/some/absolute/path name").and_return("data") expect(subject).to eq 'data' end end context "when a path outside of our root is specified" do let(:url) { "/other/absolute/./path" } it "raises" do expect(File).to receive(:expand_path).with(".").and_return(fake_root_path) expect(File).to receive(:expand_path).with(url, fake_root_path).and_return("/other/absolute/path") expect(Dir).to receive(:exist?).with(fake_root_path).and_return(true) expect { subject }.to raise_error Prawn::SVG::UrlLoader::Error, /not inside the root path/ end end context "when a file: url with a host is specified" do let(:url) { "file://somewhere/somefile" } it "raises" do expect(File).to receive(:expand_path).with(".").and_return(fake_root_path) expect(Dir).to receive(:exist?).with(fake_root_path).and_return(true) expect { subject }.to raise_error Prawn::SVG::UrlLoader::Error, /with a host/ end end context "when we're running on Windows" do let(:url) { "file:///c:/path/to/file.png" } let(:fake_root_path) { "c:/full" } it "automatically fixes up URI's misparsing of Windows file paths and loads the file" do expect(File).to receive(:expand_path).with(".").and_return(fake_root_path) expect(File).to receive(:expand_path).with("c:/path/to/file.png", fake_root_path).and_return("c:/full/path/to/file.png") expect(Dir).to receive(:exist?).with(fake_root_path).and_return(true) expect(File).to receive(:exist?).with("c:/full/path/to/file.png").and_return(true) expect(IO).to receive(:binread).with("c:/full/path/to/file.png").and_return("data") allow(file_loader).to receive(:windows?).and_return true expect(subject).to eq 'data' end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/loaders/web_spec.rb000066400000000000000000000017471402126170300231310ustar00rootroot00000000000000require 'spec_helper' RSpec.describe Prawn::SVG::Loaders::Web do let(:url) { "http://hello.there/path" } let(:uri) { URI(url) } subject { Prawn::SVG::Loaders::Web.new.from_url(url) } it "loads an HTTP URL" do expect(Net::HTTP).to receive(:get).with(uri).and_return("hello!") expect(subject).to eq "hello!" end context "with an https URL" do let(:url) { "https://hello.there/path"} it "loads the HTTPS URL" do expect(Net::HTTP).to receive(:get).with(uri).and_return("hello!") expect(subject).to eq "hello!" end end context "when the HTTP call raises" do it "re-raises the error as UrlLoader errors" do expect(Net::HTTP).to receive(:get).with(uri).and_raise(SocketError, "argh") expect { subject }.to raise_error Prawn::SVG::UrlLoader::Error, 'argh' end end context "with a non-http, non-https URL" do let(:url) { "mailto:someone@something" } it "returns nil" do expect(subject).to be nil end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/pathable_spec.rb000066400000000000000000000051351402126170300224760ustar00rootroot00000000000000require 'spec_helper' RSpec.describe Prawn::SVG::Pathable do class FakeElement < Prawn::SVG::Elements::Base include Prawn::SVG::Pathable def initialize(*args) super @properties = Struct.new(:marker_start, :marker_mid, :marker_end).new end public :apply_commands public :apply_markers def commands @commands ||= [ Prawn::SVG::Pathable::Move.new([10, 10]), Prawn::SVG::Pathable::Line.new([20, 20]), Prawn::SVG::Pathable::Curve.new([30, 30], [25, 20], [25, 25]), Prawn::SVG::Pathable::Close.new([10, 10]) ] end end let(:document) { Prawn::SVG::Document.new("", [800, 600], {width: 800, height: 600}) } let(:state) { Prawn::SVG::State.new } subject do FakeElement.new(document, document.root, [], state) end describe "#bounding_box" do it "determines the bounding box using the translated commands" do expect(subject.bounding_box).to eq [10, 590, 30, 570] end end describe "#apply_commands" do it "applies the commands to the call stack" do subject.apply_commands expect(subject.base_calls).to eq [ ["move_to", [[10.0, 590.0]], {}, []], ["line_to", [[20.0, 580.0]], {}, []], ["curve_to", [[30.0, 570.0]], {bounds: [[25.0, 580.0], [25.0, 575.0]]}, []], ["close_path", [], {}, []] ] end end describe "#apply_markers" do let(:marker) { instance_double(Prawn::SVG::Elements::Marker, name: "marker") } before do document.elements_by_id["triangle"] = marker end context "with marker-start attribute specified" do before do subject.properties.marker_start = "url(#triangle)" end it "calls apply_marker on the marker" do expect(marker).to receive(:apply_marker).with(subject, point: [10, 10], angle: 45) subject.apply_markers end end context "with marker-mid attribute specified" do before do subject.properties.marker_mid = "url(#triangle)" end it "calls apply_marker on the marker" do expect(marker).to receive(:apply_marker).with(subject, point: [20, 20], angle: 45) expect(marker).to receive(:apply_marker).with(subject, point: [30, 30], angle: -45) subject.apply_markers end end context "with marker-end attribute specified" do before do subject.properties.marker_end = "url(#triangle)" end it "calls apply_marker on the marker" do expect(marker).to receive(:apply_marker).with(subject, point: [10, 10], angle: -45) subject.apply_markers end end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/properties_spec.rb000066400000000000000000000124761402126170300231200ustar00rootroot00000000000000require 'spec_helper' RSpec.describe Prawn::SVG::Properties do subject { Prawn::SVG::Properties.new } describe "#load_default_stylesheet" do it "loads in the defaults and returns self" do expect(subject.load_default_stylesheet).to eq subject expect(subject.font_family).to eq 'sans-serif' end end describe "#set" do it "sets a property" do result = subject.set('color', 'red') expect(result).to be expect(subject.color).to eq 'red' end it "handles property names that are not lower case" do result = subject.set('COLor', 'red') expect(result).to be expect(subject.color).to eq 'red' end it "right-cases and strips keywords" do subject.set('stroke-linecap', ' Round ') expect(subject.stroke_linecap).to eq 'round' end it "doesn't right-case values that aren't recognised as keywords" do subject.set('color', 'Red') expect(subject.color).to eq 'Red' end it "sets a 'keyword restricted' property to its default if the value doesn't match a keyword" do subject.set('stroke-linecap', 'invalid') expect(subject.stroke_linecap).to eq 'butt' end end describe "#load_hash" do it "uses #set to load in a hash of properties" do subject.load_hash("stroke" => "blue", "fill" => "green", 'stroke-linecap' => "Round") expect(subject.stroke).to eq 'blue' expect(subject.fill).to eq 'green' expect(subject.stroke_linecap).to eq 'round' end end describe "#compute_properties" do let(:other) { Prawn::SVG::Properties.new } it "auto-inherits inheritable properties when the property is not supplied" do subject.set('color', 'green') subject.compute_properties(other) expect(subject.color).to eq 'green' end it "doesn't auto-inherit non-inheritable properties" do subject.set('display', 'none') subject.compute_properties(other) expect(subject.display).to eq 'inline' end it "inherits non-inheritable properties when specifically asked to" do subject.set('display', 'none') other.set('display', 'inherit') subject.compute_properties(other) expect(subject.display).to eq 'none' end it "uses the new property value" do subject.set('color', 'green') other.set('color', 'red') subject.compute_properties(other) expect(subject.color).to eq 'red' end describe "font size" do before do subject.font_size = "15" other.font_size = font_size end context "when given a % as a font-size" do let(:font_size) { "120%" } it "calculates the new font size" do subject.compute_properties(other) expect(subject.font_size).to eq "18.0" end end context "when given 'larger' as a font-size" do let(:font_size) { "larger" } it "calculates the new font size" do subject.compute_properties(other) expect(subject.font_size).to eq "19.0" end end context "when given 'smaller' as a font-size" do let(:font_size) { "smaller" } it "calculates the new font size" do subject.compute_properties(other) expect(subject.font_size).to eq "11.0" end end context "when given a value in 'em' as a font-size" do let(:font_size) { "2.5em" } it "calculates the new font size" do subject.compute_properties(other) expect(subject.font_size).to eq "37.5" end end context "when given a value in 'rem' as a font-size" do let(:font_size) { "2.5rem" } it "calculates the new font size" do subject.compute_properties(other) expect(subject.font_size).to eq "40.0" end end context "when given a value in 'px' as a font-size" do let(:font_size) { "19.5px" } it "uses the font size specified" do subject.compute_properties(other) expect(subject.font_size).to eq "19.5" end end context "when given a value in 'pt' as a font-size" do let(:font_size) { "19.5pt" } it "uses the font size specified" do subject.compute_properties(other) expect(subject.font_size).to eq "19.5" end end context "when given a value without units as a font-size" do let(:font_size) { "19.5" } it "uses the font size specified" do subject.compute_properties(other) expect(subject.font_size).to eq "19.5" end end context "when given the keyword 'inherit' as a font-size" do let(:font_size) { "inherit" } it "uses the font size specified by the parent" do subject.compute_properties(other) expect(subject.font_size).to eq "15" end end end end describe "#numerical_font_size" do context "when the font size is a number" do before { subject.font_size = "16.5" } it "returns the number as a float" do expect(subject.numerical_font_size).to eq 16.5 end end context "when the font size is one of the keyword size specifiers" do before { subject.font_size = "x-large" } it "returns the font size number corresponding with the keyword" do expect(subject.numerical_font_size).to eq 24 end end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/transform_parser_spec.rb000066400000000000000000000045351402126170300243100ustar00rootroot00000000000000require 'spec_helper' RSpec.describe Prawn::SVG::TransformParser do class Test include Prawn::SVG::Calculators::Pixels include Prawn::SVG::TransformParser State = Struct.new(:viewport_sizing) Properties = Struct.new(:numerical_font_size) Document = Struct.new(:sizing) def document Document.new(_sizing) end def state State.new(_sizing) end def computed_properties Properties.new(14) end def _sizing Prawn::SVG::Calculators::DocumentSizing.new([1000, 800]) end end subject { Test.new.parse_transform_attribute(transform) } context "with no transform" do let(:transform) { '' } it { is_expected.to eq [1, 0, 0, 1, 0, 0] } end context "with translate" do let(:transform) { 'translate(10 20)' } it { is_expected.to eq [1, 0, 0, 1, 10, -20] } end context "with single argument translate" do let(:transform) { 'translate(10)' } it { is_expected.to eq [1, 0, 0, 1, 10, 0] } end context "with translateX" do let(:transform) { 'translateX(10)' } it { is_expected.to eq [1, 0, 0, 1, 10, 0] } end context "with translateY" do let(:transform) { 'translateY(10)' } it { is_expected.to eq [1, 0, 0, 1, 0, -10] } end let(:sin30) { Math.sin(30 * Math::PI / 180.0) } let(:cos30) { Math.cos(30 * Math::PI / 180.0) } let(:tan30) { Math.tan(30 * Math::PI / 180.0) } context "with single argument rotate" do let(:transform) { 'rotate(30)' } it { is_expected.to eq [cos30, -sin30, sin30, cos30, 0, 0] } end context "with triple argument rotate" do let(:transform) { 'rotate(30 100 200)' } it { is_expected.to eq [cos30, -sin30, sin30, cos30, 113.39745962155611, 23.205080756887753] } end context "with scale" do let(:transform) { 'scale(1.5)' } it { is_expected.to eq [1.5, 0, 0, 1.5, 0, 0] } end context "with skewX" do let(:transform) { 'skewX(30)' } it { is_expected.to eq [1, 0, -tan30, 1, 0, 0] } end context "with skewY" do let(:transform) { 'skewY(30)' } it { is_expected.to eq [1, -tan30, 0, 1, 0, 0] } end context "with matrix" do let(:transform) { 'matrix(1 2 3 4 5 6)' } it { is_expected.to eq [1, -2, -3, 4, 5, -6] } end context "with multiple" do let(:transform) { 'scale(2) translate(7) scale(3)' } it { is_expected.to eq [6, 0, 0, 6, 14, 0] } end end ruby-prawn-svg-0.32.0/spec/prawn/svg/ttf_spec.rb000066400000000000000000000015431402126170300215120ustar00rootroot00000000000000require 'spec_helper' RSpec.describe Prawn::SVG::TTF do subject { Prawn::SVG::TTF.new(filename) } context "with a truetype font" do let(:filename) { "#{File.dirname(__FILE__)}/../../sample_ttf/OpenSans-SemiboldItalic.ttf" } it "gets the English family and subfamily from the font file" do expect(subject.family).to eq 'Open Sans' expect(subject.subfamily).to eq 'Semibold Italic' end end context "with a file that isn't a TTF" do let(:filename) { __FILE__ } it "has a nil family and subfamily" do expect(subject.family).to be nil expect(subject.subfamily).to be nil end end context "with a file that doesn't exist" do let(:filename) { "does_not_exist" } it "has a nil family and subfamily" do expect(subject.family).to be nil expect(subject.subfamily).to be nil end end end ruby-prawn-svg-0.32.0/spec/prawn/svg/url_loader_spec.rb000066400000000000000000000074571402126170300230570ustar00rootroot00000000000000require 'spec_helper' describe Prawn::SVG::UrlLoader do let(:enable_cache) { true } let(:enable_web) { true } let(:enable_file) { "." } let(:loader) { Prawn::SVG::UrlLoader.new(enable_cache: enable_cache, enable_web: enable_web, enable_file_with_root: enable_file) } describe "#initialize" do it "sets options" do expect(loader.enable_cache).to be true end end describe "#load" do let(:url) { "http://hello/there" } let(:data_loader) { instance_double(Prawn::SVG::Loaders::Data) } let(:web_loader) { instance_double(Prawn::SVG::Loaders::Web) } let(:file_loader) { instance_double(Prawn::SVG::Loaders::File) } before do allow(Prawn::SVG::Loaders::Data).to receive(:new).and_return(data_loader) allow(Prawn::SVG::Loaders::Web).to receive(:new).and_return(web_loader) allow(Prawn::SVG::Loaders::File).to receive(:new).with(enable_file).and_return(file_loader) end subject { loader.load(url) } it "calls the Data loader and returns its output if successful" do expect(data_loader).to receive(:from_url).with(url).and_return("data") expect(web_loader).not_to receive(:from_url) expect(subject).to eq 'data' end it "calls the Web loader if the Data loader returns nothing, and returns its output if successful" do expect(data_loader).to receive(:from_url).with(url) expect(web_loader).to receive(:from_url).with(url).and_return("data") expect(subject).to eq 'data' end it "calls the File loader if the Data and Web loaders return nothing, and returns its output if successful" do expect(data_loader).to receive(:from_url).with(url) expect(web_loader).to receive(:from_url).with(url) expect(file_loader).to receive(:from_url).with(url).and_return("data") expect(subject).to eq 'data' end it "raises if none of the loaders return any data" do expect(data_loader).to receive(:from_url).with(url) expect(web_loader).to receive(:from_url).with(url) expect(file_loader).to receive(:from_url).with(url) expect { subject }.to raise_error(Prawn::SVG::UrlLoader::Error, /No handler available/) end context "when caching is enabled" do it "caches the result" do expect(data_loader).to receive(:from_url).with(url).and_return("data") expect(subject).to eq 'data' expect(loader.retrieve_from_cache(url)).to eq 'data' end end context "when caching is disabled" do let(:enable_cache) { false } it "does not cache the result" do expect(data_loader).to receive(:from_url).with(url).and_return("data") expect(subject).to eq 'data' expect(loader.retrieve_from_cache(url)).to be nil end end context "when the cache is populated" do before { loader.add_to_cache(url, 'data') } it "returns the cached value without calling a loader" do expect(data_loader).not_to receive(:from_url) expect(web_loader).not_to receive(:from_url) expect(subject).to eq 'data' end end context "when web requests are disabled" do let(:enable_web) { false } it "doesn't use the web loader" do expect(data_loader).to receive(:from_url) expect(web_loader).not_to receive(:from_url) expect(file_loader).to receive(:from_url) expect { subject }.to raise_error(Prawn::SVG::UrlLoader::Error, /No handler available/) end end context "when file requests are disabled" do let(:enable_file) { nil } it "doesn't use the file loader" do expect(data_loader).to receive(:from_url) expect(web_loader).to receive(:from_url) expect(file_loader).not_to receive(:from_url) expect { subject }.to raise_error(Prawn::SVG::UrlLoader::Error, /No handler available/) end end end end ruby-prawn-svg-0.32.0/spec/sample_images/000077500000000000000000000000001402126170300202335ustar00rootroot00000000000000ruby-prawn-svg-0.32.0/spec/sample_images/mushroom-long.jpg000066400000000000000000000556431402126170300235600ustar00rootroot00000000000000JFIFHH ICC_PROFILE mntrRGB XYZ $acsp-)=ޯUxBʃ9 descDybXYZbTRC dmdd gXYZ hgTRC lumi |meas $bkpt rXYZ rTRC tech vued wtpt pcprt 7chad ,descsRGB IEC61966-2-1 black scaledXYZ $curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmdesc.IEC 61966-2-1 Default RGB Colour Space - sRGBXYZ bXYZ PmeasXYZ 3XYZ o8sig CRT desc-Reference Viewing Condition in IEC 61966-2-1XYZ -textCopyright International Color Consortium, 2009sf32 D&uBExifMM* LGE(12iˆ%LNexus 5HHPixelmator 3.22014:06:02 13:06:05"'d $,4  <ȢD   2014:04:20 12:32:072014:04:20 12:32:07G ddd SEM& .)Od/d 2014:04:20http://ns.adobe.com/xap/1.0/ Pixelmator 3.2 2014-04-20T12:32:07 2014-06-02T13:06:05 2014-04-20T12:32:07 C    C  " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?S^ ׆I$.Z<*ms޸ EE\X^s4%؍ I#z+[tT;["ڈuַOoMlRQQ_2kX2GMOqZ~X g6fD8Ʃ.󧽒70`K;$sGM]"y4h$rv. zޭh{]7ZK??vfϜs#1Ҕqpri]ӡV$>5t~`6ONMs[7D= m~~wYZڧm?mH]Lg$ f/ Z/.IMMhryI_vje2p~:jXs*4!kGu&?fO@>+t;G5èh 6G@~K~|?umW@;()'yn.cÖר/cxfcV/Or){W_?ÚFQm/>#j%I6QXA4c6O rW%nnen5nՊXuR:Y{A[ZcxJ5t).MWBǕ܍th 5x&]Sx|nvI]́o=E~iW/g7⿁]Κ-ÒݶyjGsbm#׆|4[ou}Z{d_-:($uc*Z#ֽmUsܤտ\e|95 &]XO;77n%I?6@5^;čoKԧCwMM'p{~g_z<>gzuFIydb}NN}+ \P|GD~7˷i`(Oҹ*c]r”/:/7^.RÖB F),Ow"׈? 7uM̚{\xUt1H}e9(99_45߈5䈺UK3I0څk.m:h=moS9(cԜUv=Υ&s7??(xCNç ~4h*Ѥ9 ?^>8xV#SN񗅼[w u5iiq7:^kky5tI]އ)HU$h;Q@\OJ {fx'Z 6H/WI NBaS1W;R[M.E?_XZ!y\UO +]'mOcngn;(ROEe*Mv7Xoa!LiR; {==3[z^;n.Iǧ ` Zik421X9Sֲa{5F >QmZuinn`)roI/]=檖,7æ[$J ,=🌼?K e ,r@c'N=ZtH QVW¯jxK6KlC#lsҕ}m "Ub#. Uc-~gijg4 ldVT1s^uPOӴjm4O$&$pI!7]KfV;[[+,wGn-b)a;&l"K;9g>nʛ]R(VxDZ6]W=;/[6Wz̒6Ќ.ۀOj}sPLKߘ'[B*7t=ZZ#k_ž4ZMKV"AdlAHNb?w⏎iҭ5K: "I=Ӵ9oA4FXs`aא9#sCPHaqw*Io6q' ,;]bnEd"[ ɒO&/~-K/g%fΟb'|g]7K/C6X1'gB=[⿎u'JuKr FFElWxƍ]BPѮJA )Va9{q+*ssr7+ #(N;+Ӎ7m'?{B/2d@61AY7/u/ #t 1ԜpqI?:n5?Znu@#6eg$;;~5JJsmK\ 9O_wʓ.If+Uk<3tX~0_ipbk 'vo-P`zik=ƘMͬ _1os& in,>i0O°c \r<ӥ&m=ogG+/|V|[mqj&5ً I~+f.|)ܦ?Ou}}}Z? bD9={O&W5(E= ?PzsJu"}G3so]w|[ͫ4*HQ.Yh^XłV_?)<'_7LObcl+7Oo.YTsJi~trgyʓv^gOHЭ\Nc`'|#g #Gt=WB1$у,w渟Oyg`=ݳ\i<-{Zjwx !1IV*ϧlӎ*TjZ}zK9Wx.ox5-. mga)`^dhԤ3 #߭~'1x_584z +X/0G&#~ xvP5[H2(jh?h8M%Se~q4U8>2Uо%R˗bݫƗ곑#bM @|CxDhiZU GXds((\ g_ RIJ˯-:p?9Mb 865m,oI7}MMv$O!i&$nDn*YVc(SهvJthn~H>#'I|p: /|LΣCSU؄=$qD] ؊%gDPpbpyM'>kN| .,"U;O u8;@^\5%KF4~eVV%(%̣r5k>7 W7źv$l5-U_<:S[x6E>%2k"+wfi6 TFA! I'if\|=9m]ZSc(c.w)V8>)񟍥u[fF ƫ}%ف0'h$x.\aéǑ)EZi>(p(Z.YGޓ-GV揝22|-4FI-z̈ƁknHs1mĄ`8 5v|cMzUgJ)"T%J 'z^qxQuytI%r,zO?/t7N^ ݓuU1P],\PL՚Kmߪz+r(R*ݣ>ǹ&׫ZzukOoulVS[ +#FYrJz߉7 %ۍIH6_\kj2%\FW=^.67|s5Kh0|;@rr@P:Zϊ~} x(5Ek_0sUzZoǚ\MXnjֱJVwcIf7ȼZxG~OF=uh^;Gq "ɸ?&ø|A+ƚLZ_ڵKH\DU;PTrF k#U$xr_ъm{[=M)6r7e*3>yjɧ|4윕7w'lOIVA.7VlNr ^O>m.[M72疖T:jAKmIt=AǕq0` ω]>[ȬƢqDRX;+08.2Kq_{tL2IY|m췲i[]J/wvq-&6K(M}?|7j麈~o3E>4:PzE{YWW)n_,/^v:^if[xub]BybŁv$MsZwMi=rB[qy]/Ƕz'gXV+8. j/-==]/?|[{T] ZYK:/4->N"*A58{+')sw%$}{~Þ'qhPWRM[isIڮ\VgOy iR<󍰒8z3oGLVFz+qq1D_jt }/iN&@dPFK   }R=&LvFbicѺqYy$c m.)=yŭ*V르ءwnx̴ocH׉F;+FBs{CY" Z#*E?6;@xu -Sz-4IA}M2$QG'Ѳk ]gE>{g,[^c@>G' psڼWbd0[_VVޏ|O(Wm7쬯-'ũЈ+8g泤~/ػt J ƶ19G^Z_ZFlu~tK/U&w;H%~@:IX6ƭ۬9de_r:y?t(qVU"ծ]u%h2˨i XC_lV}\<皒ucbgWwnӹ8X'">*2*e}ւi2l O#JXX$#b>Ԋ*w4f"]#GuYrF?,>kW-;EM&WӵU>BMӆm<6>Ku;Bt2WC}]atSuo$098>Qd5"l-z'fnT,|`LA[6RN̊A.$8] iI񇊾']GLqo$`I>ПJΉxU֭+lp^0< |!UVx{Ά"1̹|[8aDh.,JeװӚ|]xcfPkZ%IfA] 4)$wGP8t~0ׇ|/hw𭎏=ia+#q9L8?*%(7JWɛ]{ʔMO{Y%VKV{,d',I'$^o;70CsE}bI+/~BZ۲owcjxIl>Fqdў&`KH|#sڭ~CjM5=|Nd"Lkī'{7M:㱎U}VQ;Ar8ʟ,b/}kGye֝jx0!H@=Mu֣ <)NV.nkL xjZ/~g?#?jϊ^omcZ%?hmnUSiV|@S8u7V4#~##O-e,p$8cy3=^՛_vKY#[OTZ ^?sw %Ӧy`LjpAҼ]bݭv_z=**sw>imtJWm/i $KSYIoBL1ȘR1b<)XY-mI;og9#Ew_ tz7m]^y/P 1D{\5/~8uM(_jެs*7M ;EλXrF_=#K> ZzԟS-Tͳ!G1s~~4I$uc߇:O_kjz& *BȨ ~Q2B|0q_MօIvo/OV1S'3~~}_~bxaz=_[T&ie^I#ڥO(Wi?Z?CF>o8u-jNfÑjg(yxUerʇs1\zW6gťθS+E=~|y:Ky o^.ytGmYö֊ox.%ۥ$Q#H+J_`5VIkp̰ؼVlpǚ{ zBbߡYl>Ӓ^*$o=p/Qj6īڔ̄3ڸwZ߅ԣthQXxŷ^0<6I ",rwy8{kZ~Yo2[J׶t* c1jΝisz[oɏ)*ӋZz^*_sC- Ao j2ŧ@NWdjNG5VW:ȫoip7|~ڈk[ƹZۏ#$v|Cxusōm ⤐Q]B:c]Na8|OWwvwS:4,lۻZWw?g$b+i%byoEy|_R5BẸ#Oqa%A2ܮU܅מ-KcKzZu͕夥ty+0$c:W>ʴRTӽte4)Z]viޟ_?mS<<@Ply쑖:~~L 4%6 *|&Ei;k/jF] A(pkG WLH۞0}r4+IYɷm1{?nW_w!VIWGLw9OŞ?RmX2TgvF {9F⻰_qyWwy./rx[kᅭƅ&j}OӻO$\`*5?Zjr~LnCR/13@f~u/o͆Ft#$<',tg'$*?+W~^G6YrZ-8wpwZ=niմkmW?4+Y{:Q5ܿdS]Η \ƿ/OvZ6%\q $*y'= wP\X-V4vXn"I"'5kEk}Gg+$#RKYY7p1QPVpzw;23h:)*Xtݴkw}S]u-N)wCg3Ӛ$6bx^)TUD=B}(%gM+1ٙoLQ]٭_S _\i?45-{/y?@-~C{-rEh[Lv5XZ63n'id/l~8I&O:kc`՝8ߓǩ+P Cy V[G$E$ވ9K?x'%P%3E/'#A5k~,4FSk$2 620H=:e&['i+eOЛ]I5Eo$rgfV%7E獦ʥ9$ua5|<)Y<_Y>.K ˆyB N@ \Mt-6>#ܖO#5qi&u,,kJv^w[LxP('-S?+ QS _nػ4eg@prw)pC`kk2>.[KD v1l}k' .~Qdn[-'MYWPYWxү+?dbn͗ι;|ӊso(֭(Ԡvm]1x_úǁ|mj蔍Bo{8 WGSW%ԾBͼ_mu$*$9 cz/% X_i# @NJ~MxP5q- 4I#8Bvx8_?:iY;{vxɪRx{Z/Sڲ_kZfehsoqos:KF\qg4 w޶Vۤwij* L=k +hLrq$?cn/ޟ*'LP}(²oލ뵸#X*){twWEc]Jԩǒ-8)+|Ok=~n~&Σs-*宧\ܴAf'blb/ ɯO>C߅z]D}87%I`GZ*1;OSArinͼM*a(Fsg'a{kXk%mk}F!(q~_Rm߶2 59s=^U⡥?Pn.4Holip`sοwڼ[&en\52nHb͐:qk.=?:v߽Ej\Bsԏ` =nÿ?h+=:KML ZKH` 0zQ^QiEϿш¼=)VGwo?w: ߈>#ã~'{,E^E 3@rD-yr=+z*]R[O!̫s@DgvҼ6Ŷ$&˶ֱF~&5_>*h><sk|UoF( slw]>K;tpR_ch:-Yu[[\,eet'=k汭i6q fh UR79%;ҼK'!;cg7r,y=HUi^iۺGk2T2d(2c)Sd~:Q`ҌV<ӍU_z3o%}Z^h,1}om$hs`?.AWwҥ9Sb:q_IM{G?m~,[N<* N^6r~A]\-n 1 jS~vV[W{=&{uIBe/;oͨ6ca=D_(FU;kC2I&Bn=zc?Zx/uu♴Y[ۋfx?Kr8kR9"̩9啣fެ`Yk:WZtkN-j>'@ Vn#67/C"úҲ[?Z+|wZEEbwp08(Ji[8kA+s/:PjFQW:snvB{Ug_<=xeWNhf܃-@?>wƹksWN퍦Q7ᅴ q,x 0'G^^޵èo\Si;ZI2#°?uϐkq>ӬtuHvE$+1%ąQa^Xajouܪ>w<<5}Jt 裴ZGIp*$y n/穯"TҎRptw^N=l߇SX-ܱL$}Dfe85\k*.ctnsESH}st<W-/)e9#듵vև= thW+tm:cp+~CvK UG[npW(Xq% .nSr-qD>cv*N[+u_ëon{3+|P/ݜuK]Nju+o.aPI]2yp4Ec`۳E$, m! wp &x/mǏ^mkxk>r,UN!xs/m44O> ')5U,a"mp>ɗaSU]7;Yu%*Tu0xȽ۽՟Jzlg`N*{gR(q\Rr@8m'ৄFl5;>k%X*ne;+龽Z{s3=N_x4xnIidA.GJ5xgX m-<Īs"YG 89?ZV9W!pbG$qoƞ~y/bqp\zmQMa~8Z]?s!>'lSn3ùIX6(9lMO,m5m-X{QQLJ@6PxjEouF/Z"#4(h I矧בW}{IK;+KĘG$;OztvzXU%~!x↗jW:#Ωl@Dq\Ov+oEhگn Q|큕;'y5x - Pbu? &t2Q8auMvPyg, nfRO~j_^yÞC~4AHmt N*ILbVd2OHm#:tV1i]Gs ndpV[+;>CoKVFiwrntK;Gt6pdYfl6QPyU|5m4^[z(-IFQJt܍_҄jCOkOvx[fb.t 1_COþ 'ڵԶۉByrny!QMܤOLǾ,iϬskk(P|0Q:J7z5P`/o3:FzVw3?, }*Rڸ+' lס:|d}*J=SWyx٥'٫~nhu^?Q[ _A#Q2xd8LT>B0+^;R*Yiw-V]fF&&6qd7K>;2hfwCv:O|pk_ĺW>*x.zcIfgcܪdp5/܇iRJxkW1>kZhi%'ۏڄ۪}mOĆ񞉫x3t/ kv0Fr#:뎻^A5 V,H&:㌲W޸-OO+"Y``>vfW`8fVOj>wsyId264g\&֛]pԹ((4q{>sCԥسMNJ#T`<澃>nYQIkɌ?X gxn S|_S¼4xZ@-M/6璪NOu+*u[{Vb/i!Hv} 5:K2K"Kى1.NZoڣ@[VI;]-?/s<JTej9ʢR*a9G1K ĺ՟\̉e# X|25OIˊk,ŎU6(%r+[? 5>xr+J\j"Ō!x>ɮ xWۛ"ʸɏ&RnMJv~ ښr xv;Kz%IhbKȱwe84-HU0C 6As-3q0/PP0/˞^τ.ŷ`1 +3Fq`BP'o/RjV_Y! FI(Q.zo}rehׂYq{_rԭD^+N]WmWYo$x=o^ MЬmlVce7JZ8eB$"m`à_{;?~ 2`Amm.#/_r!bp'l+|bS)?|B+~<ӗQ&5$j9븆,1$dW+ !Zxm<%`>aHnJ*>}QrJRltKRvfUa WbT}@W\%ͤ9Y4u/W%3W{(蔗coO]RP4uXܻ$_%8;Uw鴏Ҹ_ hs~9 4mSjuիH@yrps<E)ג~GVN%Oվ&k=kMTl\d,GTeuG;iF_MAhu|Oml6߈|>ӭ-^VH%Îc%¡JcQ^*1{LxxTwvC5!ŏͩ !A 4QEogl]'ʾruby-prawn-svg-0.32.0/spec/sample_images/mushroom-wide.jpg000066400000000000000000000504141402126170300235400ustar00rootroot00000000000000JFIFHH ICC_PROFILE mntrRGB XYZ $acsp-)=ޯUxBʃ9 descDybXYZbTRC dmdd gXYZ hgTRC lumi |meas $bkpt rXYZ rTRC tech vued wtpt pcprt 7chad ,descsRGB IEC61966-2-1 black scaledXYZ $curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmdesc.IEC 61966-2-1 Default RGB Colour Space - sRGBXYZ bXYZ PmeasXYZ 3XYZ o8sig CRT desc-Reference Viewing Condition in IEC 61966-2-1XYZ -textCopyright International Color Consortium, 2009sf32 D&uBExifMM* LGE(12iˆ%LNexus 5HHPixelmator 3.22014:06:02 13:06:71"'d $,4  <ȠgD   2014:04:20 12:32:072014:04:20 12:32:07G ddd SEM& .)Od/d 2014:04:20http://ns.adobe.com/xap/1.0/ Pixelmator 3.2 2014-04-20T12:32:07 2014-06-02T13:06:71 2014-04-20T12:32:07 C    C  g" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?o%ko %.XhېyHo0WT|XWN}=HH*ȩ]PEܫe  J6oӪ>^҆ݣk+]}nlφ>u{jxwĂ(DmJaoBFqq^VKo"k{bFd&ჷs`5^(Bs]j7\Ke8+lU-՜ /&h "mTޣ%s'hMWNW7O3¼]xxZrmkyEA|)J]~&:/CV"r~u,ZXU9NJ'K -@um!600|3n9Z] V|)&x]P]ife##8?J57kv =褏19?P.iqkMw<ʪ)nJVkqx$[^]qi%;lmxr`O9"_\jSii[]jr`v#R2yQk5S¶VNTzؒ#$BTHڵɟxRd:'!b(j ڻ\I<⾇/R*[7g3&Z3QMip;WOA4 &d+v`~bsyYZƭ,Z fXC9/T|޿ZJZYjU{\pJ.pp\㡭 C^X{9ė"`f$|lb3[f 9hԼ_]s3\2B^Kr8M 4sUK].,Vyu#>^:w*w_?LLIzu}4^k6^,noQ4~D"$ʉNpI& [ן|Ama1EKj7:&ǒV*. .9$u~!&Y#YV"b2XsM<{|ZԼGɥhQ[hRZ5I<.~@: ѧvO_{nZ_Z%w&O Jm^X,teoy2ȊNr]Q} V'^#d^,d[$Svwddl vϦEfx+⧆|-ZֈVR[\ P/?.zu>OӴWU,Ɲuĩ&9:67SKǧmoɋR(`욓mkߝ{348dudI/;[ 㓖'J))|? |A]fvl2'-is0o8!eU^T+.ZU׹<`(Ɣ(ʤl(&Zonף< Y-Rt-*X Zki|ykw;,D[X"HlHӼ;еKTT+%Z21@r"-F^miw^]};y,6Be\#+ϪDՏ bTGkk?O:GnVw5ˣm>"k}#42U_SlNma@e1F㎆jTI+vD!fَ' ʝUy-evW;_.m.GE$Oje_gj/O`ib#j&L6A?0${kL05{7]fYHc&r@HK1}3~ 2%\Jf݆*pvCR^iO1G$5{5k]~yYN I}{; $hӿK{P J,Y{ʾdៅv 5PBt~>//ZepZZ\`M*ʱR܌zUiVôoJc'|woK)'EVz^?mM(nv7dV'߇>Dwi4>( P`]y[+<̵͐wtȍ=>!6gt>G]JyܩyqdSGn6N+9P^Voo+MS펛z-7I,61 I8A8>'I=ind3@Gͱ 7$gC/i=ukB4|9TY%#UcG<ޭ5eņX>o_*pęYTmC%EǩmQ?~"aMzT].ra! y|C`n4f>E5nKXV<-۠m<7{ONV&Vէd_BHaR뙼[='-֗qϤ6[ٍdm*s(52|}ÛXuxgZlmӧTTp+Ȯ:h_fJjH>ZM!b$p3[bXJN].oG_}R9k0aRJ4|2OGKr>!i^ ?Zϕms_ m,Z>@d >]A6{u-yCq:F!8g9ga#S?jOIG-?MVyQ/mtֿ4%ܻfvʶ-R bH}ROwi,)< `P398p|vZދk-omBY|um]EƟ,x9uoޏ>@JI#s*z̞<7c[]CͰS1tiMtͺ v6^ǍoO 4 # Dĭ|&n;pMxj miݼ1sgdلN ezWUXXqI%+I_sRwcm޿=bN= uDW::_[+Ǫ""eb˴U= SYkc/,Kۻ{)8#s"y+üKxĚfDu^y $h|#R;[6/kc5 x\jP㲃ּvT_^뷪_3 M/kF++ikZw~RGƷ&/!$0!0*Sk FM6Tõ>ns׮kS[Rox~|g {**cF89ُh'Ÿ5e3 S2 W#n}^SNsRm]$Ulr䑆<}/n]R^df7dJ>FwH`l蚯+MvTV48{)wllGTҡ5}]h֡_ QQ4i=Sjn_{'h-J KHӮtMY<߶BFc@]=O9'|m'9tQ ~q!uuPG"y֏my릸V.kIn*xbIN_EOٴu99,9 kWWOwⱸS6moJm[em5ť-X<-$LÜ̚@[ɭ/k-m.J)28ܬe& Kjy4-( I'yQ҄4~WN??qtSӨIENܭŻ[z=Z]xSG"] ecaÞN=+ >,w_Eguc$u76@ЕSsmnMnYX1_'x#Ns+ u'C2i*j,s cu[0feI@8yTgN5[]JK[uݮV(`Qh*ߪi9?7-|#{Id:u&P% ,|aXZ%SPo5cWmCpJ;c\ ;W%u5I.u-Km _#+=;%ֻV\}R+{{_١w1B,m95S.۷OdjӦcYrH.LsCw|g[?/ch&YCR@I,z3^##ڧIos./䔈nfӧ.<#Ejul#?.kX$_m&־GBė#\ Mnf;3}3Lៅ.>b;6dKstDl…LƍGgxj\Omo2.2ax~#ƚ6="hRM!PveaHz_gYE]tj>G:1jY㶗ݭ_C.}J$^B*ZxCc P1`V6[\X){kxų20,~1CWw3][ek+ y`تlw[)fwgp ~SU}fB-F vfv#sF35 诗Y%MY$ 2 irgf0Yf]f[ kpRт95Zt =!#̯()Ni# iR.>&i7}9mcYǛ.#Pm b#8RkV,4t]҅ʮbpG"ד]oM:|,lM G9#Ļ.]G[ZDj:1;΋Z}*Qƣii<Z #3aʼnt<`sk¤uUQYK:vN\F Mm_ /ZiZqch|YmO7$mBKV- ;j~@T2=^#4leABL3VDܛԍ rc#{iNYg֬UeiISc%B&Ϥa,5n(m~4Uco7a:W+%lLM)+I$|u+> xF]&;xm\6Y⍵m/%Trs^*:/Eᖊtus2g(ڿ6qޯxίY[hz烴_\w^%#jgiA1x-bܢ^m֞[xBoojYjy|WgNFGU_6.4jk9q6/,m>GI@|5|{+Zю$8aCqX' i{VlQʗ\ڄ ] 33^+mF/_;wlz1jNt\[jRJۢ~3fâ <w4S(ģsar87t5w(f]foTar+`A*xu;<" Z8++19#:~Eg3;[ݙ%{'[PbDX 18^ g5%*2KiK[ͮ=׺+o{vG>MC\}jkMz7[ح>O6@1ePg^k$bLyzdMɹwےPCqq^}j7$KlDY.-N"E.s$<q+ _ ?4Ga{ xuѭ2+ Aƣi^gtU|˔#F_->R tY|B VւfXܤdW8(c{K<={oM[*)B Wolڏ B% Nka?qK_wnhSߕ?؉ x%XgW˗(ܰR98 p' Ӳ읙OWcen59[ |Yq^VK]F-+"ꬨeHzg[~&58k:k\xMf[[b, [##[w^i d ջ\`#u_ҵ_kx"9-3YE@Xe@P2z7#5[ R5 [{#/VkQtvfN"/#{u,m"CEU*r+n/<1/|?ި̷V> !$um-HH9_Ƶ{#n(s"~U\v'{ir8iD Ft8 =&=,C]Mz}CN)ZIUX wm|wxben %dْ$h 9u6FkoVV?H!Q9~ʿ&*xO ~~9Ղim˒uU1 &&LfΤjsf7VJQOnIϋ~%&#eŭ=Ѹ}>)`nrܝ"Lcѿ1kٌYjf`HqQJ}3Y4^$ \-]HIgҵxX]>)ݾyeٴH#s_/XeGQIFpUmG _aTI[ߚR_&zwǞ(5WkjFd]*آm.Tv}wƟu>B{~wec0C `R4v2AEyk -q++ۉH87-D.y$ȬoZMAA]26YP.Y<ѦXIn ɭ2To6[[='g 潯ۣM˽͝M%w;$++0Ȍ,0屌kS}摢|o, SLm*J5$`m;Ib>e^M>Wѣº%eD 4nFH?/uV#,|A;4AXꪗ U≙Ne_2"zB )ou0ӧEUfmJfd/ywImχMg|{n'wQl`"ħúg+ASO k8q*O_|TӬƝ"${ttPY] "MˏF#ǀִ Y 3KokISlf"ByzZa4ҕ7N}^gʖ:]u\5{t–ZهH&_C+~"ֵMvK¶YpNTB7 (ɮo[O/49%V?ăn G<viy"nlVmU!ʳ&$LҺ~rͤ+c <~Uw$i{$yZtHCgfi8Av Q9;xǺn=_OXRGo:کS\m?x/>Cw&ivY%IZ26$75)G]ZTDf087NV9_ReKTW~)ѥVqyvKo|#vP ApC"|(p8ZR ^hw"5ByS?N"ºyS]xuHM!fT̊21>!kz.[/$O#$s(Ҏ*RQ[UẔ0H_{?s_mk἟!\k;[_idU%_:^Vд]x Q#Kk2DM,mv8{' }_%Pݘtlp=m r6Z"tTS D|Ƿ 3|VM C3$]2e] G_0pKZV7sQ_Z[AQb`3~^@Wt!**9lǩ|BYn'?a_-cA$尻U8nOF~w ,%OL͓tm`z|;5ĺV&q#öny8bTnjq=+C ]+4_x2msUE崁[pO\(crI1֧_'F*&eio jl6y0Wfqo F I~I8nϝ8b7`A9j1Z_\}JL&vH+y&<t{MpZ$%AV8湱1){g۬_unVI+M{54g螞螶|Y+?M'Pͅ,rBC|p9\I]ſ?־h4$0Um-  %xݓ\mV^~A,k,,YB} [^6/<9ime6(PB&e+EN" xVn;תSd7>[̨'xoz~.de<1AcZ6Vr(< t~%|b|=ݠXhh3yr nт>w _qmO^%hz3>C,ꣳGR x}§Fþ)awyb+y5T^kV1jP4F< 2x'VwD#O>19l|)}rV Lh]О {o|C'_it)ie(Hhl.H#(cR]Vף844S__|Q[ZhژI-.|fI 0p 'C75nYke|TeQ9(g6V];wcO[ԎԼ/ o h*xV{Է,?!,~\ soZ/#'Dm[MDzy4݌c QEvR_g48iUJIG[խ4C㔞%q6}> c)39 GE3SguBU`*J+zXYG-B0J4ۺn+[o:qX[ETϘ ʧQ)А䝦o>/G;:^o{kqq+mYGy,Y7AWUTSW0T-z~ER&}%e]gEmW'N+$ ͒68y|6@:V-1<,d1 ㎸#(]~"ϞUk>n6+Y>| k(ӮaӘJ +$[߅5xGHR)w+K#x3=rż69;zr U߳` vruby-prawn-svg-0.32.0/spec/sample_output/000077500000000000000000000000001402126170300203265ustar00rootroot00000000000000ruby-prawn-svg-0.32.0/spec/sample_output/.keep000066400000000000000000000000001402126170300212410ustar00rootroot00000000000000ruby-prawn-svg-0.32.0/spec/sample_svg/000077500000000000000000000000001402126170300175655ustar00rootroot00000000000000ruby-prawn-svg-0.32.0/spec/sample_svg/arcs01.svg000066400000000000000000000017461402126170300214070ustar00rootroot00000000000000 Example arcs01 - arc commands in path data Picture of a pie chart with two pie wedges and a picture of a line with arc blips ruby-prawn-svg-0.32.0/spec/sample_svg/arrows.svg000066400000000000000000000045101402126170300216230ustar00rootroot00000000000000 image/svg+xml ruby-prawn-svg-0.32.0/spec/sample_svg/cap_styles.svg000066400000000000000000000011531402126170300224540ustar00rootroot00000000000000 ruby-prawn-svg-0.32.0/spec/sample_svg/circle01.svg000066400000000000000000000011041402126170300217040ustar00rootroot00000000000000 Example circle01 - circle filled with red and stroked with blue ruby-prawn-svg-0.32.0/spec/sample_svg/clip_path.svg000066400000000000000000000005521402126170300222530ustar00rootroot00000000000000 ruby-prawn-svg-0.32.0/spec/sample_svg/close_path.svg000066400000000000000000000006461402126170300224350ustar00rootroot00000000000000 Example close_path - triangle with rounded corners ruby-prawn-svg-0.32.0/spec/sample_svg/cubic01.svg000066400000000000000000000036331402126170300215410ustar00rootroot00000000000000 Example cubic01- cubic Bézier commands in path data Picture showing a simple example of path data using both a "C" and an "S" command, along with annotations showing the control points and end points M100,200 C100,100 250,100 250,200 S400,300 400,200 ruby-prawn-svg-0.32.0/spec/sample_svg/cubic01a.svg000066400000000000000000000040701402126170300216760ustar00rootroot00000000000000 Example cubic01- cubic Bézier commands in path data Picture showing a simple example of path data using both a "C" and an "S" command, along with annotations showing the control points and end points THIS TEXT SHOULD NOT BE RENDERED - IT IS IN A DEFS BLOCK M100,200 C100,100 250,100 250,200 S400,300 400,200 ruby-prawn-svg-0.32.0/spec/sample_svg/cubic02.svg000066400000000000000000000106651402126170300215450ustar00rootroot00000000000000 Example cubic02 - cubic Bezier commands in path data Picture showing examples of "C" and "S" commands, along with annotations showing the control points and end points M100,200 C100,100 400,100 400,200 M100,500 C25,400 475,400 400,500 M100,800 C175,700 325,700 400,800 M600,200 C675,100 975,100 900,200 M600,500 C600,350 900,650 900,500 M600,800 C625,700 725,700 750,800 S875,900 900,800 ruby-prawn-svg-0.32.0/spec/sample_svg/display_none.svg000066400000000000000000000020341402126170300227710ustar00rootroot00000000000000 Visible ruby-prawn-svg-0.32.0/spec/sample_svg/double_opacity.svg000066400000000000000000000005651402126170300233160ustar00rootroot00000000000000 ruby-prawn-svg-0.32.0/spec/sample_svg/ellipse01.svg000066400000000000000000000012771402126170300221130ustar00rootroot00000000000000 Example ellipse01 - examples of ellipses ruby-prawn-svg-0.32.0/spec/sample_svg/gistfile1.svg000066400000000000000000000102331402126170300221740ustar00rootroot00000000000000 Alice Bob hello this is a first note ok this is another note I am thinking a note can also be defined on several lines ruby-prawn-svg-0.32.0/spec/sample_svg/google_charts.svg000066400000000000000000000347651402126170300231450ustar00rootroot00000000000000 03/03/12 05/03/12 07/03/12 09/03/12 11/03/12 16/03/12 20/03/12 22/03/12 24/03/12 26/03/12 28/03/12 30/03/12 02/04/12 04/04/12 11/04/12 13/04/12 16/04/12 18/04/12 20/04/12 22/04/12 25/04/12 27/04/12 01/05/12 03/05/12 0 3 6 9 12 15 18 21 ruby-prawn-svg-0.32.0/spec/sample_svg/gradient_transform.svg000066400000000000000000000015661402126170300242060ustar00rootroot00000000000000 ruby-prawn-svg-0.32.0/spec/sample_svg/gradients.svg000066400000000000000000000040411402126170300222650ustar00rootroot00000000000000 ruby-prawn-svg-0.32.0/spec/sample_svg/hidden_paths.svg000066400000000000000000000004511402126170300227400ustar00rootroot00000000000000 ruby-prawn-svg-0.32.0/spec/sample_svg/highcharts.svg000066400000000000000000000117051402126170300224360ustar00rootroot00000000000000 Created with Highcharts 3.0.7 Mobilière Bâloise Generali ruby-prawn-svg-0.32.0/spec/sample_svg/image01.svg000066400000000000000000000232521402126170300215350ustar00rootroot00000000000000 mid/mid mid/mid mid/mid min/min min/min max/max max/max wide image, aspect ratio meet wide image, aspect ratio slice long image, aspect ratio meet long image, aspect ratio slice aspect ratio preservation disabled ruby-prawn-svg-0.32.0/spec/sample_svg/image02_base64.svg000066400000000000000000001442461402126170300227110ustar00rootroot00000000000000 image/svg+xml ruby-prawn-svg-0.32.0/spec/sample_svg/image03.svg000066400000000000000000000035251402126170300215400ustar00rootroot00000000000000 wide image, aspect ratio meet ruby-prawn-svg-0.32.0/spec/sample_svg/line01.svg000066400000000000000000000016141402126170300214000ustar00rootroot00000000000000 Example line01 - lines expressed in user coordinates ruby-prawn-svg-0.32.0/spec/sample_svg/links.svg000066400000000000000000000026351402126170300214340ustar00rootroot00000000000000 You can use links in notes You can use links in notes ruby-prawn-svg-0.32.0/spec/sample_svg/marker.svg000066400000000000000000000021451402126170300215710ustar00rootroot00000000000000 ruby-prawn-svg-0.32.0/spec/sample_svg/markers_degenerate_cp.svg000066400000000000000000000012161402126170300246170ustar00rootroot00000000000000 ruby-prawn-svg-0.32.0/spec/sample_svg/maths.svg000066400000000000000000000121431402126170300214230ustar00rootroot00000000000000 ruby-prawn-svg-0.32.0/spec/sample_svg/matrix_transform.svg000066400000000000000000000013601402126170300237050ustar00rootroot00000000000000 Zero transform Matrix transform ruby-prawn-svg-0.32.0/spec/sample_svg/matrix_transform_3.svg000066400000000000000000000025211402126170300241270ustar00rootroot00000000000000 ruby-prawn-svg-0.32.0/spec/sample_svg/negminy.svg000066400000000000000000000050411402126170300217540ustar00rootroot00000000000000 ruby-prawn-svg-0.32.0/spec/sample_svg/no_width_or_height.svg000066400000000000000000000004051402126170300241500ustar00rootroot00000000000000 ruby-prawn-svg-0.32.0/spec/sample_svg/offset_viewport.svg000066400000000000000000000005471402126170300235410ustar00rootroot00000000000000 ruby-prawn-svg-0.32.0/spec/sample_svg/omnigraffle.svg000066400000000000000000000053421402126170300226030ustar00rootroot00000000000000 2010-05-25 19:53Z Canvas 1 Layer 1 Tiny Grey Text on Yellow Circle Blue Text on Red Triangle ruby-prawn-svg-0.32.0/spec/sample_svg/opacity01.svg000066400000000000000000000036321402126170300221230ustar00rootroot00000000000000 Example opacity01 - opacity property ruby-prawn-svg-0.32.0/spec/sample_svg/path.svg000066400000000000000000000004161402126170300212430ustar00rootroot00000000000000 ruby-prawn-svg-0.32.0/spec/sample_svg/pie_piece.svg000066400000000000000000000010271402126170300222300ustar00rootroot00000000000000 ruby-prawn-svg-0.32.0/spec/sample_svg/polygon01.svg000066400000000000000000000030451402126170300221400ustar00rootroot00000000000000 Example polygon01 - star and hexagon ruby-prawn-svg-0.32.0/spec/sample_svg/polyline01.svg000066400000000000000000000015211402126170300223010ustar00rootroot00000000000000 Example polyline01 - increasingly larger bars ruby-prawn-svg-0.32.0/spec/sample_svg/preserve-space.svg000066400000000000000000000010661402126170300232350ustar00rootroot00000000000000 Text (Far away text) Text (Close text) Text With Newlines And Preserve Text With Newlines No Preserve ruby-prawn-svg-0.32.0/spec/sample_svg/quad01.svg000066400000000000000000000021541402126170300214030ustar00rootroot00000000000000 Example quad01 - quadratic Bezier commands in path data Picture showing a "Q" a "T" command, along with annotations showing the control points and end points ruby-prawn-svg-0.32.0/spec/sample_svg/radgrad01-bounding.svg000066400000000000000000000017431402126170300236630ustar00rootroot00000000000000 Example radgrad01 - fill a rectangle by referencing a radial gradient paint server ruby-prawn-svg-0.32.0/spec/sample_svg/radgrad01.svg000066400000000000000000000020021402126170300220450ustar00rootroot00000000000000 Example radgrad01 - fill a rectangle by referencing a radial gradient paint server ruby-prawn-svg-0.32.0/spec/sample_svg/rect01.svg000066400000000000000000000011021402126170300213760ustar00rootroot00000000000000 Example rect01 - rectangle with sharp corners ruby-prawn-svg-0.32.0/spec/sample_svg/rect02.svg000066400000000000000000000013041402126170300214030ustar00rootroot00000000000000 Example rect02 - rounded rectangles ruby-prawn-svg-0.32.0/spec/sample_svg/rotate_scale.svg000066400000000000000000000027231402126170300227570ustar00rootroot00000000000000 Example RotateScale - Rotate and scale transforms ABC (rotate) ABC (scale) ruby-prawn-svg-0.32.0/spec/sample_svg/scale.svg000066400000000000000000000013701402126170300213760ustar00rootroot00000000000000 scale(1,2) scale(2,1) scale(3,1) scale(2) ruby-prawn-svg-0.32.0/spec/sample_svg/scruffy_graph.svg000066400000000000000000000311411402126170300231500ustar00rootroot00000000000000 Steam 0 2,428 4,855 7,282 9,710 Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec This Year (2008) Last Year (2007) ruby-prawn-svg-0.32.0/spec/sample_svg/subfamilies.svg000066400000000000000000000025241402126170300226140ustar00rootroot00000000000000 prawn-svg prawn-svg prawn-svg prawn-svg prawn-svg ruby-prawn-svg-0.32.0/spec/sample_svg/subviewports.svg000066400000000000000000000204241402126170300230640ustar00rootroot00000000000000 Example PreserveAspectRatio - illustrates preserveAspectRatio attribute SVG to fit Viewport 1 Viewport 2 --------------- meet --------------- xMin* xMid* xMax* ---------- meet ---------- *YMin *YMid *YMax ---------- slice ---------- xMin* xMid* xMax* --------------- slice --------------- *YMin *YMid *YMax ruby-prawn-svg-0.32.0/spec/sample_svg/subviewports2.svg000066400000000000000000000013401402126170300231420ustar00rootroot00000000000000 ruby-prawn-svg-0.32.0/spec/sample_svg/svg_fill.svg000066400000000000000000000004771402126170300221230ustar00rootroot00000000000000 This is red text. ruby-prawn-svg-0.32.0/spec/sample_svg/text-decoration.svg000066400000000000000000000003261402126170300234200ustar00rootroot00000000000000 Underlined text Struck-through text ruby-prawn-svg-0.32.0/spec/sample_svg/text_entities.svg000066400000000000000000000010171402126170300231750ustar00rootroot00000000000000 More & more people say "Less is < and more is >." ruby-prawn-svg-0.32.0/spec/sample_svg/text_stroke.svg000066400000000000000000000025501402126170300226630ustar00rootroot00000000000000 Stroke only Stroke and fill No stroke or fill Fill only Inherited Mixed modes in a text More mixed modes in a text Even more mixed modes in a text ruby-prawn-svg-0.32.0/spec/sample_svg/transform.svg000066400000000000000000000017141402126170300223240ustar00rootroot00000000000000 ruby-prawn-svg-0.32.0/spec/sample_svg/tref01.svg000066400000000000000000000014741402126170300214150ustar00rootroot00000000000000 Referenced character data Example tref01 - inline vs reference text content Inline character data ruby-prawn-svg-0.32.0/spec/sample_svg/triangle01.svg000066400000000000000000000010351402126170300222530ustar00rootroot00000000000000 Example triangle01- simple example of a 'path' A path that draws a triangle ruby-prawn-svg-0.32.0/spec/sample_svg/tspan01.svg000066400000000000000000000012421402126170300215730ustar00rootroot00000000000000 Example tspan01 - using tspan to change visual attributes You are not a banana. ruby-prawn-svg-0.32.0/spec/sample_svg/tspan02.svg000066400000000000000000000014421402126170300215760ustar00rootroot00000000000000 Example tspan02 - using tspan's dx and dy attributes for incremental positioning adjustments But you are a peach! ruby-prawn-svg-0.32.0/spec/sample_svg/tspan03-cc.svg000066400000000000000000000014741402126170300221670ustar00rootroot00000000000000 Example tspan03 - using tspan's x and y attributes for multiline text and precise glyph positioning Cute and fuzzy ruby-prawn-svg-0.32.0/spec/sample_svg/tspan03.svg000066400000000000000000000014351402126170300216010ustar00rootroot00000000000000 Example tspan03 - using tspan's x and y attributes for multiline text and precise glyph positioning Cute and fuzzy ruby-prawn-svg-0.32.0/spec/sample_svg/tspan04.svg000066400000000000000000000014221402126170300215760ustar00rootroot00000000000000 Example tspan04 - Use parent text-anchor attribute attributes You are a banana. ruby-prawn-svg-0.32.0/spec/sample_svg/tspan05.svg000066400000000000000000000023131402126170300215770ustar00rootroot00000000000000 Example tspan05 - propagation of rotation values to nested tspan elements. Not all characters inthe text have a specified rotation ruby-prawn-svg-0.32.0/spec/sample_svg/tspan91.svg000066400000000000000000000022501402126170300216040ustar00rootroot00000000000000 You are hardly a banana. Then Start as you mean to go on Then Start as you mean to go on ok ruby-prawn-svg-0.32.0/spec/sample_svg/use.svg000066400000000000000000000016411402126170300211040ustar00rootroot00000000000000 ruby-prawn-svg-0.32.0/spec/sample_svg/use_disordered.svg000066400000000000000000000016331402126170300233110ustar00rootroot00000000000000 ruby-prawn-svg-0.32.0/spec/sample_svg/viewbox.svg000066400000000000000000000004371402126170300217750ustar00rootroot00000000000000 ruby-prawn-svg-0.32.0/spec/sample_svg/viewport.svg000066400000000000000000000020651402126170300221700ustar00rootroot00000000000000 Example ViewBox - uses the viewBox attribute to automatically create an initial user coordinate system which causes the graphic to scale to fit into the viewport no matter what size the viewport is. Stretch to fit ruby-prawn-svg-0.32.0/spec/sample_svg/warning-radioactive.svg000066400000000000000000000162361402126170300242530ustar00rootroot00000000000000 ruby-prawn-svg-0.32.0/spec/sample_ttf/000077500000000000000000000000001402126170300175635ustar00rootroot00000000000000ruby-prawn-svg-0.32.0/spec/sample_ttf/OpenSans-SemiboldItalic.ttf000077500000000000000000006375241402126170300247360ustar00rootroot000000000000000DSIG۾)tGDEF&%GPOS 77%8GSUB+=&OS/2r`cmap)/hcvt fpgm~agasp% glyf[ݹ%Hhead<6hhea{t$hmtxs*)kernT+ ~B6locaRFDVmaxpO namelpost7l&+prepx%ZY_< cHL b   T/\X33f @ [(1ASC X R -!Z+3h=BNfbhu/'!h\hhhhh5hoh}hLh\'!'hshuhsdF^F5FFwFdFFDDFF!'wDDwwq-%-Do^/^^3^+/3/39/3///^^D/\odyVhho-hhhhjh'oPhu/omhuNho='D }}yl5F5F5F5F^5DhmwwwwDF^^^^^^^^3^3^3^3^3/3/3/3/P/^^^^^hu3ooooVV^^^^^^^^F^^5^5F3^5F3^5F3^5F3^5F3^w+w+w+w+F/F/3/3/3/33/1h/d3F9/9/F3/F3F3/F/ ND/D/D/N.D/^^^^FD/FDFD/!'!'!'!':\%wowowowowowoyDVDDDDh^^m3!'oboHo)B`oFoRwRw'44A-Mm4RWdFF5FDFFDD'FFBD=3D^3/d}^H?3^/bd9/7'dV^BT^^T}^7 3^d}^}3^5FF!'db\FF FHFF\J5FFFFZDFFF =D?DDHFFF^hq^%^3^- oo7/)/^/^/V^mm=mXuTuw/o3^/%^3/3/35/7/VmFb/yyyDV///-,ws#w#sDb% VZmPm )hhR7h3+d)quWd` hudb/hohuhuhuwL3{FsjsVy3TT3s RVdD/^;2^Pm5FF3^o1fLF/oF9/F/3^bb B^^`^1f^o`?Zjh))FmFVyF5bFB/1 %D/D?HF//DLF/F/F/^^=/DdD\ ouZZ??D/-^1-^1-HF/F/F/?'D)^^^5F3^HL37HL37- RFoFo^^^ V V V?Fb/Fu)bFN^R^;JF/^w Z^3^^^^^^^^^^^^5F3^5F3^5F3^5F3^5F3^5F3^5F3^5F3^3/3^^^^^^^^^^^^wowoPmPmPmPmPmDVDVDV3bm|^77#\+jf`?h&`w\'''''`F`F`F`F`F`F`F`F``FFA`FFFFFFF 0HI~'2a7 # O_?M   " & 0 3 : < D p y  !!!! !"!&!.!^"""""""+"H"`"e% IJ(3b7 #P`>M   & 0 2 9 < D p t  !!!! !"!&!.!["""""""+"H"`"d%aIvhcb]gD Xz}} Bvt n%"iOS0L\pr`<&'()*+,-./0123456789:;<=>?@AIJ$%TUVWXY\]^_`abcdefhijklmnopqrstuvhijkFopqrstu45]^@G[ZYXUTSRQPONMLKJIHGFEDCBA@?>=<;:9876510/.-,('&%$#"! , `E% Fa#E#aH-, EhD-,E#F` a F`&#HH-,E#F#a ` &a a&#HH-,E#F`@a f`&#HH-,E#F#a@` &a@a&#HH-, <<-, E# D# ZQX# D#Y QX# MD#Y &QX# D#Y!!-, EhD ` EFvhE`D-, C#Ce -, C#C -,(#p(>(#p(E: -, E%EadPQXED!!Y-,I#D-, EC`D-,CCe -, i@a ,b`+ d#da\XaY-,E+)#D)z-,Ee,#DE+#D-,KRXED!!Y-,KQXED!!Y-,%# `#-,%# a#-,%-,CRX!!!!!F#F`F# F`ab# # pE` PXaFY`h:Y-, E%FRKQ[X%F ha%%?#!8!Y-, E%FPX%F ha%%?#!8!Y-,CC -,!! d#d@b-,!QX d#d b@/+Y`-,!QX d#dUb/+Y`-, d#d@b`#!-,KSX%Id#Ei@ab aj#D#!# 9/Y-,KSX %Idi &%Id#ab aj#D&#D#D& 9# 9//Y-,E#E`#E`#E`#vhb -,H+-, ETX@D E@aD!!Y-,E0/E#Ea``iD-,KQX/#p#B!!Y-,KQX %EiSXD!!Y!!Y-,EC`c`iD-,/ED-,E# E`D-,E#E`D-,K#QX34 34YDD-,CX&EXdf`d `f X!@YaY#XeY)#D#)!!!!!Y-,CTXKS#KQZX8!!Y!!!!Y-,CX%Ed `f X!@Ya#XeY)#D%% XY%% F%#B<%%%% F%`#B< XY%%)) EeD%%)%% XY%%CH%%%%`CH!Y!!!!!!!-,% F%#B%%EH!!!!-,% %%CH!!!-,E# E P X#e#Y#h @PX!@Y#XeY`D-,KS#KQZX E`D!!Y-,KTX E`D!!Y-,KS#KQZX8!!Y-,!KTX8!!Y-,CTXF+!!!!Y-,CTXG+!!!Y-,CTXH+!!!!Y-,CTXI+!!!Y-, #KSKQZX#8!!Y-,%ISX @8!Y-,F#F`#Fa#  Fab@@pE`h:-, #Id#SX<!Y-,KRX}zY-,KKTB-,B#Q@SZX TXC`BY$QX @TXC`B$TX C`BKKRXC`BY@TXC`BY@cTXC`BY@cTXC`BY&QX@cTX@C`BY@cTXC`BYYYYYYCTX@ @@ @  CTX@   CRX@ @@ @Y@U@cUZX  YYYBBBBB-,Eh#KQX# E d@PX|Yh`YD-,%%#>#> #eB #B#?#? #eB#B-,CPCT[X!# Y-,Y+-,-@ !H U UHU?OFNMMF&4U%$LKKF3UU3U?JJJIHFGFIF#H"U3U3UU3UU3UoTS++KRK P[%S@QZUZ[XYBK2SX YKdSXBYss++^stt+++++t++ssst+++++++++++++st+++^NuRy1Fc!'Gp'GT({/}+w8  8 n  [ 0 U  $ 8 S o 0 c C2u;t 4xS|);+v &(g&8e+iBXm 0A)ul~hyP\m~K\m~ G X i z !!!!3!D!P!\!n!!!!!!!!" ""~"""""""#####5#F#X#i#{#####$$e$w$$$$$$$$% %%$%6%H%T%_%%%%%%%%&&3&b&t&&&&&&' 'Q'c't''''((((((((() ))-)9)E)W)i)t))))*(*:*K*]*n********+++)+:+M+_+p+++++,3,-5-G-Y-k-|-----. .(.[..../:/K/T/f/x////////00 000i0q0y0000011 1=1E1M1112?2R2e2v222233u334@445555=555666S6677K7w788U88888899Z9l99999:1:v::::;;B;J;R;;;<&:>w>>?D???@3@x@@AJAAAABBLBuB}BBBBBBCCJCCD:DDEEWEEFFrFFFFFFGXGGGGHH;H[HmH~HHHHHHHIII%I>IYIoIIIIJ/JJJK?KGKOKhKKKKLLtLM@MMNSNNNNO O!O8OOOOPP0PPQ#Q[QQQQQR R/RHRaRzRRSS_SyST T T T T T T T T T T T T T U+U~UUVVBVVVVVVWWGWXXXXY:YYYYYYYZZZ'ZZ[[l[\\Q\\]]j]^^r^____`+`b`````a8abDbcwcddFd}dddefffg\gghIhhiiQiijVjbjnjjkkOkkll4lglllmLmnnnnno3o;oboopp:pqpqqJqqrrTrsssstttbttu-ujuuv vNvvww"w4wEwXwjwrwzwwwx5xHxZxmxxxxy+y=yNyaysyyyyyyyyzzz)z;zNz`zszzzzz{?{{||P|||}}}~5~~(̀^߁nvł%1CUh{ǂڂ+>Qdwƃۃ):M`s҄!-9EQcuԅ #8J[m~ņц݆+EPdA=ObC} ?3210#!#H`J373@     ?3?399//333333333310!!####7!!7!33333# Ty{yuT'yyyyRh^^ZZ=H%+A@"@H% ++@  OY@&&MY/3+3/3+393+10#7&'5&&546773&'6654'--ʼnN\T%#VnPu8`VesYYn C*88uBB3Xr bMe,D ]Lb)F )7'@555$.?3?3??99//3310"326654#"&54632%#"326654#"&546327X5P4W;os|jw> 4W9Q4X;oqjv#zgtf͚'J%sluh˚*BZ 14@#/$),&&+KY/ KY/?+?+?99910"6654&267%467&54632673!'#"&W^>iHMJapXṠmHq^j|lXm\KuDBG67}JVVmbբ[pPG ?10#HN '??103#NsWC~f/ '??10#3/s\$G V ?10%%'%7dt f%Gb%-=sȐ dòu  RY/3+310!5!3!!#{yw}V/10%#6N}i_/R LY/+107!/--!N QY ?+1074632#"&!^T8C_MB?^Sc?=NgG ??10#+J\L @ MY MY?+?+10#"&5$32%"3265L¿pakNZdc(o   ??9910!#67'3}69Njf7/u=?@ MYNY?+9?+10!!7>54&#"'6632!_$װ}8cZFesxuNn{FUc54&#"'6324632#"&k{kO%UQMNN˫h\^T8CbLB=ZMPQ0FX7%qxwJvUSc?=OdEdF8D,@ 9(5 ?? -!5(-/3?39/3339/3910#"&'##"&54632326654$#"327#"$5$!2"32677&wքbi e{4UJ\eOH|GƩ$3VRpRw)@5Nۦ\J xr-\zVZ8vkgN@ LY ?3?39/+10!#!#&5;9( 7WjHf4F -@  KYLYLY?+?+9/+9102!!32654##32654&## 㭙lw5nNjߵߓxtlyoۈ~bg!@ LY LY ?+?+10"327#"$32&&򑥡`٬^?̴DC) \"0F @ LYLY?+?+10!!! 2$54&##o5q$ı}l58ȸF &@ LYLY LY?+?+9/+10!!!!!!!N5+T)`u8F @ LYLY?+?9/+10!#!!!!35+`- :\&@LY LY LY?+?+9/+10!# $32&#"327!pՄwogZmjP (%$ )1Vͷ!sF @ LY ?3?39/+10!#!#3!3Vʋ56mV? @ KY KY?+3?+310!!77'7! ;枅<3;;<hs LY#?+?10"'73273hBTE5+.hZFf @  ?3?39910!!#37!?u5헍d>cFyLY?+?1033!F5+D@   ?33?399310!##!3!#67#s .5Cm^X'/}v}JhBD@   ?3?39910!!##!3673f 5 2E6A @ LY LY?+?+10# $32%"32654&Vۊ{L+ ]ʭSΪF@ LY LY?+?9/+1032654&##!##!2^uywWns5N쟒md#@LYLY?+9?+10!# $32%"32654&Vۊ{[H+ ]ʭSѪF &@ KY LY?+?39/+910#!2!'32654&##{5RϏ{v|wHĥ4HƖi\';$ @ LYLY?+?+9910#"'532654&'.546632&#"ҊRid5{ͰVm?gvKauhEkSCnOl\Nu^/G=Aa@ LY?+3?10!#!7!!-+@  LY?+?310#"&547332678wy'DSWwXFfqH  ??3910%673!3FCJ JwgL@    ?3?3399310!!'7#!3367336673%%/F5 S;TfJj݆IX+N% @  ?3?39910!!!3!JJ P:??3910!#3F rwo) @LYLY?+3?+310!!7!7!!T!R+#?Ϭ'?3?310!!#3R}'g ??10#Jq'?3?3103#7!!j1'T%//39103#%`N[NDH/310!7!u1! /10#&&'53A"/U?C^f '@  FYFY?+??+?9910"&54632373#7#'2654&#"a' >iRf^LUZQ˸`[WľXkfe/P#'@ FYFY?+?+??9910"&'##336632"32654Bb( @JG 2ZV Qc]UUVZV?/qW϶`k^f@  FYFY?+?+10"&54$32&#"3267ؓ FzcpcJAS=5ox, G^!.@ FY HY FY?+?+?+?991023673#7##"&5462654&#"oY LX\ RaWYUXfhfjZ˺dD[n^f #&@HY HY GY ?+?+9/+10"32654&"&54$32!#3267`%@ݛ +qpHa`kb39:Uo~&.,%)@FY HYFY?+?+33?+10"'5327#?6632&#"3#LZ;@2+ٳ,s`=J>ES%(jL\Ƨ+VbV㽲wf'4AH@(((FYη`k^f"'@ FYFY?+?+??99102373#667##"&5462654&#"q[ @K ?TZ Pa[QVYf]8lZͶfD^k/f@    ???92102&#"#3366>.360~'j Sf  Rxiqf" @ GYHY?+?+9910#"'532654&'&&54632&#"ҾaxEk}gֶĖL~I[BfiX.TCZPE3I=C_TLB;-F7;Tc\%H'@@ HYFY?+?+3310%27# 547#?3!!DS#x<y4'z 29J:nR7%+3oR@   FY?+??3910326673#7##"&5467HncRg {R4rӎtm?{>HdPR  ??321033366737T7RJ)Vy^R@   ?3?3399310!'7!336733>3L5/  B+P/sF>~;RzW`k52nTR @  ?3?39910!3!#3}9uVRR@  FY?+?391033673#"'532677d? V1%PZԏLCK2Jx@3R>Eb>Wp\R $@HYHY?+9?+910!!7!7!! {I'% J' @  &'?3/39/]3910 5477654#7267>33"3-'x;Z{<)`WF~t+ AM=HA!Ue-'y?"j]F~t+ VN#=HA!TdΥEP5mz07B,:(o;+h@ RYRY/+/+10"56323267#"&'&&X3z;l'>:o!!  ^@  QY ?+/9/103!#"&54632ݮ7^P;DbNA<VPd?߹D>MVaIpwilfϼttNfv\ES]>Kcw dAN+E<+C28`\=LuC]QG+I0<Aj>=W9$m<F?09G:/>d7rr`OwÅ}Pd /3210%P蓴?vLpLu+RY/+10#!5 +w/Rb,53@%)))5***'-)**)-  ?3?39///3]3]3104$32#"$732$54$#"%###! 32654&##^]{$%ݭۨ[UȬ[ QTHTZ[SH^Zƨ߬!# S|$EngH?I8o%/310!7!s';N   /32104632#"&&732654&#"ˆXXhJHhgIJhˆXXFhhFJhgu $@ RY B RYp/]q3+3?+10!5!3!!#5!{y}崴NJ  ?39?310!7%>54&#"'6632! oK#80[dPD^s/evsJ_RH&.4P{67x_Eon[h9#'@ ! !?3?39/]q3910#"'532654##732654#"'632mhNJǪp~zZcl]Yku\`D~|ZvbB8GJEqDAdAyZo! /1067!#a6GlB4R @  FY?+???3991032673#7##"'##3fB?q-f KWl/ BR3AHocQI>bT/3?39/10####"&563!>SEf39juVD@ @ H/?39/+310#"'53254&'73줎@6/1FEb2H@jz`(+ `TJ   ?2?9103#67'c(9}MO.P @  ?3]210#"&546632%"32654TnzXk|QgpMe~pzo  \  /3/210'7'7sH^wJrL9Pq\`LP'&{< ?55y'w&{t?5l/'!'<+u ?55uZ%-@ ##QY# MY"?+?+9/_^]9103267#"&5467667#"&54632mtkM%TQLOK̮]`'`R8C]OB?SONP0GW7&pxu@u_^UcA&$j\R $$&+55N&$Pm $?55%<@ LY LY LYLY?+?+3?9/+9/+10!!!!!!!!!#VP+T+ bMRpju5}!&&z+Fs&(CR  &+5Fs&(v}R &+5Fs&(K?R &+5F>&(j5R !!&+55?s&,C R  &+5s&,vR &+5s&,KcR &+5~>&,jgR !!&+555 -@LY LY LY?+?+9/3+310!!#73! 2$54&##!!o-q$ı^-Z}lo58ȸIZDH&1RR &+5s&2CoR &+5s&2vR $$&+5s&2KR ""&+5H&2RR %%&+5>&2jR 11&+55 @   /3/39107'}897{z7}5{{5{m'.@!"$ LY$LY?+?+9910#"''7&5$327%"&4'326}vgVٽw^ۍPkKw|LSh ^hXLDAX78Rs&8CNR &+5s&8vR &+5s&8KR &+5>&8jR ++&+55s&<vfR &+5Fd @ LY LY ??99//++10!##33232654&##dlB53a:`wyy1mb9,@1% 4GY "HYFY?+?+?+910"'532676632#"'532654&'&&54676654&#"uEH=4AS0ѳv=JkH&ƶe~~iv/XRNY[bQ^U4*Wh̠WA#,9TVc>AE::C?>>AE::Cw@GH?@IG@GH?@IG3Z&.@$% GYGY?+?+9910#"''7&54$327%"&26654'5bi{sFgV}d?X-YUL);`hJ=l`udN'#%#-!o!&XC &+5o!&Xvs ""&+5o!&XK  &+5o&Xj //&+55VR!&\v  &+5P$'@  FYFY?+?+??9910"&'##33632"32654&J^+`023T`\VVVR[U[^1̹bideVR&\j --&+55q&$M{R &+5^&DM# $$&+5Z&$NHR &+5^&DN $$&+5-N&$Q1^-f&DQ!s&&vR !!&+5^!&Fv/  &+5!s&&KR &+5^!&FK &+5!L&&OR ""&+5^&FO !!&+5!s&&LR $$&+5^*!&FL ##&+5Fs&'L\R &+5^^&G8$?55^P)Q@0IY / $FY  FY?+??_^]+?9/_^]3+3991023677!7!733##7##"&5462654&#"fZ!P%%#R]PdT\WULKim=g]еX^WkF&(MXR &+5^&HM ''&+5FZ&(N-R &+5^(&HN ''&+5F/&(OD5 &+5^&HO --&+5F-&(Q/^Ff&HQFs&(L-R &+5^G!&HL //&+5\s&*KR $$&+5w!&JK HH&+5\Z&*NR !!&+5w&JN EE&+5\L&*OR ''&+5w&JO! KK&+5;\&*9#w!&J:u EE&+5Fs&+KR &+5/q&KKF !!&+5F0@  LY  ?3?39/+9/33333103##!##7373!737!^"ʋ%//6/++תm-/?<@!   IYFY   ?3?9/]+9/3+3910!654#"##7373!!3663 yIqZ$%%D#TS]{G8sщPãj]8hH&,RR &+5/M&R  &+5z&,MR &+5/&M &+5Z&,NQR &+5/&N &+5-?&,Q-V&LQF?L&,O{R &+5/R ??10!#3Rh@&,-/&LM3his&-K>R &+5!&7K &+5F;f&.9/;&N9`/R@    ?3?3910!!#3#шM9 7V`R5Fs&/vR &+5/u&Ov  &+5F;y&/9o;d&O9Fd&/8 ?5/&O8 &+5F&/Ook/3&OO] y #@ @ LY?+?9/9103'737!FjTR՜|T\+0ukL (@ /O_ ??9/]9107#'73_OߏqXP׬7Z3{ Ds&1vPR &+5/V!&Qvq !!&+5D;&19/;Jf&Q9dDs&1LR &+5/m!&QL $$&+5.'QDj@  LY#?+??39910"'7327##!3673l@WC6C-52+j}J/Jf"#@ FYFY?+??+?910"'5327654#"#336632LH=8'Hpb Sg"\Z)r׈+Rvk:{S&2MR &+5^7&RM &+5Z&2NR &+5^7&RN &+5s&2S3R ..&+55^!&RS; ..&+55R!:@ LY LY  LY LYLY?+?+?+?+9/+10!!# $32!!!!!27&#"3TVVّN+T+`lJADq+ u5ʭ^f"/9;@ 3HY33 0# #FY **FY?3+3?3+39/+9910"&'#"&546326632!#3267"3254&%"32654&x0ړbI}/qqEo[]WWa[ci"<\\M[g&<jR &+55s&=vR &+5!&]v &+5L&=O1R &+5&]O &+5s&=LR &+5!&]L &+5@ FY FY?+?+10"'532676632&#"h[;@3>\)u`=J=ET(di+Ucۿo(@FY HY FY?+9/3+3+10"'53267#?6632&#"3#Z;@2>]%sb>J=GS%+dimGu+UcmN&.M@*LY. $@ H@ H*$$*@ H?3/+]9///+]+3333+10#!#&54632%667!#4&#"326!&'T+#gh+&5V:./<65.:1f& rBs#0Qgzz$/1019912773h]kG^ !4BQ@-_  " )@2,").)iRf^LUZQ),)5f{yfg{yi2992088˸`[WľXkfe%s&vmR &+5^!&v JJ&+5ms&vR 00&+53Z!&v? //&+5';;&69;qf&V9b+!  /3210#&'#56673+LUi~&?snD(cm!  /32103673#&'E]}qP!,!:xiIG/n/310!!F%J /3]210#"&54733267JIWX_t$?>>?BN  /104632#"&BNG5BQA4FbDT56GR4 @  / p  /3]]210#"&546324&#"326jjgh`6uj7ɨ"!@LY LY ?3+3?+10"!7!&&54$32!!7654&\zVc+)hfjEժm++맟bUjĄ~ˀn媸>&,j|R !!&+55>&<j#R &+55^h&~T' 66&+53h&T ,,&+5/Jh&T% !!&+5dh&T &+5}o&U((&+555^f -+@(FYFY!FY?3++?+?9910237673327#"'##"&5462654&#"oU*']0P"&>RT]T_WOVXf'R'D?"$ fTͶ_D [n)6@ "##"FY## FY FY ?+?+?9/+99102#"&'#66"32654##732654&}wޛQRwT2d{#'C9)AXF'7H׽ *쾘PdHNR ??39910#6336673?+;a!ɝ Fߥ@=#?*$@%% GY FY?+?+93310&54632&&#"#"&&542654'3ܸ`b]?PTZ(Rwd;R  ?3?210363#dC HGRZDVs/4@%..HY..%#'$%%$GY%?+9?9/+99310#"#6654&'&&54675&&5467##7!#"!3DLTtiT^sJ?gdoS7&$} bפPb1?VPQkq2*7,<-{Zo' H[^7dRThR"@ GYGY?+?+33?10%27#"&547!##77!##64Rlps{;&} $nd9KVhjP*#DJf"@ FYFY?+?+?910#"'#632%"32654&J혥s R8`h&FO|VZV|GwY "do^jf@  #FY?+?9310#6654&'&&54$32&#"LWvhS_WfA[Fze]cf{2:[OXR?-9%AЕJ=5w^R@ GY FY?+?+310#"&54$3!!%"3254'#Ryٗ$%^ċ9RuY1 ޗmTR@  GYFY?+?+310%27# 547!77!!JDS#w=q'r2=]jPD-+3}oR@  FY?+?310"&5473323xyGv9gH^^j$'@GY !!FY?+33?+??10&&547>32#4#">Т~i%eqco;Hzy]G!\Ѽ (al ^%@FY FY?+?+??991023327#"&'!&&#"'6pw#mF 48--LVs{+\q9 /--)P^ KBF_N@! @  GY ?3+3??3?10%63#&&54733%de wmf$p*(Ȫ=@f]?fpl^R'$@% GY#?2+3?39/910"&54733267332654'3#"'z~O]@(,sQM7>ȶ~ɇ}--yƼdXd&j &&&+55}o&j ((&+55^7h&RT $$&+5}oh&T &+5^h&T 00&+5F>&(j=R !!&+55+@LYLYLY?+?+3?9/+10"'532676654&#!#!7!!32dbD?KUZO] -+JL\edAGI=`Fs&av}R &+5!&@LYLY LY?+?+9/+10"!!327#"$32&?B)Wp`׮^KD!"* \R';6?,>&,j|R !!&+55hs-#0@"LY#LYLY LY?+?+?+9/+10#"'53266!32!!2654##<—J;<(DXSjF}X}e?2 +F)@  LY  LY ?+??39/3+310332!!!#3!2654##P|b}5|뜠|eda+#@ LY   LY ?+3?39/+104&###!7!!3 #6'W] -+JtTa1LF=DhbKFXs&vR &+5 jy&6PR &+5Fm @  # LY ?3+??3103!3!#!{1 mWVmJmN$H &@ LY  LYLY?+?+9/+102!!!!2654##Xq5+Qed{c+F%FaJo5 $@# LY  LY?+33?+?310!#3!3#!{VVrCaKPoo^ExF(B!@  ?33?33931033!##!9K NLL'#+-j(-@KY && KY& KY ?+?+9/+910!"&'532654&##732654&#"'6632jйRTm)ncZ}싵&).6sexZZyRDF@  ?3?2991033!#7#!{ݷ4 Tp{ -hJNFy&6R &+5FX @  ?3?393310!!#3!D5om/F)d@LY LY?+?+?10#"'53266!#ΰQ47-DXSjF ?2 JD0F+2FnF3!&7 j@   LY?+?39310"'53267367!nOReUQ' 2/v}k'b=vQղIs%;Dmy @ # LY?+3??310%#!3!3)V05# J@ LY ??39/+910!#"&54733273%{okDV=PD*LJD @ LY?+3?331033!3!3D5  JDm@ # LY?+33??3310%#!3!3!3V5   &@ LY  LY LY?+?+9/+102!!!7!2654&##s -@toedci\+F"@LY  LY ?+??39/+10!#3!32!!2654&##d5|X5^uo|eh]+F# @LY  LY ?+?9/+1032!!2654##h|fu5ne+&@LY LYLY?+?+9/+10% !7!74&#"'632#"&'5}j)9Gj>mPZH(PI$-/0F#*@ LY  LYLY?+?+??9/+10#"47!#3!32%"32654&ҋ5#Gm uvO* A3m!L\˯Rح $@KY  LY ?+?39/+310!&&54$!!##"33oIh[){sJ=jJJfo^fDh'$@ !GYFY?+?9/+910476$736632#"&26654#"hCZjϋ'J`QRK=4D1cȘXZ1w}oXq\^5f(-@""HY"" HY HY ?+?+9/+9102#"&54$32654&#"32654&mВqpivq~w'ՅOf;4dZ?u_OIHמ\P8G%f# @ !GYGY?+?+99106323267#"&546676654#"}WQUJc^Og`~TuC;aC:=4".!XdI%R4fJ^`)'-@ !GY FYFY?+?+9/+910#"&546323754&#"'663 27&&#"`亻~叿^ke6?Gz)rMSN\;ij."- Zh}ۃjs^fHTf;=@ 9IY;;'FY".  FY3?3+3?3+3??9/3+310##"'7326654&#"5632333632&#"327#"&557##6D=%0*_UYQ8=LRef7S6),2ZYUS2CFVe uy&) s}!!+ f%-@$%%$HY%% GY GY?+?+9/+9102654#"'632#"&'532654&##7|=ɫ{Zb\A]d'PQuJT~ntZ&!X_SHEoRXo'&X6 &+5/R @  ?3?393310!!#3uFrnR!Rb`@FY FY ?+?+?10!#&#"#"'532667>32%!H^QJWja@3$(1JEDIcxs@VAѵg1+)R@     ?33?399310#&'#!67!#0b )_=6d9LM_RZYo/R @ GY   ?3?39/+10!3#!#^_dHfRD#R^7dR/JfQPfS^fF/fPVRR\^X#+@ #GY GY ?3+3?3+3??10#&&54$73>54&'Ӥܿdg֤#]/nao]m^n`^¾Ш &ż0 v` wڀ| TR[myR!!@ !"FY?3+3??391032673327#&&'##"&547p-c $"!3}Y;:҆R^L5:""&aPҘD}hR@ FY  ??39/+910326773#667##"&5477;J=z2@ ! 6RV5GBw1n/b & $0}Xs r}Khyk+dR^L1DC9##%(}ntw;z^U.XR-@ HY GY HY ?+?+9/+910632#"&547!7!"32654&bkpqז\'H/OhcvXt`Moh2eWJEuR")@ HY !  HY ?+??39/+910632#"&547"32654&#3d}UԼ H` ]nVR-ԨVhi+$gWM@RuR$@ HY  HY ?+?9/+910632#"&5473"32654&oxtۘ»=[k jx[saXbkC4#eWJEbf4@HY <LFY FY?+?+9/_^]+102#"&'53267!7!54#"'6ԊO*x| V#>l7Bf­=!!K/d"*@ GY  FYFY?+?+??9/+10#"&57##336$32%"326654&f^= dTQZ^PL]G#RD#j{nv;R$.@""HY""HY FY?+?+?9/+910"#"'53267667&5463!#"33`?Y$KUiIG,$,>%2V4]R^maSDBHj2 6I^R;`UKFF^&Hj 99&+55/?)R@1# %&%IY&& ( FY     #(#FY?+??9/_^]]+9/3+3910!!3632#"'5327654#"##7373?D#2È&^6;:'p-Z$%fJpƝL`O0^ã%!&v ,,&+5^f&@HY FYFY?+?+9/+10"&54$32&#"!!3267זFzcp'&bji:xZZ=5$&j}-GqfV/VL/&j &+55VM`)57@ *HY''FY'FY 0HY ?+?+?+9/+910632#"&547&#"#"'532667>32"32654&Հ[qו\!=RHNQjc>3"*0IAFL\pb7NhcvYt`Mo&:juR 22&+55y^&Zj 11&+55s&<CR  &+5VR!&\C, &+5//3107!/+F+/w/3107!/++/w,2'BvBw1 ?10'673}"WzML s/ ?10#67'%R+~S_@VV/10%#6Nli_ ?10#&'7 . oڬZ |w  ?3210'63!'673 TzM{"WzM!L s ?3210#67!#67'%R+~ b3t S_@Vr&]  /2210%#6!#7Nli_ \xO '@  ??9/333933310%#73%ƞ+'"F!_DE@!    ??99//9333933333333310%%#7773%%3F--7 `-7F- wx  //104632#"&dufqmrs%o'!'1  )7CQ3@885OOO$>>.H?333?3??99//333310"326654#"&54632%#"326654#"&54632"326654#"&546327X5P4W;os|jw>5V:R6X9osjv-4W9Q4X;oqjv#zgtf͚'J%rpzc˚)sluh˚* }Pdb/10P=vL \/10'7t!ZwNnL@w' ??10#=J9@  ?3?2310654#"#36321V GFw>dT\R:My_X6>r1@NY PY NY ?+9/3+39/+10!!##73!!!!87 +_-L$O@+#$#PY$$$  PY $ $  MYNY?+3?+99//3+3_^]3+31076632&&#"!!!!!!7667#737#7m/⼾X8>^o#N!M9-6$aw !#V+ehJv73,9@ '$'PY MY"$ $"MYOY?+?+?9///++31032654##!##!227#"&547#?33#);Bt87PVptzEo1#L ,짒ɻ!+pg=\H\`ݪ>&*3'S@/PY PY p !!MY!NY?+?+99//_^]^]3+33+310"!!!!327#"5#7367#7332&&vA!n T!yx! \GXPf6jCH<=_,,7",3%@.(#?3?3??9/39/310##"&546632%"326654%"&546632&#"3267Cæ{Wm|Mdi4M-^rXb-NA<_4y/E%PJ{}o{POُ}zp' OL)d&#@$$  ?3?399//33310%2673#"&5556746324#"66@M Ti>DnX.,^Tie¶¶(ˡ`egI_7)u ,4@ !' ?3?3?399//]339910!##376737!#"&546632%"326654 '$51$ҁ##WpyXmx5P-e6N.s/VeJtsyt VHQMq&@  ?3333339/32210##5!###33#7#ǒ?ת͒RsX/yvuH@ /3/29/310"&546632!3267&&#"1RRHbٓ2Xz#5Fh)|5Bu$'&{@ ?55510W''@uu ?555d'&=@s *?555"''@? ?555`\%(@  FY GY FY?+9/++910#"&546324&#"5663227&&#"\丸Ǐ꘣Yy;AAN}&k@XU?ʬ6u(*"(CSrv) @  LY?+?910!!7!&$J{PNщ:j#XLY?+/310!#!dk}#<m#T #@ LYLY?+9/+91055!!!\fw#o5uw+ RY/+105!uwb//9/3910##5!36N +$@$&!/333/333910#"'#"&54632632267&&#""32654&N:Sx|8^0-_b>>R`\ oy+1/S@-**$RY** *@'RY RY @RY/+_^]++_^]+10"56323267#"&'&&"56323267#"&'&&X3z;l'#A8o$ uD5m%@9n !%u '@RY RY /33+3+33310#5!7!5!3!!!'^=g\ehݳGӳݴEu @  RY/+/_^]1035!75uXGyu @    RY/+/_^]1035! 5uXHX0XyRf @  //910#3 f>^=^!-- &IL&IOL' /3210#"&54733267'˱jo'5YaR FY?+?10"'53273q]6>7'&!` /10673#P9!6琝E5; /10673#W0AVADL! /10#56673La(@x>D{5 !?3?310"3254#"&546323X:VYnby|fs'qs枞"FJ %@   ??9/]33310##7!733!77z''y{4" B9݁3Ps9@  !?3?39/3102#"'532654&#"'!!6qΫ\nsedRB:K?x!7,um4C`L?>7 7%@  !?3?39/]3910632#"&54632&#"2654&#"JHxetUbR>%8OwVCX53)H/9%Z}jc[({kU8=%ED=JJL ?3?10!7!sV/Jו{j7+@ &  !?3?29102#"&547&&54632654"6654&x?L942A9:N6=0 F;1m`C'aKz|fO'[E=&2%1 }kKvVVKpKK@: HulOltZZ\QOQ KlQQlK -, 48!59/333/3339//////3]333q3+]33333222222]10!#%5!#533!5353!5!!5!5!#3#35!#35!35!#35#3#3#"&546323254#"%32##32654&##32654#"'53253T/0momImmmm0oowoooomm~smp.,;0m^{B.$*/;J1%Z^4+V}i0oo/mmmmmmoo;mmJoooo/yhIaCS1D D8QYb" "+%J fVr_cT*@ (""//9///3310 54676654&#"63232654&#"TV,AgIOGRZ?>1HT;GFBIHCHEVW/2A1R~X8*P:/5K6DpJ;?HI>@IHE!&7L &+5s/R9).9@@#,2!!2HYGY!!''7GY'GY?+?+99//_^]++3310#"&54>54#"763232&$546323654&#"*76a[Xc ;ܳ'kUNKS%0]WQ#: '^R7d]Y,E8ͳ6"lm(Cg@  KY?+??933106632&#"#3Dw՛bH=-(1drwQx h)dR+-@ ##  GY GY?2+?+339/910"&547!77!##"'4'!32677332a^'ߐ26)?>Lb#sx¶(jPd~[g^[\dL9IDu&0vT &+5/!&Pv //&+5N&$[;^f&D[72&2o\e @    /q3210#"&546324&#"326ol}jh:/.<64/:dzggzzg1771299bV ?10673#%4%#"&U?to% BG715Bi:P,%/;9=IK@'G@AA<;)66HY &2FY-"FY?3+3?3+3?33+33??9/10"'5327#?6632&#"!76632&#"3##"'5327!#34632#"&LZ;@2,ٳ,s`=J>ES,u`>J=GQ'+_6<6(J(*NE6AOB3FjL\Ƨ+VbV`Ũ+VbV㽲RDT56GR49=?@!<;"FY )66HY &2FY-?2+3?33+33?3+3??10"'5327#?6632&#"!76632&#"3##"'5327!#3LZ;@2,ٳ,s`=J>ES,u`>J=GQ'+_6<6(J(*LjL\Ƨ+VbV`Ũ+VbV㽲$"@  LY LY?+?+9910# $3 6673%"32654&V.HM) ۊ{L+ %j8fʭSΪ^$"@ !FYFY?+?+991026673#"&54$4&#"3266nGX([b[]QcaZPd9GYLZkyov# @   LY ?+?39/3106673#"&54733267)T\ /9%{H`uZ9৯m/ .@  JY  FY?+??39/+910326736673#7##"&547p-cP_,RgR^L1wtmB}!C!vRU3 /210#76654#"5632[KZ)F=Uq5[6+=Yy}  /3104632#"&NF6@OB3FDT56GR4Fs&(CR  &+5Fs&C}R &+5^!&HCn %%&+5o!&XC &+581@++  LY2''LY?3+3?3+39/910"'632#"'#"5$32&&#"32677332654&5[5XmY>xum)X7pvpsgu5)QPLJa* aw؋`T a+œ{V5JTЍfJR@ ???3393221033363##? )-6JF-RhdJfPZ/@KY LY LY?+99//+3+310!!!7!73!!3232654&##+35L)5h:luyb'c\L%'$8@ HY GY HY ?+?3+39/+910!632#"&547#7373!"32654&=>myvޖú\'--ZkjyXs_Moh2fVGHFV%1@LY!LY! LY?+?+??9/3+310"!!3267#"47!#3!!2&ϫ;@)U^^j5S װ`߿.G%$$ @6m%F\R/f$1@ GY FYFY?+?+??9/3+310"&57##336$32&&#"!!3267f^@âF0kBg,'bqd:}UV#RD=!+mz!+G %@ KY ?33?9/+3910!###!##7'&&'ێVBXT977!#&&####"!T=of\9[q:DK Ui7fT쁆L ውW=y^b]z9fR*@JY HY?+?339/33+310#6677!#&&'#"!jIyEV0+# 5F]7^p8 Qf:dTNJBmˋUbV}5f/R #3@ GY!   #HY ?+?3?9/33+3310!67!#3!7!#&&'#"!d/1g^EX1 +# =CfjEV-s\Z'#RDSiiHtkDWM?[ DjHM@(:4C8>> >4 '(('KY((F44/KY4KY/+?+39/+993_^]3910327632&#"&546%6654&##732654&#"'67&'53>32&#"jйƢl}D__CkCAs٨)ncZ&oj-NSS12(("KR}14N#&q"vqbzZZyvJt>YE$:`VZEI@'(= DEEDHY=EE7 7-GY7" @ H  HY ?+3+29?+9/9+93102654#"'67&'536632&#"32632&#"&5467>54##7z~@q(]MHdzC1-&$L:Ň}]_mۃV}NHo9Cey<$PQuJ;MR^vL 8G8lvSoX1+L ''r -I:u &@LY LY LY?+?+9/+10# $32267!"!654&V'5 G8L+ ,8H#%^7d &@HY FY GY?+?+9/+10#"&54$32267!"!54&7b#gb&aL)-ox3qw@  KY?+??910%67>32&#"!33Jbi|VBE/3=\@J ˈ?f_FbbZ@  GY ?+??9103367>32&#"!b7 1I?\oJ>*$#0=kRnË5r6 D;s&vR ""&+55bb!&vd !!&+55 &2\^d&R\V1-,@, ,LY"$&&LY ?33/+33+333310#"&'&54$7663226'#"'6E;/LE!fy,5290鳫"0*1+"Qz(!E.]{A=*`#TW@3LL6=$C=CLY!    @H   *=NI6ILY16?3+3?3299//+_^]93/3+39/310#".#"#663237654&'&&5432"'632#"'#"5$32&&#"326732654&{!!Lwf[0\u=qosA썒}&l?O5[5XȁW_%ðum)X7stVHt|a#*#p%-%^~T#= QG* axB6 a+]S^))<No@@= H<,IY<7@@ 471IY777@ H7L4    GY# GY?3+3?3+39/_^]3+]+9/++10"'#"&54632&#"3273254#"'632#".#"#663237654&'&&54632hyĉzfLEF}q^BY3x!!Lwf[0\u>qorA}$85?NSSX=-oo9+=ȝ"*"q%+%]T$?  (,I FE@" @! (99!(.(.LY(@5!5LY!?3+3?3+39/22999310#'##'##'7"'632#"'#"5$32&&#"32677332654&s t1F1F1+ 5[5XmY>xum)X7pvpsgu5)QPLJa6gggg6* aw؋`T a+œ{V5JTЍfJ $8@!##  @ H  ?33?3322+9393?10#'##'##'73363##- u3F3G2( ? )-6JF-6gggg6;RhdJfPZ!@ LY LY ?+?+?10"327#&5$32&󎨜]ifa׮^ͮ!9 (\R^f@ FYFY?+?+?10&&54$32&#"327diÙFzccZqdf`ԷZ=5hu-7o @   ?910%'%7%7%RH㴁EHJ{J;{Z}9IĤ{?J  /33210#"&5463!632W-0EEZ..BE^7%;F_.&  (,J) (6DR_m @ H  "00,&4@ H4)ZggS`IB:P@ HPE>LL7Ec^Vk@ Hk``)`EE`) @ H /2/3+9///]+2333+2333+23333+2102#&&#"#62#&&#"#662#&&#"#66!2#&&#"#662#&&#"#66!2#&&#"#662#&&#"#6!2#&&#"#66]qObvzw%ֆI GNmdPf'<@  # "" FY FY ?+??+99?999102'#"'##336"37'7654BF-"X VR cT`WQ"AajHP5} $@ LY  LY ?+?9/3+310!!!##73}+\>+ƒ냔+NoR $@ HY FY?+?9/3+3103#73!!!!/b%e+\; '`Ŵ;F.@  LY LYLY?+?+?9/+910"#!!632#"'532654&/W(5+b@X ġsk^ 0/5/ R.@FYFY FY?+?+?9/+910%#"'53254&#"#!!632Vbmnc=+X)V=N7˺/9؃VRmB+@ # LY?+??3?33931033!3###!9K āVTLL'+-{Tf;B@#$((IY &&"77FY +0+0FY+?+33?3+3???9/3+3102333632&#"327#&&557####"'7326654&#"56+ef7S6),2ZYXTNL}Tee6D=%0*_UYQ8=Lf&) u{wպ!!+ uy-j& -f&PDmV$@  #LY?+???393310%3###3!Xw5oo/F)/yR$@   "FY?+???393310!3###3u}XlrnR!RDd*@      ?3?393399910!!##373!5#R{u5H:ZFRVFHR,@  ?3?3993399910!#3737!!#'1oiC  9$K=Rl@>^kFm2@ LY  ?3?39/]3+3910!!##73733#!?u+#"+JbL˟^/-@IY   ?3??99/3+310373!!3!!##%'%B((#шMfı|` #@  LY?+?3?93310!!#!7!! +3nl/F)L/R #@   GY ?+?3?93310!!#!7!!Jt'=nR!Fm%@ LY   #LY?+???39/+10%3##!#3!3߁Vʋ56mV/yR%@ GY " FY ?+???39/+10!33##!#^_}XdHfRDq#RF $@ LY   LY ?+?3?9/+10#!#3!!`ʋ56-)mV/R $@ GY   GY?+?3?9/+10!!!#!#^_C)dHfRDh#RFq0@ LY LYLY?+?+?39/+910!#!#!632#"'5326654&#"; 5@Zt~}lS.c13 / %R0@FYGY FY ?+?+?39/+910632#"'532654&#"#!#!#N;ˍXggkd>.Xdnm/9؂VhR+5K@+,# ))1KY))`) )) LY @LY!LY?+?++9/_^]+910327#"'#"$32&#"337&54632654#"%8AJ>ffZwYڄtFS_ꃠLrπ%n[Q{!n^*  /#ϭ·+1Q5Ȓ^{f,7S@- $**2HY***@ H** HY @GY"GY?+?++9/+_^]+910327#"'#"&54$32&#"337&&546326654#"{m)7>BRk]pٓ2n$5@KfXi_%ɤ}J^D>MHC P"E z|(}K5fbn5a-!&&;^-f&Fm @# LYLY?+?+3?10%3##!7!!;܁V-+/yf34@11$."))FY/GY?+??3+3??393310236632327#&54766'4#"#654#"#336'"KgJ"*2{X02wl+eun-b ftw7u"!"$'=8$R-+R<dPR   ??3910%673#33V/hi7 7TN\%@  LY  ??39/3+3910!!!#!7!73F %+AB+o!7%PR!@   HY ?3+3??3910%673!!##733(c/ 'AB'7e7:R.m% @  #LY?+???39910%3##!3!ׁVyJJ P:{qR @ " FY?+???39910!3!3##3|Xn}9umV'@ # LY  LY?+3?+3??10%#!!7!!!3V/ ++! ZyR&.@$"#$#GY $FY?3+3?3+3?910326673327#&&'##"&547!7!^h}Jpb#(4{Z<=Ɇa''Q0pՎ"! &aPҗVmǺoJ)@ LY #LY?+??39/+910###"&5473326733V{vPso ^XoD0&?@ 02*"{hR)@FY " FY?+??39/+91032733####"&547=F?b}X{8RL3BGwqMoJ2@   LY ??39/+339/9/910!#"&54733673%{|WDA uq KPHE[zD4+2>-.&DEP0JqR2@FY ??39/+339/99/103673#>7##7"&547(+i77N? %Rh718RwHXy10k&随KtD@LY ?3?9/+9106632#654#"#3J ur ^V5q4$4=/'*"R/R@ GY  ?3?9/+910!674&#"#33632> DA]+," 7#1NAHJuRzXv^%%/3@ ) LY) ) )&LYLY?+?+99//3+310!2!#3267#"47&&54733"3 $54&Q ^ThV|rm>/T9I."dJ*Y7%1.#) KtilQM/TT XHVV|PVʆNPjlQM32%!H^QJWja@3$(1JEDIcxs@VAѵg1+F$@ LY LY  ??3?+9/+10"'53267!#3!3t2oʋ56A13mV/ R"@GY FY?+??39/+10!3#"'53267!#^_<ˊdlrs'ZHfRD5=#RFm%@ LY   #LY?+???39/+10%3!#!#3!3܌ʋ56mV/{R%@ GY " GY ?+???39/+10!33##!#^_dHfRDf#RmJ)@LY#LY?+??39/+910!#3#"&5473326733VPvP uq ^Vm\{0&2>-.&*"JyR)@FY " FY ?+??39/+910326773##3667##"&546>z-R⃿!BRP/uyJx7$[=Dm&@  # LY?+??3?399310!##!3!3!#67#s95Cm^XϦG }}a'"B){R(@   "GY?+??3?393910#&'#!67!3##0c )_Ay9ѾLSZRZOsd?,y&$6yR &+5^'&D61 $$&+5o>&$jXR $$&+55^&Dj 66&+55%^fFy&(6LR &+5^'&H6 ''&+5L"&@KY LY LY ?+?+9/+10"5663 #"&54$!3654&267# kzhCaV-'F4&ևHX7f #&@HY GY HY?+?+9/+10%267#"2#"&54$!3754&#"566a"@ݛM4+pqFfala39o~$0.$L>&jR 88&+557&j 99&+55B>&jTR ''&+55T&jX QQ&+55j>&jR >>&+55 &j ;;&+55q(@LY KY?+?9/33+910!"&'532654&##7!7!VcJPT…%+<#? '(-7ihϨR1@IYGY FY?+?+99/+910#"'532654&##7!7!ѧǑɖśg#)!ѪL\}F&MR &+5o&XM/ &+5F>&jR %%&+55o&Xj //&+55>&2jR 11&+55^7&Rj 11&+55~^7d>&~jR 55&+55^7&j 44&+55>&jR 22&+55j&jS 11&+55 j&MdR &+5VR&\M &+5 j>&j9R ++&+55VR&\j --&+55 js&SR ((&+55V~!&\S **&+55J>&jR **&+55h&j 00&+55Fm @# LY LY?+?+?10!3##+ہV5/yR @"FYFY?+?+?103!!3#/)\{XR4F>&j;R --&+55u&j 88&+55)D}4@KY LY LY  LY?+?9/3+3++10"'53277##73!!!!3V773h郔++\>+TK!DmoNrDR8@ HY FY FY FY ?+?++9/3+310"'53277##73!!!!3Z247e b%e+\; '7F!DmŴD%(@  KY  LY ?3+?3+9910"'53277#!3!3V774g{JJ پL!DmP:DTR)@  FY   FY ?+??3+9910"'53277#!3!3Y473iq3F!Dm}9u%)@  LY ?3?39/3+39910!!#7!3!!J+ -+mPXTR)@  HY ?3?39/3+3991033!3##!#&u;#}N @ KYLY?+?9/+104$!33!"&#"33N=}uRJ҇^GR^(1@ LY % %LY ?3+3?9/+9/910#"&'#"&54!333267#"3267^d)־j%KeQ v} LBPa_V[QXuP!NGODR$EGlmS[e\^j#0.@ +FY$$FY ?3+3?+?999/1032673#"&'##"&5463236732654&#"JF[`;C,ѷ ڡZ,L U]V\VW?EPx~Ӿo[ҹcZX`d4Ȥ[n`-6@+KY++&KY+ LY?+?+9/+99/1032673#"&54654&##732654&#"'6!2;{nFLSaZd+ö }'h[^}%oOMj!̹#R3b[UWnf'6@ %HY GY  FY ?+?+9/+99/1032673#"&574&##732654#"'6327Z`?D)ĭYr'vw@²j?qt-ÒBQFNQwJT=mu'0@ KY '#KY$LY?+?+?9/+910!#654&##732654&#"'66323#bN}})i`[xcԸ $hS[byU[yRDT`sP{f$0@!HY"GYFY?+?+?9/+9103##654&##732654#"'632L}V; b['ss?IJV`o1b0(L=POwJTkg$'@ $$LY$LY?3+3?+9/1032673#"&547!#"'53266NTeZf*­чΰQ47-DXSjF]+m}#ʽMo?2 T`.+@**FY*!FY FY ?+?+?+9/1032673#"&547&#"#"'532667>32IDT^!;F+j%!H^QJWja@3$(1JEDIcxs 9GHd̹?<@VAѵg1+a5FP,@LY LY ?+??39/+9/1032673#"&5477!#3!3VcZd-տ%ʋ56?pz#ι?smVK/R,@GYFY?+??39/+9/10!#3!332673#"&5469Hf^_ LFV`;=4ܻ#RDJ:'EFnȥ5w&@LY LY LY?+?+9/+10!# $32&&#"3267!g.rZfU(,Z2$ȷ^f&@GY FY GY?+?+9/+10!#"&54$32&#"3267!w:.ّVr|j|ATJ|%@LY LY?+?+39/107!!32673#"&547--}IISc[d-տK AHh#ι?cZR%@ GY FY ?+?+39/1032673#"&547!7!!IDT^!32F!Y255e %!H^QJWja@3$(1JEDIcxsm@VAѵg1+yN&$g^yf&DgN&$fR &+5^&Df %%&+5&$wR &+55^^&Dw ++&+55q&$xR &+55^&Dx ++&+55`;&$yR &+55^ &Dy ++&+55b&$zR 00&+55^&Dz BB&+55ys&$'gKZR &+5^y!&D'gK --&+5&${R &+55^&D{ !!&+55&$|R &+55^&D| **&+55X&$}R ""&+55^&D} 44&+55b&$~R $$&+55^&D~ 66&+55yZ&$'NHRg &+5^y&D&Ng $$&+5Fy&(g^yf&HgF&(fR &+5^&Hf ((&+5FH&(RPR &+5^K&HR --&+5F&(wR &+55^A&Hw ..&+55F&(xR &+55^&Hx ..&+55FC;&(yR &+55^&Hy ..&+55Fb&(zR --&+55^d&Hz EE&+55Fys&('gK?R &+5^y!&H'gK 00&+5E&,fR &+5/&f &+5y?&,gyV&Lgdy&2gB^y7d&Rg&2fR  &+5^7&Rf  &+5'&2wqR &&&+55^N&Rw &&&+55&2xoR &&&+55^7&Rx &&&+55;&2yoR &&&+55^&Ry &&&+55b&2zoR ==&+55^q&Rz ==&+55ys&2'gBKR ((&+5^y7!&R'gK ((&+5s&_vR --&+5^!&`v? ,,&+5s&_CoR &&&+5^!&`C %%&+5&_fR ((&+5^&`f ((&+5H&_RR ..&+5^&`R --&+5y&_gB^y&`gy&8g%oyR&Xg&8ffR &+5o&Xf &+5#s&avR &&&+5m/!&bvb ((&+5#s&aC?R &+5m/!&bC !!&+5#&afhR !!&+5m/&bf $$&+5#H&aRR ''&+5m/&bR1 ))&+5y#&ag%my/&bgy&<gjVRR&\g&<fR  &+5VR&\f; &+5H&<RR &+5VR&\R !!&+5P&B3 ! /3210#&&'53#&&'53<"*Yl@ *Y=B+$7:R)MD"=@#  /?@H/3+]9///33]310".#"#63232673"&5332673%KFAHu2$LHB&,s:}WVWd"1 V"..Ab- /2102654'3#"'5?08ZstJ5,66\wsivD  /210"'532673-Y2423DFN!D^+{ @ MY&MY?+?+10"32654#"&54$32VSؓQ7f @   ??9/910!#7'3QV",Wkol,:w?{@ MY&NY?+9?+10!!76654&#"'6632!mr#|EHOWpu.Q9LODnQ|u~vf %@OY $??9/33+3910%##!7!3!667#ӼNN%ÿ^'1JXoso$y!+ifdi?Q&P98@"FY )66HY &2FY-?2+3?33+33?3+310"'5327#?6632&#"!76632&#"3##"'5327!LZ;@2,ٳ,s`=J>ES,u`>J=GQ'+_6<6(J(jL\Ƨ+VbV`Ũ+VbV㽲w 16@ )!!-&&'/##'*'?33/33]2/39910#"'53254&'&&54632&#"##33#7#=wzJj\u/VbL~kcj+WF-85LnFլ̑ds%/Z#/%,`G[p.n'*&%/!3YoT/y&7zN\%H&Wz'f -.@($)$FY$FYFY?+?+?+?9910%2654&#""'5326?##"&54632373S_XTVYT؊GTu1TZ`1@/ ahfejD(0qr@lZϴdV\'!&K 44&+5'&N 11&+5'&O# 77&+5'!&:{ 11&+5Fh ??1033F7JFvs&CR &+5Fs&vR  &+5Fis&K>R  &+5F`>&jIR &+55FH&RKR  &+5FM&MWR &+5FxZ&N.R &+5-h&QTFL&O^R  &+5Fh'-`A 'T?5FhF\>&jER &+55FhF\>&jER &+55FhFhF!&fR &+5yh&g{2I6$$q7)9):)<DFGHJPQRSTUVXqqqqqqqqq !$)&)+-/1356)8:CqDFHJVq_qbqiqyz{~qqqq)))WXqY`bjrqsq}qqqq q  q qqqq !q"#q%q&'q()q*+q,-q./q01q23q468:<@BDJLNRTVXZ\^`bdfhjlnoqs) $q 7) 9) :) < D F G H J P Q R S T U V X q q q q q q  q q q           ! $) &) + - / 1 3 5 6) 8 : Cq D F H J Vq _q bq iq y z { ~              q    q  q       q ) ) )  W Xq Y ` b j rq sq }         q q  q  q         q   q   q    q q  q  !q " #q %q & 'q ( )q * +q , -q . /q 0 1q 2 3q 4 6 8 : < @ B D J L N R T V X Z \ ^ ` b d f h j l n o q s ) -&*247q89:<$q&q*,.02468:Gfmqqrsuxqqq\qT_al|\~qqq\\\\ qIKMOQSUWY[]_acegikmoqsq7$&q&*247q89:<$q&q*,.02468:Gfmqqrsuxqqq\qT_al|\~qqq\\\\ qIKMOQSUWY[]_acegikmoqsq$q$ q$&$*$- $2$4$7q$9$:$<$$$$$$$$$$$$$$$$$$$$$$q$&q$6$8$:$G$$$$$q$ q$_$I$K$M$O$Q$S$U$W$Y$[$]$_$o$q$s$q%%%$%7%9%:%;%<%=%%%%%%%%%%%$%&%6%8%:%;%=%?%C%%%%%%% %X%%%!%#%%%'%)%+%-%/%1%3%o%q%s%&&&*&2&4&&&&&&&&&&&&&&&&&&&&G&_&I&K&M&O&Q&S&U&W&Y&[&]&_'''$'7'9':';'<'='''''''''''$'&'6'8':';'='?'C''''''' 'X'''!'#'%''')'+'-'/'1'3'o'q's'(-{)))"))$))))))))))C)) )X)))!)#)%)')))+)-)/)1)3.&.*.2.4....................G._.I.K.M.O.Q.S.U.W.Y.[.]._/\/ \/&/*/2/4/7/8/9/:/</////////////////////////$/&/*/,/./0/2/4/6/8/:/G/////\/ \/_/a/I/K/M/O/Q/S/U/W/Y/[/]/_/a/c/e/g/i/k/m/o/q/s/222$27292:2;2<2=22222222222$2&26282:2;2=2?2C2222222 2X222!2#2%2'2)2+2-2/21232o2q2s2333$3;3=3333333333;3=3?3C33 3X333!3#3%3'3)3+3-3/3133444$47494:4;4<4=44444444444$4&46484:4;4=4?4C4444444 4X444!4#4%4'4)4+4-4/41434o4q4s47777")7$q7&7*727477)7D\7Fq7Gq7Hq7Jq7P7Q7Rq7S7Tq7U7V7X7Y7Z7[7\7]7q7q7q7q7q7q77777777q7\7\7\7\7\7\7q7q7q7q7q7q7q7q7q7q7q777777q7\7q7\7q7\77q77q77q77q7q7q7q7q7q7q7q77q77q77q77q7777 77q77q77q77q7777!7$)7&)7+7-7/717375777<7>7@7Cq7D\7F\7G7Hq7J7777777 7W7Xq7Y\7_7`q7b7q7\7q7 \7!q7"\7#q7%q7&\7'q7(\7)q7*\7+q7,\7-q7.\7/q70\71q72\73q74\76q78q7:q7<@<C<D<F<G<H<J<< <W<X<Y<_<`<b<<<< <!<"<#<%<&<'<(<)<*<+<,<-<.</<0<1<2<3<4<6<8<:<<<@<B<D<I<J<K<L<M<N<O<Q<R<S<T<U<V<W<X<Y<Z<[<\<]<^<_<`<b<d<f<h<j<l<n=&=*=2=4====================G=_=I=K=M=O=Q=S=U=W=Y=[=]=_>-DD DD EE EYEZE[E\E]EE7E<E>E@EEEE EpF)F )F)F )HH HYHZH[H\H]HH7H<H>H@HHHH HpI{I {I{I {KK KK NFNGNHNRNTNNNNNNNNNNNNNNNNNNNNNNNNNNNNHN`N6N8N:N<N@NBNDNJNLNNNRNTNVNXNZN\N^N`PP PP QQ QQ RR RYRZR[R\R]RR7R<R>R@RRRR RpSS SYSZS[S\S]SS7S<S>S@SSSS SpURU RUDUFUGUHUJURUTUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUDUFUHURU RUYU`UU U"U&U(U*U,U.U0U2U4U6U8U:U<U@UBUDUJULUNURUTUVUXUZU\U^U`W)W )W)W )YRY RYYY")YRYY RY ZRZ RZZZ")ZRZZ RZ [F[G[H[R[T[[[[[[[[[[[[[[[[[[[[[[[[[[[[H[`[6[8[:[<[@[B[D[J[L[N[R[T[V[X[Z[\[^[`\R\ R\\\")\R\\ R\ ^-q q&*- 247q9:<$q&q68:Gq q_IKMOQSUWY[]_oqsqq q&*- 247q9:<$q&q68:Gq q_IKMOQSUWY[]_oqsqq q&*- 247q9:<$q&q68:Gq q_IKMOQSUWY[]_oqsqq q&*- 247q9:<$q&q68:Gq q_IKMOQSUWY[]_oqsqq q&*- 247q9:<$q&q68:Gq q_IKMOQSUWY[]_oqsqq q&*- 247q9:<$q&q68:Gq q_IKMOQSUWY[]_oqsq-{&*24G_IKMOQSUWY[]_-{-{-{-{$79:;<=$&68:;=?C X!#%')+-/13oqs$79:;<=$&68:;=?C X!#%')+-/13oqs$79:;<=$&68:;=?C X!#%')+-/13oqs$79:;<=$&68:;=?C X!#%')+-/13oqs$79:;<=$&68:;=?C X!#%')+-/13oqs$79:;<=$&68:;=?C X!#%')+-/13oqs$79:;<=$&68:;=?C X!#%')+-/13oqs$C X!#%')+-/13$C X!#%')+-/13$C X!#%')+-/13$C X!#%')+-/13")$&*24DFGHJPQRSTUVX] !+-/135<>@CDFGHJ WXY_`b !"#%&'()*+,-./0123468:<@BDIJKLMNOQRSTUVWXYZ[\]^_`bdfhjln$;=;=?C X!#%')+-/13             YZ[\]7<>@ p YZ[\]7<>@ p YZ[\]7<>@ p YZ[\]7<>@ p YZ[\]7<>@ p YZ[\]7<>@ p YZ[\]7<>@ p YZ[\]7<>@ p   YZ[\]7<>@ pR R")R R  YZ[\]7<>@ pR R")R R q q&*- 247q9:<$q&q68:Gq q_IKMOQSUWY[]_oqsq  q q&*- 247q9:<$q&q68:Gq q_IKMOQSUWY[]_oqsq  q q&*- 247q9:<$q&q68:Gq q_IKMOQSUWY[]_oqsq  &*24G_IKMOQSUWY[]_&*24G_IKMOQSUWY[]_&*24G_IKMOQSUWY[]_&*24G_IKMOQSUWY[]_$79:;<=$&68:;=?C X!#%')+-/13oqsR R "@E=K=N=O=`={R R$79:;<=$&68:;=?C X!#%')+-/13oqs-{ YZ[\]7<>@ p-{ YZ[\]7<>@ p-{ YZ[\]7<>@ p-{ YZ[\]7<>@ p-{ YZ[\]7<>@ p  &*24G_IKMOQSUWY[]_FGHRTH`68:<@BDJLNRTVXZ\^`FGHRTH`68:<@BDJLNRTVXZ\^`\ \&*24789:<$&*,.02468:G\ \_aIKMOQSUWY[]_acegikmoqs\ \&*24789:<$&*,.02468:G\ \_aIKMOQSUWY[]_acegikmoqs\ \&*24789:<$&*,.02468:G\ \_aIKMOQSUWY[]_acegikmoqsR R "@E=K=N=O=`=R R\ \&*24789:<$&*,.02468:G\ \_aIKMOQSUWY[]_acegikmoqs\ \&*24789:<$&*,.02468:G\ \_aIKMOQSUWY[]_acegikmoqs  $79:;<=$&68:;=?C X!#%')+-/13oqs$79:;<=$&68:;=?C X!#%')+-/13oqs$79:;<=$&68:;=?C X!#%')+-/13oqs-{R RDFGHJRTDFHR RY` "&(*,.02468:<@BDJLNRTVXZ\^`R RDFGHJRTDFHR RY` "&(*,.02468:<@BDJLNRTVXZ\^`R RDFGHJRTDFHR RY` "&(*,.02468:<@BDJLNRTVXZ\^`$$$$")$$q$&$*$2$4$7)$D\$Fq$Gq$Hq$Jq$P$Q$Rq$S$Tq$U$V$X$Y$Z$[$\$]$q$q$q$q$q$q$$$$$$$$q$\$\$\$\$\$\$q$q$q$q$q$q$q$q$q$q$q$$$$$$q$\$q$\$q$\$$q$$q$$q$$q$q$q$q$q$q$q$q$$q$$q$$q$$q$$$$ $$q$$q$$q$$q$$$$!$$)$&)$+$-$/$1$3$5$7$<$>$@$Cq$D\$F\$G$Hq$J$$$$$$$ $W$Xq$Y\$_$`q$b$q$\$q$ \$!q$"\$#q$%q$&\$'q$(\$)q$*\$+q$,\$-q$.\$/q$0\$1q$2\$3q$4\$6q$8q$:q$&@&Cq&D\&F\&G&Hq&J&&&&&&& &W&Xq&Y\&_&`q&b&q&\&q& \&!q&"\&#q&%q&&\&'q&(\&)q&*\&+q&,\&-q&.\&/q&0\&1q&2\&3q&4\&6q&8q&:q&(@(Cq(D\(F\(G(Hq(J((((((( (W(Xq(Y\(_(`q(b(q(\(q( \(!q("\(#q(%q(&\('q((\()q(*\(+q(,\(-q(.\(/q(0\(1q(2\(3q(4\(6q(8q(:q(8@8C8D8F8G8H8J88 8W8X8Y8_8`8b8888 8!8"8#8%8&8'8(8)8*8+8,8-8.8/808182838486888:8<8@8B8D8I8J8K8L8M8N8O8Q8R8S8T8U8V8W8X8Y8Z8[8\8]8^8_8`8b8d8f8h8j8l8n9R9 R999")9R99 R9 :::"):$:&:*:2:4:D:F:G:H:J:P:Q:R:S:T:U:V:X:]:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::!:+:-:/:1:3:5:<:>:@:C:D:F:G:H:J:: :W:X:Y:_:`:b:::: :!:":#:%:&:':(:):*:+:,:-:.:/:0:1:2:3:4:6:8:::<:@:B:D:I:J:K:L:M:N:O:Q:R:S:T:U:V:W:X:Y:Z:[:\:]:^:_:`:b:d:f:h:j:l:n;&;*;2;4;;;;;;;;;;;;;;;;;;;;G;_;I;K;M;O;Q;S;U;W;Y;[;];_=&=*=2=4====================G=_=I=K=M=O=Q=S=U=W=Y=[=]=_?&?*?2?4????????????????????G?_?I?K?M?O?Q?S?U?W?Y?[?]?_CqC qC&C*C- C2C4C7qC9C:C<CCCCCCCCCCCCCCCCCCCCC$qC&qC6C8C:CGCCCCCqC qC_CICKCMCOCQCSCUCWCYC[C]C_CoCqCsCqDD DD E-{GGG$G7G9G:G;G<G=GGGGGGGGGGG$G&G6G8G:G;G=G?GCGGGGGGG GXGGG!G#G%G'G)G+G-G/G1G3GoGqGsGVqV qVfVmVqqVrVsVuVxVqV qVT[[[V[_[b[d[i[p[q[r[t[u[x[[[ [T\\\V\_\b\f\i\m\s\v\y\z\{\|\}\~\\\\\\\\\\\\\\\\\\\\ \!]q]r]x]T^^ ^^ _q_ q_f_m_qq_r_s_u_x_q_ q_T```V`_`b`i`t`` aaaaV\a_\ab\afai\amasavayqaza{a|a}a~qaaaaaaaaaqaaqaqaaqaaaaaqaaaaaaa a!aSbqb qbfbmbqqbrbsbubxbqb qbTdfdmdsfffVf_fbfdfifpfqfrftfufxfff fThfhmhshhiqi qifimiqqirisiuixiqi qiTmmmVm_mbmdmimpmqmrmtmumxmmm mToooVo_obodoiotooo qqqqV\q_\qb\qfqi\qmqsqvqyqqzq{q|q}q~qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq q!qSrrrVr_rbrfrirmrsrvryrzr{r|r}r~rrrrrrrrrrrrrrrrrrrr r!sssVs_sbsdsispsqsrstsxsss sTtftmtsttuuuVu_ubufuiumuu vqvrvxvTxxxVx_xbxfxixmxsxvxyxzx{x|x}x~xxxxxxxxxxxxxxxxxxxx x!y){{ {{ || |||| ~) y~     y~ y~         y~       n| q)qqqqqq jqklmqrqsuwy}~qqqqqqq)qqqqqqqqq q q q qqql~    n|   n|   n| l|~  qff jlrqs~ffqqq q  q q qqq qn|q qq  r|  q)qqqqqq jqklmqrqsuwy}~qqqqqqq)qqqqqqqqq q q q qqq)l|~    l|~   rsz|  rsv  l~  q)qqqqqq jqklmqrqsuwy}~qqqqqqq)qqqqqqqqq q q q qqqqff jlrqs~ffqqq q  q  rsz l|~  ))  n|   n|  rsz|  rsz|   ) js      j  )j       js   s  j        m  m         js    m  m  j   sq)qqqqqq jqklmqrqsuwy}~qqqqqqq)qqqqqqqqq q q q qqq js  ")$&*24DFGHJPQRSTUVX !+-/135CDFGHJ WXY_`b !"#%&'()*+,-./0123468:<@BDIJKLMNOQRSTUVWXYZ[\]^_`bdfhjlnR R")R R ")$&*24DFGHJPQRSTUVX !+-/135CDFGHJ WXY_`b !"#%&'()*+,-./0123468:<@BDIJKLMNOQRSTUVWXYZ[\]^_`bdfhjlnR R")R R ")$&*24DFGHJPQRSTUVX !+-/135CDFGHJ WXY_`b !"#%&'()*+,-./0123468:<@BDIJKLMNOQRSTUVWXYZ[\]^_`bdfhjlnR R")R R ")$&*24DFGHJPQRSTUVX] !+-/135<>@CDFGHJ WXY_`b !"#%&'()*+,-./0123468:<@BDIJKLMNOQRSTUVWXYZ[\]^_`bdfhjlnR R")R R 7$&q7$&q7$&q$q7)9):)<DFGHJPQRSTUVXqqqqqqqqq !$)&)+-/1356)8:CqDFHJVq_qbqiqyz{~qqqq)))WXqY`bjrqsq}qqqq q  q qqqq !q"#q%q&'q()q*+q,-q./q01q23q468:<@BDJLNRTVXZ\^`bdfhjlnoqs)$q7)9):)<DFGHJPQRSTUVXqqqqqqqqq !$)&)+-/1356)8:CqDFHJVq_qbqiqyz{~qqqq)))WXqY`bjrqsq}qqqq q  q qqqq !q"#q%q&'q()q*+q,-q./q01q23q468:<@BDJLNRTVXZ\^`bdfhjlnoqs)&*247q89:<$q&q*,.02468:Gfmqqrsuxqqq\qT_al|\~qqq\\\\ qIKMOQSUWY[]_acegikmoqsq $q 7) 9) :) < D F G H J P Q R S T U V X q q q q q q                        q  q  q                             ! $) &) + - / 1 3 5 6) 8 : Cq D F H J Vq _q bq iq y z { ~              q    q  q       q ) ) )  W Xq Y ` b j rq sq }         q q  q  q         q    q    q    q q  q   !q " #q %q & 'q ( )q * +q , -q . /q 0 1q 2 3q 4 6 8 : < @ B D J L N R T V X Z \ ^ ` b d f h j l n o q s ) & * 2 4 7q 8 9 : <                         $q &q * , . 0 2 4 6 8 : G f m qq r s u x  q  q   q  \ q        T _ a l |\ ~        q    q    q  \  \    \     \        q  I K M O Q S U W Y [ ] _ a c e g i k m o q s q!q!r!x!TSSSS TTTVT_TbTfTiTmTsTvTyTzT{T|T}T~TTTTTTTTTTTTTTTTTTTT T!XqX qX&X*X- X2X4X7qX9X:X<XXXXXXXXXXXXXXXXXXXXX$qX&qX6X8X:XGXXXXXqX qX_XIXKXMXOXQXSXUXWXYX[X]X_XoXqXsXqYY YY ZZZVZ_ZbZdZiZpZqZrZtZuZxZZZ ZT`IR`WR`Yf`Zf`[f`\f`f`%R`'R`7f`f`f`4R`5R`]R`^R`pf`R`RbIfbWfbYfbZfb[fb\fbfb%fb'fb7fbfbfb4fb5fb]fb^fbpfbfbfjj jj llllllllllllllllllllll lrlslzl|lllllllllllllllllllllllllllll llllllmmmmmmm msmmmnn nnnnnnnnn n|nnnnnnnnnnnnnnn nnnoo ooooooooo omooooooooooooooooooooooooooopppppplp~ppppppppppppppppp p ppprqr qrrrqrrrrrrrqr qrnr|rrrrrrrrqrrrrrrrrrrrrrrrrrrr qrrqrrrsqs qssssssssssssqs qsjsms}sssssssssssssssssssssssssssss s ssssstqt qtttqtttttttqt qtnt|ttttttttqttttttttttttttttttt qttqtttuqu quuuuuuuuuuuuqu qujumu}uuuuuuuuuuuuuuuuuuuuuuuuuuuuu u uuuuuv vx xzzzz zzzzz z|q|q||||||||q| q|r|s|||||| | ||||}} }}}}}}}}} }}}}}}}}}}}}}}}}}}}~~~~~~~~~~~~~~~~~~~~~~ ~r~s~z~|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~  qff jlrqs~ffqqq q  q  sqff jlrqs~ffqqq q  q  s s s rsz|    rsz|    rsz|  sl~  )    |   m rsv    )))))) jklqrsuwy}~)))))    ) js   f |   l{=}~j    )l{=}~j  l|~  j  l|~  j  l|~  j  )  )))))) jklqrsuwy}~)))))    ) js  \ \fH\ \|qqH HHq qq qmqq   l~  q)qqqqqq jqklmqrqsuwy}~qqqqqqq)qqqqqqqqq q q q qqq js  )) jklqrsuwy}~))     s)) jklqrsuwy}~))     sl{=}~j  )  )    |         l|~  j   f m| )  )  )  q qqq qn|q qq  q qqq qn|q qq       rsz|    rsz|   l|~  j    )   rsz|    rsz|    rsz|    rsz|   qff jlrqs~ffqqq q  q  sqff jlrqs~ffqqq q  q  sqff jlrqs~ffqqq q  q  sq)qqqqqq jqklmqrqsuwy}~qqqqqqq)qqqqqqqqq q q q qqq js  )))))) jklqrsuwy}~)))))    ) js  l{=}~j  l|~  j          q             r v |       q                                                                           q             r v |       q                                      )   q rv|q    q rv|q    r    r|   )  q q&*- 247q9:<$q&q68:Gq q_IKMOQSUWY[]_oqsq  q q&*- 247q9:<$q&q68:Gq q_IKMOQSUWY[]_oqsq     !q! q!&!*!- !2!4!7q!9!:!<!!!!!!!!!!!!!!!!!!!!!$q!&q!6!8!:!G!!!!!q! q!_!I!K!M!O!Q!S!U!W!Y![!]!_!o!q!s!q"" "" #q# q#&#*#- #2#4#7q#9#:#<#####################$q#&q#6#8#:#G#####q# q#_#I#K#M#O#Q#S#U#W#Y#[#]#_#o#q#s#q$$ $$ %q% q%&%*%- %2%4%7q%9%:%<%%%%%%%%%%%%%%%%%%%%%$q%&q%6%8%:%G%%%%%q% q%_%I%K%M%O%Q%S%U%W%Y%[%]%_%o%q%s%q&& && 'q' q'&'*'- '2'4'7q'9':'<'''''''''''''''''''''$q'&q'6'8':'G'''''q' q'_'I'K'M'O'Q'S'U'W'Y'[']'_'o'q's'q(( (( )q) q)&)*)- )2)4)7q)9):)<)))))))))))))))))))))$q)&q)6)8):)G)))))q) q)_)I)K)M)O)Q)S)U)W)Y)[)])_)o)q)s)q** ** +q+ q+&+*+- +2+4+7q+9+:+<+++++++++++++++++++++$q+&q+6+8+:+G+++++q+ q+_+I+K+M+O+Q+S+U+W+Y+[+]+_+o+q+s+q,, ,, -q- q-&-*-- -2-4-7q-9-:-<---------------------$q-&q-6-8-:-G-----q- q-_-I-K-M-O-Q-S-U-W-Y-[-]-_-o-q-s-q.. .. /q/ q/&/*/- /2/4/7q/9/:/</////////////////////$q/&q/6/8/:/G/////q/ q/_/I/K/M/O/Q/S/U/W/Y/[/]/_/o/q/s/q00 00 1q1 q1&1*1- 121417q191:1<111111111111111111111$q1&q16181:1G11111q1 q1_1I1K1M1O1Q1S1U1W1Y1[1]1_1o1q1s1q22 22 3q3 q3&3*3- 323437q393:3<333333333333333333333$q3&q36383:3G33333q3 q3_3I3K3M3O3Q3S3U3W3Y3[3]3_3o3q3s3q44 44 5-{66 6Y6Z6[6\6]6676<6>6@6666 6p7-{88 8Y8Z8[8\8]8878<8>8@8888 8p9-{:: :Y:Z:[:\:]::7:<:>:@:::: :p;-{<< <Y<Z<[<\<]<<7<<<><@<<<< <p=-{>> >Y>Z>[>\>]>>7><>>>@>>>> >p?-{@@ @Y@Z@[@\@]@@7@<@>@@@@@@ @pA-{BB BYBZB[B\B]BB7B<B>B@BBBB BpC-{DD DYDZD[D\D]DD7D<D>D@DDDD DpIII$I7I9I:I;I<I=IIIIIIIIIII$I&I6I8I:I;I=I?ICIIIIIII IXIII!I#I%I'I)I+I-I/I1I3IoIqIsIJJ JYJZJ[J\J]JJ7J<J>J@JJJJ JpKKK$K7K9K:K;K<K=KKKKKKKKKKK$K&K6K8K:K;K=K?KCKKKKKKK KXKKK!K#K%K'K)K+K-K/K1K3KoKqKsKLL LYLZL[L\L]LL7L<L>L@LLLL LpMMM$M7M9M:M;M<M=MMMMMMMMMMM$M&M6M8M:M;M=M?MCMMMMMMM MXMMM!M#M%M'M)M+M-M/M1M3MoMqMsMOOO$O7O9O:O;O<O=OOOOOOOOOOO$O&O6O8O:O;O=O?OCOOOOOOO OXOOO!O#O%O'O)O+O-O/O1O3OoOqOsOQQQ$Q7Q9Q:Q;Q<Q=QQQQQQQQQQQ$Q&Q6Q8Q:Q;Q=Q?QCQQQQQQQ QXQQQ!Q#Q%Q'Q)Q+Q-Q/Q1Q3QoQqQsQSSS$S7S9S:S;S<S=SSSSSSSSSSS$S&S6S8S:S;S=S?SCSSSSSSS SXSSS!S#S%S'S)S+S-S/S1S3SoSqSsSUUU$U7U9U:U;U<U=UUUUUUUUUUU$U&U6U8U:U;U=U?UCUUUUUUU UXUUU!U#U%U'U)U+U-U/U1U3UoUqUsUXIRXWRXYfXZfX[fX\fXfX%RX'RX7fXfXfX4RX5RX]RX^RXpfXRXRZIRZWRZYfZZfZ[fZ\fZfZ%RZ'RZ7fZfZfZ4RZ5RZ]RZ^RZpfZRZR\IR\WR\Yf\Zf\[f\\f\f\%R\'R\7f\f\f\4R\5R\]R\^R\pf\R\R^IR^WR^Yf^Zf^[f^\f^f^%R^'R^7f^f^f^4R^5R^]R^^R^pf^R^R`IR`WR`Yf`Zf`[f`\f`f`%R`'R`7f`f`f`4R`5R`]R`^R`pf`R`Raaa$aaaaaaaaaaCaa aXaaa!a#a%a'a)a+a-a/a1a3fIffWffYffZff[ff\ffff%ff'ff7ffffff4ff5ff]ff^ffpfffffhIfhWfhYfhZfh[fh\fhfh%fh'fh7fhfhfh4fh5fh]fh^fhpfhfhfjIfjWfjYfjZfj[fj\fjfj%fj'fj7fjfjfj4fj5fj]fj^fjpfjfjflIflWflYflZfl[fl\flfl%fl'fl7flflfl4fl5fl]fl^flpflflfnIfnWfnYfnZfn[fn\fnfn%fn'fn7fnfnfn4fn5fn]fn^fnpfnfnfooo")o$o&o*o2o4oDoFoGoHoJoPoQoRoSoToUoVoXo]oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo oooooooooooo!o+o-o/o1o3o5o<o>o@oCoDoFoGoHoJoo oWoXoYo_o`oboooo o!o"o#o%o&o'o(o)o*o+o,o-o.o/o0o1o2o3o4o6o8o:o<o@oBoDoIoJoKoLoMoNoOoQoRoSoToUoVoWoXoYoZo[o\o]o^o_o`obodofohojolonpRp Rppp")pRpp Rp qqq")q$q&q*q2q4qDqFqGqHqJqPqQqRqSqTqUqVqXq]qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq qqqqqqqqqqqq!q+q-q/q1q3q5q<q>q@qCqDqFqGqHqJqq qWqXqYq_q`qbqqqq q!q"q#q%q&q'q(q)q*q+q,q-q.q/q0q1q2q3q4q6q8q:q<q@qBqDqIqJqKqLqMqNqOqQqRqSqTqUqVqWqXqYqZq[q\q]q^q_q`qbqdqfqhqjqlqnrRr Rrrr")rRrr Rr sss")s$s&s*s2s4sDsFsGsHsJsPsQsRsSsTsUsVsXs]ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss ssssssssssss!s+s-s/s1s3s5s<s>s@sCsDsFsGsHsJss sWsXsYs_s`sbssss s!s"s#s%s&s's(s)s*s+s,s-s.s/s0s1s2s3s4s6s8s:s<s@sBsDsIsJsKsLsMsNsOsQsRsSsTsUsVsWsXsYsZs[s\s]s^s_s`sbsdsfshsjslsntRt Rttt")tRtt Rt { {{ {")$q&*247)D\FqGqHqJqPQRqSTqUVXYZ[\]qqqqqqq\\\\\\qqqqqqqqqqqq\q\q\qqqqqqqqqqqqqqq qqqq!$)&)+-/1357<>@CqD\F\GHqJ WXqY\_`qbq\q \!q"\#q%q&\'q(\)q*\+q,\-q.\/q0\1q2\3q4\6q8q:q?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~.notdefnullnonmarkingreturnspaceexclamquotedbl numbersigndollarpercent ampersand quotesingle parenleft parenrightasteriskpluscommahyphenperiodslashzeroonetwothreefourfivesixseveneightninecolon semicolonlessequalgreaterquestionatABCDEFGHI.altJKLMNOPQRSTUVWXYZ bracketleft backslash bracketright asciicircum underscoregraveabcdefghijklmnopqrstuvwxyz braceleftbar braceright asciitildenonbreakingspace exclamdowncentsterlingcurrencyyen brokenbarsectiondieresis copyright ordfeminine guillemotleft logicalnotuni00AD registered overscoredegree plusminus twosuperior threesuperioracutemu paragraphperiodcenteredcedilla onesuperior ordmasculineguillemotright onequarteronehalf threequarters questiondownAgraveAacute AcircumflexAtilde AdieresisAringAECcedillaEgraveEacute Ecircumflex Edieresis Igrave.alt Iacute.altIcircumflex.alt Idieresis.altEthNtildeOgraveOacute OcircumflexOtilde OdieresismultiplyOslashUgraveUacute Ucircumflex UdieresisYacuteThorn germandblsagraveaacute acircumflexatilde adieresisaringaeccedillaegraveeacute ecircumflex edieresisigraveiacute icircumflex idieresisethntildeograveoacute ocircumflexotilde odieresisdivideoslashugraveuacute ucircumflex udieresisyacutethorn ydieresisAmacronamacronAbreveabreveAogonekaogonekCacutecacute Ccircumflex ccircumflexCdotcdotCcaronccaronDcarondcaronDcroatdcroatEmacronemacronEbreveebreve Edotaccent edotaccentEogonekeogonekEcaronecaron Gcircumflex gcircumflexGbrevegbreveGdotgdot Gcommaaccent gcommaaccent Hcircumflex hcircumflexHbarhbar Itilde.altitilde Imacron.altimacron Ibreve.altibreve Iogonek.altiogonekIdotaccent.altdotlessiIJ.altij Jcircumflex jcircumflex Kcommaaccent kcommaaccent kgreenlandicLacutelacute Lcommaaccent lcommaaccentLcaronlcaronLdotldotLslashlslashNacutenacute Ncommaaccent ncommaaccentNcaronncaron napostropheEngengOmacronomacronObreveobreve Ohungarumlaut ohungarumlautOEoeRacuteracute Rcommaaccent rcommaaccentRcaronrcaronSacutesacute Scircumflex scircumflexScedillascedillaScaronscaron Tcommaaccent tcommaaccentTcarontcaronTbartbarUtildeutildeUmacronumacronUbreveubreveUringuring Uhungarumlaut uhungarumlautUogonekuogonek Wcircumflex wcircumflex Ycircumflex ycircumflex YdieresisZacutezacute Zdotaccent zdotaccentZcaronzcaronlongsflorin Aringacute aringacuteAEacuteaeacute Oslashacute oslashacute Scommaaccent scommaaccent circumflexcaronmacronbreve dotaccentringogonektilde hungarumlauttonos dieresistonos Alphatonos anoteleia EpsilontonosEtatonos Iotatonos.alt Omicrontonos Upsilontonos OmegatonosiotadieresistonosAlphaBetaGammauni0394EpsilonZetaEtaThetaIota.altKappaLambdaMuNuXiOmicronPiRhoSigmaTauUpsilonPhiChiPsiuni03A9Iotadieresis.altUpsilondieresis alphatonos epsilontonosetatonos iotatonosupsilondieresistonosalphabetagammadeltaepsilonzetaetathetaiotakappalambdauni03BCnuxiomicronpirhosigma1sigmatauupsilonphichipsiomega iotadieresisupsilondieresis omicrontonos upsilontonos omegatonos afii10023 afii10051 afii10052 afii10053 afii10054 afii10055.alt afii10056.alt afii10057 afii10058 afii10059 afii10060 afii10061 afii10062 afii10145 afii10017 afii10018 afii10019 afii10020 afii10021 afii10022 afii10024 afii10025 afii10026 afii10027 afii10028 afii10029 afii10030 afii10031 afii10032 afii10033 afii10034 afii10035 afii10036 afii10037 afii10038 afii10039 afii10040 afii10041 afii10042 afii10043 afii10044 afii10045 afii10046 afii10047 afii10048 afii10049 afii10065 afii10066 afii10067 afii10068 afii10069 afii10070 afii10072 afii10073 afii10074 afii10075 afii10076 afii10077 afii10078 afii10079 afii10080 afii10081 afii10082 afii10083 afii10084 afii10085 afii10086 afii10087 afii10088 afii10089 afii10090 afii10091 afii10092 afii10093 afii10094 afii10095 afii10096 afii10097 afii10071 afii10099 afii10100 afii10101 afii10102 afii10103 afii10104 afii10105 afii10106 afii10107 afii10108 afii10109 afii10110 afii10193 afii10050 afii10098WgravewgraveWacutewacute Wdieresis wdieresisYgraveygraveendashemdash afii00208 underscoredbl quoteleft quoterightquotesinglbase quotereversed quotedblleft quotedblright quotedblbasedagger daggerdblbulletellipsis perthousandminutesecond guilsinglleftguilsinglright exclamdblfraction nsuperiorfranc afii08941pesetaEuro afii61248 afii61289 afii61352 trademarkOmega estimated oneeighth threeeighths fiveeighths seveneighths partialdiffDeltaproduct summationminusradicalinfinityintegral approxequalnotequal lessequal greaterequallozengeuniFB01uniFB02 cyrillicbrevedotlessjcaroncommaaccent commaaccentcommaaccentrotate zerosuperior foursuperior fivesuperior sixsuperior sevensuperior eightsuperior ninesuperioruni2000uni2001uni2002uni2003uni2004uni2005uni2006uni2007uni2008uni2009uni200Auni200BuniFEFFuniFFFCuniFFFDuni01F0uni02BCuni03D1uni03D2uni03D6uni1E3Euni1E3Funi1E00uni1E01uni1F4Duni02F3 dasiaoxiauniFB03uniFB04OhornohornUhornuhornuni0300uni0301uni0303hookdotbelowuni0400uni040Duni0450uni045Duni0460uni0461uni0462uni0463uni0464uni0465uni0466uni0467uni0468uni0469uni046Auni046Buni046Cuni046Duni046Euni046Funi0470uni0471uni0472uni0473uni0474uni0475uni0476uni0477uni0478uni0479uni047Auni047Buni047Cuni047Duni047Euni047Funi0480uni0481uni0482uni0483uni0484uni0485uni0486uni0488uni0489uni048Auni048Buni048Cuni048Duni048Euni048Funi0492uni0493uni0494uni0495uni0496uni0497uni0498uni0499uni049Auni049Buni049Cuni049Duni049Euni049Funi04A0uni04A1uni04A2uni04A3uni04A4uni04A5uni04A6uni04A7uni04A8uni04A9uni04AAuni04ABuni04ACuni04ADuni04AEuni04AFuni04B0uni04B1uni04B2uni04B3uni04B4uni04B5uni04B6uni04B7uni04B8uni04B9uni04BAuni04BBuni04BCuni04BDuni04BEuni04BF uni04C0.altuni04C1uni04C2uni04C3uni04C4uni04C5uni04C6uni04C7uni04C8uni04C9uni04CAuni04CBuni04CCuni04CDuni04CE uni04CF.altuni04D0uni04D1uni04D2uni04D3uni04D4uni04D5uni04D6uni04D7uni04D8uni04D9uni04DAuni04DBuni04DCuni04DDuni04DEuni04DFuni04E0uni04E1uni04E2uni04E3uni04E4uni04E5uni04E6uni04E7uni04E8uni04E9uni04EAuni04EBuni04ECuni04EDuni04EEuni04EFuni04F0uni04F1uni04F2uni04F3uni04F4uni04F5uni04F6uni04F7uni04F8uni04F9uni04FAuni04FBuni04FCuni04FDuni04FEuni04FFuni0500uni0501uni0502uni0503uni0504uni0505uni0506uni0507uni0508uni0509uni050Auni050Buni050Cuni050Duni050Euni050Funi0510uni0511uni0512uni0513uni1EA0uni1EA1uni1EA2uni1EA3uni1EA4uni1EA5uni1EA6uni1EA7uni1EA8uni1EA9uni1EAAuni1EABuni1EACuni1EADuni1EAEuni1EAFuni1EB0uni1EB1uni1EB2uni1EB3uni1EB4uni1EB5uni1EB6uni1EB7uni1EB8uni1EB9uni1EBAuni1EBBuni1EBCuni1EBDuni1EBEuni1EBFuni1EC0uni1EC1uni1EC2uni1EC3uni1EC4uni1EC5uni1EC6uni1EC7 uni1EC8.altuni1EC9 uni1ECA.altuni1ECBuni1ECCuni1ECDuni1ECEuni1ECFuni1ED0uni1ED1uni1ED2uni1ED3uni1ED4uni1ED5uni1ED6uni1ED7uni1ED8uni1ED9uni1EDAuni1EDBuni1EDCuni1EDDuni1EDEuni1EDFuni1EE0uni1EE1uni1EE2uni1EE3uni1EE4uni1EE5uni1EE6uni1EE7uni1EE8uni1EE9uni1EEAuni1EEBuni1EECuni1EEDuni1EEEuni1EEFuni1EF0uni1EF1uni1EF4uni1EF5uni1EF6uni1EF7uni1EF8uni1EF9uni20ABuni030Fcircumflexacutecombcircumflexgravecombcircumflexhookcombcircumflextildecombbreveacutecombbrevegravecomb brevehookcombbrevetildecombcyrillichookleftcyrillicbighookUCcyrillicbighookLCone.pnumzero.osone.ostwo.osthree.osfour.osfive.ossix.osseven.oseight.osnine.osffuni2120Tcedillatcedillag.altgcircumflex.alt gbreve.altgdot.altgcommaaccent.altIIgraveIacute Icircumflex IdieresisItildeImacronIbreveIogonek IdotaccentIJ IotatonosIota Iotadieresis afii10055 afii10056uni04C0uni04CFuni1EC8uni1ECA   46latnMOL ROM  nlatnMOL (ROM B      ligaligaligalnumlnumlnumloclloclonumonumonumpnumpnumpnumsalt saltsaltss01"ss01*ss012ss02:ss02@ss02Fss03Lss03Rss03Xtnum^tnumftnumn    &.6>FNV^Pz2HJJ.,ZgwEG      !$%IJ6 "(^IO]ILI5O4LI^V0R *H C0?1 0 +0a +7S0Q0, +7<<<Obsolete>>>0!0 +37yc 1:X;y]0z0b8%a&Z0  *H 0S1 0 UUS10U VeriSign, Inc.1+0)U"VeriSign Time Stamping Services CA0 070615000000Z 120614235959Z0\1 0 UUS10U VeriSign, Inc.1402U+VeriSign Time Stamping Services Signer - G200  *H 0ĵR`)J[/Kk5TX56^bMRQ4q{f*j 7٘tvJcEG.k NK+XJ,XB-uލǎlLgrIž`<cxi{-004+(0&0$+0http://ocsp.verisign.com0 U003U,0*0(&$"http://crl.verisign.com/tss-ca.crl0U% 0 +0U0U0010 UTSA1-20  *H PK$ $- 7 ,Za񑑳V@뒾89u6t:O7ʕBǠWdB5N3M'L8MxSݤ^ ⥾`߭(ǥKd[98"3/!?DA e$HDT\y>]r},CS}=*:Om ]^SWp`+nx'4[^I2300-GߍRFCmH 10  *H 01 0 UZA10U Western Cape10U Durbanville10 U Thawte10U Thawte Certification10UThawte Timestamping CA0 031204000000Z 131203235959Z0S1 0 UUS10U VeriSign, Inc.1+0)U"VeriSign Time Stamping Services CA0"0  *H 0 ʲ }uNgadڻ30X~k6xw~o< hlʽR-H=]_/kLR`@~ ?Ǵ߇_zj1.G 1s W-x43h/Š*Ë!fXWou<&]'x1"ijGC_^|}bM "Vͮv M٠h;004+(0&0$+0http://ocsp.verisign.com0U00AU:0806420http://crl.verisign.com/ThawteTimestampingCA.crl0U% 0 +0U0$U0010U TSA2048-1-530  *H JkXD1y+LͰXn)^ʓR G'/8ɓN"b?7!Op18UN$ҩ'NzaA*^ݻ+>W~ +;R8'?J00eeR&.Y)"\0  *H 0_1 0 UUS10U VeriSign, Inc.1705U .Class 3 Public Primary Certification Authority0 090521000000Z 190520235959Z01 0 UUS10U VeriSign, Inc.10U VeriSign Trust Network1;09U 2Terms of use at https://www.verisign.com/rpa (c)09100.U'VeriSign Class 3 Code Signing 2009-2 CA0"0  *H 0 g`IoV|f^ q-!ќPL"5; .Z|=;%X{ ξ'tag'MjaXy'M4+G Df$fO8TrfujIh8y 0,`Hת809:|@T/ܨR>+!\ P4.M^%Ԍn|)]1ZՌgX5+!`x^{`W ]A cT`C!00U00pU i0g0e `HE0V0(+https://www.verisign.com/cps0*+0https://www.verisign.com/rpa0U0m+ a0_][0Y0W0U image/gif0!00+kπjH,{.0%#http://logo.verisign.com/vslogo.gif0U%0++04+(0&0$+0http://ocsp.verisign.com01U*0(0&$" http://crl.verisign.com/pca3.crl0)U"0 010UClass3CA2048-1-550Uk&pȡ?-50  *H ݔAaix0Ɛ<~B$s/DrPU nQj71ܥ-OM2NgUejzd8xEv1z`³]fvYI8VAwX00fgymPSo0  *H 01 0 UUS10U VeriSign, Inc.10U VeriSign Trust Network1;09U 2Terms of use at https://www.verisign.com/rpa (c)09100.U'VeriSign Class 3 Code Signing 2009-2 CA0 100729000000Z 120808235959Z01 0 UUS10U Massachusetts10 UWoburn10U Monotype Imaging Inc.1>0<U 5Digital ID Class 3 - Microsoft Software Validation v210U Type Operations10UMonotype Imaging Inc.00  *H 0Di|U 25L3^ L*8ט@I "SOCʋVnH9c;$5}rGWyˊJ@p-5cįפ {uePd"}KXEMYLM00 U00U0DU=0;09753http://csc3-2009-2-crl.verisign.com/CSC3-2009-2.crl0DU =0;09 `HE0*0(+https://www.verisign.com/rpa0U% 0 +0u+i0g0$+0http://ocsp.verisign.com0?+03http://csc3-2009-2-aia.verisign.com/CSC3-2009-2.cer0U#0k&pȡ?-50 `HB0 +700  *H N"gA~™cjrb<8=_G_[KI  VD 5< D`E*oL;4gpZ9\Zl5|eKmIp=b۴A~}n"w6MZ S1+(RzkwD ]%,͊0>KyʦN $ 񺐶\<'M0  *H Pj<1wPd%i9Zp&3ZFJŬ>PO'/ӁAZԯdb:8؛p.@am J.w1o{ƵѬd~M#, -~z (Pruby-prawn-svg-0.32.0/spec/spec_helper.rb000066400000000000000000000015351402126170300202470ustar00rootroot00000000000000require 'bundler' Bundler.require(:default, :development) # Requires supporting files with custom matchers and macros, etc, # in ./support/ and its subdirectories. Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f} module Support def flatten_calls(calls) [].tap do |flattened_calls| add = -> (local_calls) do local_calls.each do |call| flattened_calls << call[0..2] add.call call[3] end end add.call element.base_calls end end def fake_state state = Prawn::SVG::State.new state.viewport_sizing = document.sizing if defined?(document) state end end RSpec.configure do |config| config.mock_with :rspec do |c| c.syntax = [:should, :expect] end config.expect_with :rspec do |c| c.syntax = [:should, :expect] end config.include Support end