From ddd036ef9755c8fb77ebbdb3d2568272f4a87284 Mon Sep 17 00:00:00 2001 From: albert Date: Fri, 14 Oct 2011 18:02:11 -0400 Subject: [PATCH] fixes #118: flash uploads are broken --- Gemfile | 2 +- Gemfile.lock | 2 - .../stylesheets/specific/post_flags.css.scss | 5 + app/models/upload.rb | 12 +- app/views/posts/partials/show/_flash.html.erb | 2 +- vendor/plugins/imagesize/Manifest.txt | 18 + vendor/plugins/imagesize/README.txt | 49 + vendor/plugins/imagesize/imagesize.gemspec | 15 + vendor/plugins/imagesize/init.rb | 1 + vendor/plugins/imagesize/install.rb | 2 + vendor/plugins/imagesize/lib/image_size.rb | 295 +++ .../imagesize/lib/image_size/version.rb | 9 + vendor/plugins/imagesize/setup.rb | 1585 +++++++++++++++++ vendor/plugins/imagesize/test/2-4-7.png | Bin 0 -> 11639 bytes vendor/plugins/imagesize/test/4_1_2.gif | Bin 0 -> 10794 bytes vendor/plugins/imagesize/test/bmp.bmp | Bin 0 -> 7654 bytes vendor/plugins/imagesize/test/cursor.xbm | 6 + vendor/plugins/imagesize/test/detect.swf | Bin 0 -> 4544 bytes vendor/plugins/imagesize/test/pbm.pbm | Bin 0 -> 637 bytes vendor/plugins/imagesize/test/pgm.pgm | 5 + vendor/plugins/imagesize/test/ppm.ppm | 694 ++++++++ vendor/plugins/imagesize/test/test.xpm | 38 + vendor/plugins/imagesize/test/test_helper.rb | 2 + .../plugins/imagesize/test/test_image_size.rb | 70 + vendor/plugins/imagesize/test/tiff.tiff | Bin 0 -> 12564 bytes vendor/plugins/imagesize/test/tokyo_tower.jpg | Bin 0 -> 32458 bytes vendor/plugins/imagesize/test/tower_e.gif.psd | Bin 0 -> 5588 bytes 27 files changed, 2805 insertions(+), 7 deletions(-) create mode 100644 app/assets/stylesheets/specific/post_flags.css.scss create mode 100755 vendor/plugins/imagesize/Manifest.txt create mode 100755 vendor/plugins/imagesize/README.txt create mode 100644 vendor/plugins/imagesize/imagesize.gemspec create mode 100644 vendor/plugins/imagesize/init.rb create mode 100644 vendor/plugins/imagesize/install.rb create mode 100755 vendor/plugins/imagesize/lib/image_size.rb create mode 100755 vendor/plugins/imagesize/lib/image_size/version.rb create mode 100755 vendor/plugins/imagesize/setup.rb create mode 100755 vendor/plugins/imagesize/test/2-4-7.png create mode 100755 vendor/plugins/imagesize/test/4_1_2.gif create mode 100755 vendor/plugins/imagesize/test/bmp.bmp create mode 100755 vendor/plugins/imagesize/test/cursor.xbm create mode 100755 vendor/plugins/imagesize/test/detect.swf create mode 100755 vendor/plugins/imagesize/test/pbm.pbm create mode 100755 vendor/plugins/imagesize/test/pgm.pgm create mode 100644 vendor/plugins/imagesize/test/ppm.ppm create mode 100755 vendor/plugins/imagesize/test/test.xpm create mode 100755 vendor/plugins/imagesize/test/test_helper.rb create mode 100755 vendor/plugins/imagesize/test/test_image_size.rb create mode 100755 vendor/plugins/imagesize/test/tiff.tiff create mode 100755 vendor/plugins/imagesize/test/tokyo_tower.jpg create mode 100755 vendor/plugins/imagesize/test/tower_e.gif.psd diff --git a/Gemfile b/Gemfile index c4a1ef32d..3f4978ae2 100644 --- a/Gemfile +++ b/Gemfile @@ -18,7 +18,7 @@ end gem "rails", "3.1.0" gem "pg" gem "memcache-client", :require => "memcache" -gem "imagesize", :require => "image_size" +# gem "imagesize", :require => "image_size" gem "delayed_job" gem "super_exception_notifier" gem "simple_form" diff --git a/Gemfile.lock b/Gemfile.lock index 41f962472..d81cc7d75 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -70,7 +70,6 @@ GEM activesupport hike (1.2.1) i18n (0.6.0) - imagesize (0.1.1) libv8 (3.3.10.2) mail (2.3.0) i18n (>= 0.4.0) @@ -177,7 +176,6 @@ DEPENDENCIES delayed_job factory_girl ffaker! - imagesize mechanize memcache-client meta_search! diff --git a/app/assets/stylesheets/specific/post_flags.css.scss b/app/assets/stylesheets/specific/post_flags.css.scss new file mode 100644 index 000000000..8ec371aec --- /dev/null +++ b/app/assets/stylesheets/specific/post_flags.css.scss @@ -0,0 +1,5 @@ +div#c-post-flags { + li { + list-style-type: disc; + } +} \ No newline at end of file diff --git a/app/models/upload.rb b/app/models/upload.rb index 86b0f98e0..4af725857 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -123,13 +123,19 @@ class Upload < ActiveRecord::Base def calculate_hash(source_path) self.md5 = Digest::MD5.file(source_path).hexdigest end + + def is_image? + ["jpg", "gif", "png"].include?(file_ext) + end end module ResizerMethods def generate_resizes(source_path) - generate_resize_for(Danbooru.config.small_image_width, Danbooru.config.small_image_width, source_path, 85) - generate_resize_for(Danbooru.config.medium_image_width, nil, source_path) - generate_resize_for(Danbooru.config.large_image_width, nil, source_path) + if is_image? + generate_resize_for(Danbooru.config.small_image_width, Danbooru.config.small_image_width, source_path, 85) + generate_resize_for(Danbooru.config.medium_image_width, nil, source_path) + generate_resize_for(Danbooru.config.large_image_width, nil, source_path) + end end def generate_resize_for(width, height, source_path, quality = 90) diff --git a/app/views/posts/partials/show/_flash.html.erb b/app/views/posts/partials/show/_flash.html.erb index 355624fea..8ff9c88c1 100644 --- a/app/views/posts/partials/show/_flash.html.erb +++ b/app/views/posts/partials/show/_flash.html.erb @@ -1,4 +1,4 @@ -<% content_tag(:object, :width => post.image_width, :height => post.image_height) do %> +<%= content_tag(:object, :width => post.image_width, :height => post.image_height) do %> <%= tag :params, :name => "movie", :value => post.file_url %> <%= tag :embed, :src => post.file_url, :width => post.image_width, :height => post.image_height, :allowScriptAccess => "never" %> <% end %> diff --git a/vendor/plugins/imagesize/Manifest.txt b/vendor/plugins/imagesize/Manifest.txt new file mode 100755 index 000000000..71c3f5a38 --- /dev/null +++ b/vendor/plugins/imagesize/Manifest.txt @@ -0,0 +1,18 @@ +Manifest.txt +README.txt +lib/image_size.rb +lib/image_size/version.rb +setup.rb +test/test_helper.rb +test/test_image_size.rb +test/2-4-7.png +test/4_1_2.gif +test/bmp.bmp +test/cursor.xbm +test/detect.swf +test/pbm.pbm +test/pgm.pgm +test/test.xpm +test/tiff.tiff +test/tokyo_tower.jpg +test/tower_e.gif.psd diff --git a/vendor/plugins/imagesize/README.txt b/vendor/plugins/imagesize/README.txt new file mode 100755 index 000000000..f3ed4d1c3 --- /dev/null +++ b/vendor/plugins/imagesize/README.txt @@ -0,0 +1,49 @@ += image_size -- measure image size(GIF, PNG, JPEG ,,, etc) + +measure image (GIF, PNG, JPEG ,,, etc) size code by Pure Ruby +["PSD", "XPM", "TIFF", "XBM", "PGM", "PBM", "PPM", "BMP", "JPEG", "PNG", "GIF", "SWF"] + +== Download + +The latest version of image_size can be found at + +* http://rubyforge.org/frs/?group_id=3460 + +== Installation + +=== Normal Installation + +You can install image_size with the following command. + + % ruby setup.rb + +from its distribution directory. + +=== GEM Installation + +Download and install image_size with the following. + + gem install imagesize + +== image_size References + +* image_size Project Page: http://rubyforge.org/projects/imagesize +* image_size API Documents: http://imagesize.rubyforge.org + +== Simple Example + + ruby "rubygems" # you use rubygems + ruby "image_size" + ruby "open-uri" + open("http://www.rubycgi.org/image/ruby_gtk_book_title.jpg", "rb") do |fh| + p ImageSize.new(fh.read).get_size + end + +== Licence + +This code is free to use under the terms of the Ruby's licence. + +== Contact + +Comments are welcome. Send an email to "Keisuke Minami":mailto:keisuke@rccn.com + diff --git a/vendor/plugins/imagesize/imagesize.gemspec b/vendor/plugins/imagesize/imagesize.gemspec new file mode 100644 index 000000000..8b45382d5 --- /dev/null +++ b/vendor/plugins/imagesize/imagesize.gemspec @@ -0,0 +1,15 @@ +Gem::Specification.new do |s| + s.name = 'imagesize' + s.description = 'measure image size(GIF, PNG, JPEG ,,, etc) code by Pure Ruby' + s.summary = 'Imagesize will detect and measure images in the following formats: GIF, PNG, JPEG, BMP, PPM, PGM, PBM, XBM, TIFF, XPM, PSD, SWF' + + s.version = '0.1.2' + s.date = '2010-10-02' + + s.author = 'Keisuke Minami' + s.email = 'keisuke@rccn.com' + s.homepage = 'http://rubygems.org/gems/imagesize' + + s.files = `git ls-files`.split("\n") + s.require_path = 'lib' +end diff --git a/vendor/plugins/imagesize/init.rb b/vendor/plugins/imagesize/init.rb new file mode 100644 index 000000000..c840adc84 --- /dev/null +++ b/vendor/plugins/imagesize/init.rb @@ -0,0 +1 @@ +require 'image_size' \ No newline at end of file diff --git a/vendor/plugins/imagesize/install.rb b/vendor/plugins/imagesize/install.rb new file mode 100644 index 000000000..1fcb8e442 --- /dev/null +++ b/vendor/plugins/imagesize/install.rb @@ -0,0 +1,2 @@ +# Install hook code here +puts "Thank you for installing Imagesize. You can visit http://imagesize.rubyforge.org/ to read the documentation." \ No newline at end of file diff --git a/vendor/plugins/imagesize/lib/image_size.rb b/vendor/plugins/imagesize/lib/image_size.rb new file mode 100755 index 000000000..149cc60b8 --- /dev/null +++ b/vendor/plugins/imagesize/lib/image_size.rb @@ -0,0 +1,295 @@ +#!ruby +# encoding: US-ASCII + +class ImageSize + require "stringio" + +# Image Type Constants + module Type + OTHER = "OTHER" + GIF = "GIF" + PNG = "PNG" + JPEG = "JPEG" + BMP = "BMP" + PPM = "PPM" # PPM is like PBM, PGM, & XV + PBM = "PBM" + PGM = "PGM" +# XV = "XV" + XBM = "XBM" + TIFF = "TIFF" + XPM = "XPM" + PSD = "PSD" + SWF = "SWF" + end + + JpegCodeCheck = [ + "\xc0", "\xc1", "\xc2", "\xc3", + "\xc5", "\xc6", "\xc7", + "\xc9", "\xca", "\xcb", + "\xcd", "\xce", "\xcf", + ] + + # image type list + def ImageSize.type_list + Type.constants + end + + # receive image & make size + # argument 1 is image String, StringIO or IO + # argument 2 is type(ImageSize::Type::GIF and so on.) or nil + def initialize(img_data, img_type = nil) + @img_data = img_data.dup + @img_width = nil + @img_height = nil + @img_type = nil + + if @img_data.is_a?(IO) + img_top = @img_data.read(1024) + img_io = def_read_o(@img_data) + elsif @img_data.is_a?(StringIO) + img_top = @img_data.read(1024) + img_io = def_read_o(@img_data) + elsif @img_data.is_a?(String) + img_top = @img_data[0, 1024] +# img_io = StringIO.open(@img_data){|sio| io = def_read_o(sio); io } + img_io = StringIO.open(@img_data) + img_io = def_read_o(img_io) + else + raise "argument class error!! #{img_data.type}" + end + + if @img_type.nil? + @img_type = check_type(img_top) + else + type = Type.constants.find{|t| img_type == t } + raise("type is failed. #{img_type}\n") if !type + @img_type = img_type + end + + if @img_type != Type::OTHER + @img_width, @img_height = self.__send__("measure_#{@img_type}", img_io) + else + @img_width, @img_height = [nil, nil] + end + + if @img_data.is_a?(String) + img_io.close + end + end + + # get image type + # ex. "GIF", "PNG", "JPEG" + def get_type; @img_type; end + + # get image height + def get_height + if @img_type == Type::OTHER then nil else @img_height end + end + + # get image width + def get_width + if @img_type == Type::OTHER then nil else @img_width end + end + + # get image width and height(Array) + def get_size + [self.get_width, self.get_height] + end + + alias :height :get_height + alias :h :get_height + + alias :width :get_width + alias :w :get_width + + alias :size :get_size + + + private + + # define read_o + def def_read_o(io) + io.seek(0, 0) + # define Singleton-method definition to IO (byte, offset) + def io.read_o(length = 1, offset = nil) + self.seek(offset, 0) if offset + ret = self.read(length) + raise "cannot read!!" unless ret + ret + end + io + end + + def check_type(img_top) + if img_top =~ /^GIF8[7,9]a/ then Type::GIF + elsif img_top[0, 8] == "\x89PNG\x0d\x0a\x1a\x0a" then Type::PNG + elsif img_top[0, 2] == "\xFF\xD8" then Type::JPEG + elsif img_top[0, 2] == 'BM' then Type::BMP + elsif img_top =~ /^P[1-7]/ then Type::PPM + elsif img_top =~ /\#define\s+\S+\s+\d+/ then Type::XBM + elsif img_top[0, 4] == "MM\x00\x2a" then Type::TIFF + elsif img_top[0, 4] == "II\x2a\x00" then Type::TIFF + elsif img_top =~ /\/\* XPM \*\// then Type::XPM + elsif img_top[0, 4] == "8BPS" then Type::PSD + elsif img_top[1, 2] == "WS" then Type::SWF + else Type::OTHER + end + end + + def measure_GIF(img_io) + img_io.read_o(6) + img_io.read_o(4).unpack('vv') + end + + def measure_PNG(img_io) + img_io.read_o(12) + raise "This file is not PNG." unless img_io.read_o(4) == "IHDR" + img_io.read_o(8).unpack('NN') + end + + def measure_JPEG(img_io) + c_marker = "\xFF" # Section marker. + img_io.read_o(2) + while(true) + marker, code, length = img_io.read_o(4).unpack('aan') + raise "JPEG marker not found!" if marker != c_marker + + if JpegCodeCheck.include?(code) + height, width = img_io.read_o(5).unpack('xnn') + return([width, height]) + end + img_io.read_o(length - 2) + end + end + + def measure_BMP(img_io) + img_io.read_o(26).unpack("x18VV"); + end + + def measure_PPM(img_io) + header = img_io.read_o(1024) + header.gsub!(/^\#[^\n\r]*/m, "") + header =~ /^(P[1-6])\s+?(\d+)\s+?(\d+)/m + width = $2.to_i; height = $3.to_i + case $1 + when "P1", "P4" then @img_type = "PBM" + when "P2", "P5" then @img_type = "PGM" + when "P3", "P6" then @img_type = "PPM" +# when "P7" +# @img_type = "XV" +# header =~ /IMGINFO:(\d+)x(\d+)/m +# width = $1.to_i; height = $2.to_i + end + [width, height] + end + + alias :measure_PGM :measure_PPM + alias :measure_PBM :measure_PPM + + def measure_XBM(img_io) + img_io.read_o(1024) =~ /^\#define\s*\S*\s*(\d+)\s*\n\#define\s*\S*\s*(\d+)/mi + [$1.to_i, $2.to_i] + end + + def measure_XPM(img_io) + width = height = nil + while(line = img_io.read_o(1024)) + if line =~ /"\s*(\d+)\s+(\d+)(\s+\d+\s+\d+){1,2}\s*"/m + width = $1.to_i; height = $2.to_i + break + end + end + [width, height] + end + + def measure_PSD(img_io) + img_io.read_o(26).unpack("x14NN") + end + + def measure_TIFF(img_io) + endian = if (img_io.read_o(4) =~ /II\x2a\x00/o) then 'v' else 'n' end +# 'v' little-endian 'n' default to big-endian + + packspec = [ + nil, # nothing (shouldn't happen) + 'C', # BYTE (8-bit unsigned integer) + nil, # ASCII + endian, # SHORT (16-bit unsigned integer) + endian.upcase, # LONG (32-bit unsigned integer) + nil, # RATIONAL + 'c', # SBYTE (8-bit signed integer) + nil, # UNDEFINED + endian, # SSHORT (16-bit unsigned integer) + endian.upcase, # SLONG (32-bit unsigned integer) + ] + + offset = img_io.read_o(4).unpack(endian.upcase)[0] # Get offset to IFD + + ifd = img_io.read_o(2, offset) + num_dirent = ifd.unpack(endian)[0] # Make it useful + offset += 2 + num_dirent = offset + (num_dirent * 12); # Calc. maximum offset of IFD + + ifd = width = height = nil + while(width.nil? || height.nil?) + ifd = img_io.read_o(12, offset) # Get first directory entry + break if (ifd.nil? || (offset > num_dirent)) + offset += 12 + tag = ifd.unpack(endian)[0] # ...and decode its tag + type = ifd[2, 2].unpack(endian)[0] # ...and the data type + + # Check the type for sanity. + next if (type > packspec.size + 0) || (packspec[type].nil?) + if tag == 0x0100 # Decode the value + width = ifd[8, 4].unpack(packspec[type])[0] + elsif tag == 0x0101 # Decode the value + height = ifd[8, 4].unpack(packspec[type])[0] + end + end + + raise "#{if width.nil? then 'width not defined.' end} #{if height.nil? then 'height not defined.' end}" if width.nil? || height.nil? + [width, height] + end + + def measure_SWF(img_io) + header = img_io.read_o(9) + + sig1 = header[0,1] + sig2 = header[1,1] + sig3 = header[2,1] + + if !((sig1 == 'F' || sig1 == 'C') && sig2 == 'W' && sig3 == 'S') + raise("This file is not SWF.") + end + + bit_length = Integer("0b#{header.unpack('@8B5')[0]}") + header << img_io.read_o(bit_length*4/8+1) + str = header.unpack("@8B#{5+bit_length*4}")[0] + last = 5 + x_min = Integer("0b#{str[last,bit_length]}") + x_max = Integer("0b#{str[(last += bit_length),bit_length]}") + y_min = Integer("0b#{str[(last += bit_length),bit_length]}") + y_max = Integer("0b#{str[(last += bit_length),bit_length]}") + width = (x_max - x_min)/20 + height = (y_max - y_min)/20 + [width, height] + end +end + + +if __FILE__ == $0 + print "TypeList: #{ImageSize.type.inspect}\n" + + Dir.glob("*").each do |file| + print "#{file} (string)\n" + open(file, "rb") do |fh| + img = ImageSize.new(fh.read) + print <<-EOF +type: #{img.get_type.inspect} +width: #{img.get_width.inspect} +height: #{img.get_height.inspect} + EOF + end + end +end + diff --git a/vendor/plugins/imagesize/lib/image_size/version.rb b/vendor/plugins/imagesize/lib/image_size/version.rb new file mode 100755 index 000000000..6c4be82ac --- /dev/null +++ b/vendor/plugins/imagesize/lib/image_size/version.rb @@ -0,0 +1,9 @@ +module Imagesize #:nodoc: + module VERSION #:nodoc: + MAJOR = 0 + MINOR = 1 + TINY = 1 + + STRING = [MAJOR, MINOR, TINY].join('.') + end +end diff --git a/vendor/plugins/imagesize/setup.rb b/vendor/plugins/imagesize/setup.rb new file mode 100755 index 000000000..424a5f37c --- /dev/null +++ b/vendor/plugins/imagesize/setup.rb @@ -0,0 +1,1585 @@ +# +# setup.rb +# +# Copyright (c) 2000-2005 Minero Aoki +# +# This program is free software. +# You can distribute/modify this program under the terms of +# the GNU LGPL, Lesser General Public License version 2.1. +# + +unless Enumerable.method_defined?(:map) # Ruby 1.4.6 + module Enumerable + alias map collect + end +end + +unless File.respond_to?(:read) # Ruby 1.6 + def File.read(fname) + open(fname) {|f| + return f.read + } + end +end + +unless Errno.const_defined?(:ENOTEMPTY) # Windows? + module Errno + class ENOTEMPTY + # We do not raise this exception, implementation is not needed. + end + end +end + +def File.binread(fname) + open(fname, 'rb') {|f| + return f.read + } +end + +# for corrupted Windows' stat(2) +def File.dir?(path) + File.directory?((path[-1,1] == '/') ? path : path + '/') +end + + +class ConfigTable + + include Enumerable + + def initialize(rbconfig) + @rbconfig = rbconfig + @items = [] + @table = {} + # options + @install_prefix = nil + @config_opt = nil + @verbose = true + @no_harm = false + end + + attr_accessor :install_prefix + attr_accessor :config_opt + + attr_writer :verbose + + def verbose? + @verbose + end + + attr_writer :no_harm + + def no_harm? + @no_harm + end + + def [](key) + lookup(key).resolve(self) + end + + def []=(key, val) + lookup(key).set val + end + + def names + @items.map {|i| i.name } + end + + def each(&block) + @items.each(&block) + end + + def key?(name) + @table.key?(name) + end + + def lookup(name) + @table[name] or setup_rb_error "no such config item: #{name}" + end + + def add(item) + @items.push item + @table[item.name] = item + end + + def remove(name) + item = lookup(name) + @items.delete_if {|i| i.name == name } + @table.delete_if {|name, i| i.name == name } + item + end + + def load_script(path, inst = nil) + if File.file?(path) + MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path + end + end + + def savefile + '.config' + end + + def load_savefile + begin + File.foreach(savefile()) do |line| + k, v = *line.split(/=/, 2) + self[k] = v.strip + end + rescue Errno::ENOENT + setup_rb_error $!.message + "\n#{File.basename($0)} config first" + end + end + + def save + @items.each {|i| i.value } + File.open(savefile(), 'w') {|f| + @items.each do |i| + f.printf "%s=%s\n", i.name, i.value if i.value? and i.value + end + } + end + + def load_standard_entries + standard_entries(@rbconfig).each do |ent| + add ent + end + end + + def standard_entries(rbconfig) + c = rbconfig + + rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT']) + + major = c['MAJOR'].to_i + minor = c['MINOR'].to_i + teeny = c['TEENY'].to_i + version = "#{major}.#{minor}" + + # ruby ver. >= 1.4.4? + newpath_p = ((major >= 2) or + ((major == 1) and + ((minor >= 5) or + ((minor == 4) and (teeny >= 4))))) + + if c['rubylibdir'] + # V > 1.6.3 + libruby = "#{c['prefix']}/lib/ruby" + librubyver = c['rubylibdir'] + librubyverarch = c['archdir'] + siteruby = c['sitedir'] + siterubyver = c['sitelibdir'] + siterubyverarch = c['sitearchdir'] + elsif newpath_p + # 1.4.4 <= V <= 1.6.3 + libruby = "#{c['prefix']}/lib/ruby" + librubyver = "#{c['prefix']}/lib/ruby/#{version}" + librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" + siteruby = c['sitedir'] + siterubyver = "$siteruby/#{version}" + siterubyverarch = "$siterubyver/#{c['arch']}" + else + # V < 1.4.4 + libruby = "#{c['prefix']}/lib/ruby" + librubyver = "#{c['prefix']}/lib/ruby/#{version}" + librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" + siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby" + siterubyver = siteruby + siterubyverarch = "$siterubyver/#{c['arch']}" + end + parameterize = lambda {|path| + path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix') + } + + if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg } + makeprog = arg.sub(/'/, '').split(/=/, 2)[1] + else + makeprog = 'make' + end + + [ + ExecItem.new('installdirs', 'std/site/home', + 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\ + {|val, table| + case val + when 'std' + table['rbdir'] = '$librubyver' + table['sodir'] = '$librubyverarch' + when 'site' + table['rbdir'] = '$siterubyver' + table['sodir'] = '$siterubyverarch' + when 'home' + setup_rb_error '$HOME was not set' unless ENV['HOME'] + table['prefix'] = ENV['HOME'] + table['rbdir'] = '$libdir/ruby' + table['sodir'] = '$libdir/ruby' + end + }, + PathItem.new('prefix', 'path', c['prefix'], + 'path prefix of target environment'), + PathItem.new('bindir', 'path', parameterize.call(c['bindir']), + 'the directory for commands'), + PathItem.new('libdir', 'path', parameterize.call(c['libdir']), + 'the directory for libraries'), + PathItem.new('datadir', 'path', parameterize.call(c['datadir']), + 'the directory for shared data'), + PathItem.new('mandir', 'path', parameterize.call(c['mandir']), + 'the directory for man pages'), + PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']), + 'the directory for system configuration files'), + PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']), + 'the directory for local state data'), + PathItem.new('libruby', 'path', libruby, + 'the directory for ruby libraries'), + PathItem.new('librubyver', 'path', librubyver, + 'the directory for standard ruby libraries'), + PathItem.new('librubyverarch', 'path', librubyverarch, + 'the directory for standard ruby extensions'), + PathItem.new('siteruby', 'path', siteruby, + 'the directory for version-independent aux ruby libraries'), + PathItem.new('siterubyver', 'path', siterubyver, + 'the directory for aux ruby libraries'), + PathItem.new('siterubyverarch', 'path', siterubyverarch, + 'the directory for aux ruby binaries'), + PathItem.new('rbdir', 'path', '$siterubyver', + 'the directory for ruby scripts'), + PathItem.new('sodir', 'path', '$siterubyverarch', + 'the directory for ruby extentions'), + PathItem.new('rubypath', 'path', rubypath, + 'the path to set to #! line'), + ProgramItem.new('rubyprog', 'name', rubypath, + 'the ruby program using for installation'), + ProgramItem.new('makeprog', 'name', makeprog, + 'the make program to compile ruby extentions'), + SelectItem.new('shebang', 'all/ruby/never', 'ruby', + 'shebang line (#!) editing mode'), + BoolItem.new('without-ext', 'yes/no', 'no', + 'does not compile/install ruby extentions') + ] + end + private :standard_entries + + def load_multipackage_entries + multipackage_entries().each do |ent| + add ent + end + end + + def multipackage_entries + [ + PackageSelectionItem.new('with', 'name,name...', '', 'ALL', + 'package names that you want to install'), + PackageSelectionItem.new('without', 'name,name...', '', 'NONE', + 'package names that you do not want to install') + ] + end + private :multipackage_entries + + ALIASES = { + 'std-ruby' => 'librubyver', + 'stdruby' => 'librubyver', + 'rubylibdir' => 'librubyver', + 'archdir' => 'librubyverarch', + 'site-ruby-common' => 'siteruby', # For backward compatibility + 'site-ruby' => 'siterubyver', # For backward compatibility + 'bin-dir' => 'bindir', + 'bin-dir' => 'bindir', + 'rb-dir' => 'rbdir', + 'so-dir' => 'sodir', + 'data-dir' => 'datadir', + 'ruby-path' => 'rubypath', + 'ruby-prog' => 'rubyprog', + 'ruby' => 'rubyprog', + 'make-prog' => 'makeprog', + 'make' => 'makeprog' + } + + def fixup + ALIASES.each do |ali, name| + @table[ali] = @table[name] + end + @items.freeze + @table.freeze + @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/ + end + + def parse_opt(opt) + m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}" + m.to_a[1,2] + end + + def dllext + @rbconfig['DLEXT'] + end + + def value_config?(name) + lookup(name).value? + end + + class Item + def initialize(name, template, default, desc) + @name = name.freeze + @template = template + @value = default + @default = default + @description = desc + end + + attr_reader :name + attr_reader :description + + attr_accessor :default + alias help_default default + + def help_opt + "--#{@name}=#{@template}" + end + + def value? + true + end + + def value + @value + end + + def resolve(table) + @value.gsub(%r<\$([^/]+)>) { table[$1] } + end + + def set(val) + @value = check(val) + end + + private + + def check(val) + setup_rb_error "config: --#{name} requires argument" unless val + val + end + end + + class BoolItem < Item + def config_type + 'bool' + end + + def help_opt + "--#{@name}" + end + + private + + def check(val) + return 'yes' unless val + case val + when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes' + when /\An(o)?\z/i, /\Af(alse)\z/i then 'no' + else + setup_rb_error "config: --#{@name} accepts only yes/no for argument" + end + end + end + + class PathItem < Item + def config_type + 'path' + end + + private + + def check(path) + setup_rb_error "config: --#{@name} requires argument" unless path + path[0,1] == '$' ? path : File.expand_path(path) + end + end + + class ProgramItem < Item + def config_type + 'program' + end + end + + class SelectItem < Item + def initialize(name, selection, default, desc) + super + @ok = selection.split('/') + end + + def config_type + 'select' + end + + private + + def check(val) + unless @ok.include?(val.strip) + setup_rb_error "config: use --#{@name}=#{@template} (#{val})" + end + val.strip + end + end + + class ExecItem < Item + def initialize(name, selection, desc, &block) + super name, selection, nil, desc + @ok = selection.split('/') + @action = block + end + + def config_type + 'exec' + end + + def value? + false + end + + def resolve(table) + setup_rb_error "$#{name()} wrongly used as option value" + end + + undef set + + def evaluate(val, table) + v = val.strip.downcase + unless @ok.include?(v) + setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})" + end + @action.call v, table + end + end + + class PackageSelectionItem < Item + def initialize(name, template, default, help_default, desc) + super name, template, default, desc + @help_default = help_default + end + + attr_reader :help_default + + def config_type + 'package' + end + + private + + def check(val) + unless File.dir?("packages/#{val}") + setup_rb_error "config: no such package: #{val}" + end + val + end + end + + class MetaConfigEnvironment + def initialize(config, installer) + @config = config + @installer = installer + end + + def config_names + @config.names + end + + def config?(name) + @config.key?(name) + end + + def bool_config?(name) + @config.lookup(name).config_type == 'bool' + end + + def path_config?(name) + @config.lookup(name).config_type == 'path' + end + + def value_config?(name) + @config.lookup(name).config_type != 'exec' + end + + def add_config(item) + @config.add item + end + + def add_bool_config(name, default, desc) + @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc) + end + + def add_path_config(name, default, desc) + @config.add PathItem.new(name, 'path', default, desc) + end + + def set_config_default(name, default) + @config.lookup(name).default = default + end + + def remove_config(name) + @config.remove(name) + end + + # For only multipackage + def packages + raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer + @installer.packages + end + + # For only multipackage + def declare_packages(list) + raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer + @installer.packages = list + end + end + +end # class ConfigTable + + +# This module requires: #verbose?, #no_harm? +module FileOperations + + def mkdir_p(dirname, prefix = nil) + dirname = prefix + File.expand_path(dirname) if prefix + $stderr.puts "mkdir -p #{dirname}" if verbose? + return if no_harm? + + # Does not check '/', it's too abnormal. + dirs = File.expand_path(dirname).split(%r<(?=/)>) + if /\A[a-z]:\z/i =~ dirs[0] + disk = dirs.shift + dirs[0] = disk + dirs[0] + end + dirs.each_index do |idx| + path = dirs[0..idx].join('') + Dir.mkdir path unless File.dir?(path) + end + end + + def rm_f(path) + $stderr.puts "rm -f #{path}" if verbose? + return if no_harm? + force_remove_file path + end + + def rm_rf(path) + $stderr.puts "rm -rf #{path}" if verbose? + return if no_harm? + remove_tree path + end + + def remove_tree(path) + if File.symlink?(path) + remove_file path + elsif File.dir?(path) + remove_tree0 path + else + force_remove_file path + end + end + + def remove_tree0(path) + Dir.foreach(path) do |ent| + next if ent == '.' + next if ent == '..' + entpath = "#{path}/#{ent}" + if File.symlink?(entpath) + remove_file entpath + elsif File.dir?(entpath) + remove_tree0 entpath + else + force_remove_file entpath + end + end + begin + Dir.rmdir path + rescue Errno::ENOTEMPTY + # directory may not be empty + end + end + + def move_file(src, dest) + force_remove_file dest + begin + File.rename src, dest + rescue + File.open(dest, 'wb') {|f| + f.write File.binread(src) + } + File.chmod File.stat(src).mode, dest + File.unlink src + end + end + + def force_remove_file(path) + begin + remove_file path + rescue + end + end + + def remove_file(path) + File.chmod 0777, path + File.unlink path + end + + def install(from, dest, mode, prefix = nil) + $stderr.puts "install #{from} #{dest}" if verbose? + return if no_harm? + + realdest = prefix ? prefix + File.expand_path(dest) : dest + realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest) + str = File.binread(from) + if diff?(str, realdest) + verbose_off { + rm_f realdest if File.exist?(realdest) + } + File.open(realdest, 'wb') {|f| + f.write str + } + File.chmod mode, realdest + + File.open("#{objdir_root()}/InstalledFiles", 'a') {|f| + if prefix + f.puts realdest.sub(prefix, '') + else + f.puts realdest + end + } + end + end + + def diff?(new_content, path) + return true unless File.exist?(path) + new_content != File.binread(path) + end + + def command(*args) + $stderr.puts args.join(' ') if verbose? + system(*args) or raise RuntimeError, + "system(#{args.map{|a| a.inspect }.join(' ')}) failed" + end + + def ruby(*args) + command config('rubyprog'), *args + end + + def make(task = nil) + command(*[config('makeprog'), task].compact) + end + + def extdir?(dir) + File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb") + end + + def files_of(dir) + Dir.open(dir) {|d| + return d.select {|ent| File.file?("#{dir}/#{ent}") } + } + end + + DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn ) + + def directories_of(dir) + Dir.open(dir) {|d| + return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT + } + end + +end + + +# This module requires: #srcdir_root, #objdir_root, #relpath +module HookScriptAPI + + def get_config(key) + @config[key] + end + + alias config get_config + + # obsolete: use metaconfig to change configuration + def set_config(key, val) + @config[key] = val + end + + # + # srcdir/objdir (works only in the package directory) + # + + def curr_srcdir + "#{srcdir_root()}/#{relpath()}" + end + + def curr_objdir + "#{objdir_root()}/#{relpath()}" + end + + def srcfile(path) + "#{curr_srcdir()}/#{path}" + end + + def srcexist?(path) + File.exist?(srcfile(path)) + end + + def srcdirectory?(path) + File.dir?(srcfile(path)) + end + + def srcfile?(path) + File.file?(srcfile(path)) + end + + def srcentries(path = '.') + Dir.open("#{curr_srcdir()}/#{path}") {|d| + return d.to_a - %w(. ..) + } + end + + def srcfiles(path = '.') + srcentries(path).select {|fname| + File.file?(File.join(curr_srcdir(), path, fname)) + } + end + + def srcdirectories(path = '.') + srcentries(path).select {|fname| + File.dir?(File.join(curr_srcdir(), path, fname)) + } + end + +end + + +class ToplevelInstaller + + Version = '3.4.1' + Copyright = 'Copyright (c) 2000-2005 Minero Aoki' + + TASKS = [ + [ 'all', 'do config, setup, then install' ], + [ 'config', 'saves your configurations' ], + [ 'show', 'shows current configuration' ], + [ 'setup', 'compiles ruby extentions and others' ], + [ 'install', 'installs files' ], + [ 'test', 'run all tests in test/' ], + [ 'clean', "does `make clean' for each extention" ], + [ 'distclean',"does `make distclean' for each extention" ] + ] + + def ToplevelInstaller.invoke + config = ConfigTable.new(load_rbconfig()) + config.load_standard_entries + config.load_multipackage_entries if multipackage? + config.fixup + klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller) + klass.new(File.dirname($0), config).invoke + end + + def ToplevelInstaller.multipackage? + File.dir?(File.dirname($0) + '/packages') + end + + def ToplevelInstaller.load_rbconfig + if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg } + ARGV.delete(arg) + load File.expand_path(arg.split(/=/, 2)[1]) + $".push 'rbconfig.rb' + else + require 'rbconfig' + end + ::Config::CONFIG + end + + def initialize(ardir_root, config) + @ardir = File.expand_path(ardir_root) + @config = config + # cache + @valid_task_re = nil + end + + def config(key) + @config[key] + end + + def inspect + "#<#{self.class} #{__id__()}>" + end + + def invoke + run_metaconfigs + case task = parsearg_global() + when nil, 'all' + parsearg_config + init_installers + exec_config + exec_setup + exec_install + else + case task + when 'config', 'test' + ; + when 'clean', 'distclean' + @config.load_savefile if File.exist?(@config.savefile) + else + @config.load_savefile + end + __send__ "parsearg_#{task}" + init_installers + __send__ "exec_#{task}" + end + end + + def run_metaconfigs + @config.load_script "#{@ardir}/metaconfig" + end + + def init_installers + @installer = Installer.new(@config, @ardir, File.expand_path('.')) + end + + # + # Hook Script API bases + # + + def srcdir_root + @ardir + end + + def objdir_root + '.' + end + + def relpath + '.' + end + + # + # Option Parsing + # + + def parsearg_global + while arg = ARGV.shift + case arg + when /\A\w+\z/ + setup_rb_error "invalid task: #{arg}" unless valid_task?(arg) + return arg + when '-q', '--quiet' + @config.verbose = false + when '--verbose' + @config.verbose = true + when '--help' + print_usage $stdout + exit 0 + when '--version' + puts "#{File.basename($0)} version #{Version}" + exit 0 + when '--copyright' + puts Copyright + exit 0 + else + setup_rb_error "unknown global option '#{arg}'" + end + end + nil + end + + def valid_task?(t) + valid_task_re() =~ t + end + + def valid_task_re + @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/ + end + + def parsearg_no_options + unless ARGV.empty? + task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1) + setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}" + end + end + + alias parsearg_show parsearg_no_options + alias parsearg_setup parsearg_no_options + alias parsearg_test parsearg_no_options + alias parsearg_clean parsearg_no_options + alias parsearg_distclean parsearg_no_options + + def parsearg_config + evalopt = [] + set = [] + @config.config_opt = [] + while i = ARGV.shift + if /\A--?\z/ =~ i + @config.config_opt = ARGV.dup + break + end + name, value = *@config.parse_opt(i) + if @config.value_config?(name) + @config[name] = value + else + evalopt.push [name, value] + end + set.push name + end + evalopt.each do |name, value| + @config.lookup(name).evaluate value, @config + end + # Check if configuration is valid + set.each do |n| + @config[n] if @config.value_config?(n) + end + end + + def parsearg_install + @config.no_harm = false + @config.install_prefix = '' + while a = ARGV.shift + case a + when '--no-harm' + @config.no_harm = true + when /\A--prefix=/ + path = a.split(/=/, 2)[1] + path = File.expand_path(path) unless path[0,1] == '/' + @config.install_prefix = path + else + setup_rb_error "install: unknown option #{a}" + end + end + end + + def print_usage(out) + out.puts 'Typical Installation Procedure:' + out.puts " $ ruby #{File.basename $0} config" + out.puts " $ ruby #{File.basename $0} setup" + out.puts " # ruby #{File.basename $0} install (may require root privilege)" + out.puts + out.puts 'Detailed Usage:' + out.puts " ruby #{File.basename $0} " + out.puts " ruby #{File.basename $0} [] []" + + fmt = " %-24s %s\n" + out.puts + out.puts 'Global options:' + out.printf fmt, '-q,--quiet', 'suppress message outputs' + out.printf fmt, ' --verbose', 'output messages verbosely' + out.printf fmt, ' --help', 'print this message' + out.printf fmt, ' --version', 'print version and quit' + out.printf fmt, ' --copyright', 'print copyright and quit' + out.puts + out.puts 'Tasks:' + TASKS.each do |name, desc| + out.printf fmt, name, desc + end + + fmt = " %-24s %s [%s]\n" + out.puts + out.puts 'Options for CONFIG or ALL:' + @config.each do |item| + out.printf fmt, item.help_opt, item.description, item.help_default + end + out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's" + out.puts + out.puts 'Options for INSTALL:' + out.printf fmt, '--no-harm', 'only display what to do if given', 'off' + out.printf fmt, '--prefix=path', 'install path prefix', '' + out.puts + end + + # + # Task Handlers + # + + def exec_config + @installer.exec_config + @config.save # must be final + end + + def exec_setup + @installer.exec_setup + end + + def exec_install + @installer.exec_install + end + + def exec_test + @installer.exec_test + end + + def exec_show + @config.each do |i| + printf "%-20s %s\n", i.name, i.value if i.value? + end + end + + def exec_clean + @installer.exec_clean + end + + def exec_distclean + @installer.exec_distclean + end + +end # class ToplevelInstaller + + +class ToplevelInstallerMulti < ToplevelInstaller + + include FileOperations + + def initialize(ardir_root, config) + super + @packages = directories_of("#{@ardir}/packages") + raise 'no package exists' if @packages.empty? + @root_installer = Installer.new(@config, @ardir, File.expand_path('.')) + end + + def run_metaconfigs + @config.load_script "#{@ardir}/metaconfig", self + @packages.each do |name| + @config.load_script "#{@ardir}/packages/#{name}/metaconfig" + end + end + + attr_reader :packages + + def packages=(list) + raise 'package list is empty' if list.empty? + list.each do |name| + raise "directory packages/#{name} does not exist"\ + unless File.dir?("#{@ardir}/packages/#{name}") + end + @packages = list + end + + def init_installers + @installers = {} + @packages.each do |pack| + @installers[pack] = Installer.new(@config, + "#{@ardir}/packages/#{pack}", + "packages/#{pack}") + end + with = extract_selection(config('with')) + without = extract_selection(config('without')) + @selected = @installers.keys.select {|name| + (with.empty? or with.include?(name)) \ + and not without.include?(name) + } + end + + def extract_selection(list) + a = list.split(/,/) + a.each do |name| + setup_rb_error "no such package: #{name}" unless @installers.key?(name) + end + a + end + + def print_usage(f) + super + f.puts 'Inluded packages:' + f.puts ' ' + @packages.sort.join(' ') + f.puts + end + + # + # Task Handlers + # + + def exec_config + run_hook 'pre-config' + each_selected_installers {|inst| inst.exec_config } + run_hook 'post-config' + @config.save # must be final + end + + def exec_setup + run_hook 'pre-setup' + each_selected_installers {|inst| inst.exec_setup } + run_hook 'post-setup' + end + + def exec_install + run_hook 'pre-install' + each_selected_installers {|inst| inst.exec_install } + run_hook 'post-install' + end + + def exec_test + run_hook 'pre-test' + each_selected_installers {|inst| inst.exec_test } + run_hook 'post-test' + end + + def exec_clean + rm_f @config.savefile + run_hook 'pre-clean' + each_selected_installers {|inst| inst.exec_clean } + run_hook 'post-clean' + end + + def exec_distclean + rm_f @config.savefile + run_hook 'pre-distclean' + each_selected_installers {|inst| inst.exec_distclean } + run_hook 'post-distclean' + end + + # + # lib + # + + def each_selected_installers + Dir.mkdir 'packages' unless File.dir?('packages') + @selected.each do |pack| + $stderr.puts "Processing the package `#{pack}' ..." if verbose? + Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}") + Dir.chdir "packages/#{pack}" + yield @installers[pack] + Dir.chdir '../..' + end + end + + def run_hook(id) + @root_installer.run_hook id + end + + # module FileOperations requires this + def verbose? + @config.verbose? + end + + # module FileOperations requires this + def no_harm? + @config.no_harm? + end + +end # class ToplevelInstallerMulti + + +class Installer + + FILETYPES = %w( bin lib ext data conf man ) + + include FileOperations + include HookScriptAPI + + def initialize(config, srcroot, objroot) + @config = config + @srcdir = File.expand_path(srcroot) + @objdir = File.expand_path(objroot) + @currdir = '.' + end + + def inspect + "#<#{self.class} #{File.basename(@srcdir)}>" + end + + def noop(rel) + end + + # + # Hook Script API base methods + # + + def srcdir_root + @srcdir + end + + def objdir_root + @objdir + end + + def relpath + @currdir + end + + # + # Config Access + # + + # module FileOperations requires this + def verbose? + @config.verbose? + end + + # module FileOperations requires this + def no_harm? + @config.no_harm? + end + + def verbose_off + begin + save, @config.verbose = @config.verbose?, false + yield + ensure + @config.verbose = save + end + end + + # + # TASK config + # + + def exec_config + exec_task_traverse 'config' + end + + alias config_dir_bin noop + alias config_dir_lib noop + + def config_dir_ext(rel) + extconf if extdir?(curr_srcdir()) + end + + alias config_dir_data noop + alias config_dir_conf noop + alias config_dir_man noop + + def extconf + ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt + end + + # + # TASK setup + # + + def exec_setup + exec_task_traverse 'setup' + end + + def setup_dir_bin(rel) + files_of(curr_srcdir()).each do |fname| + update_shebang_line "#{curr_srcdir()}/#{fname}" + end + end + + alias setup_dir_lib noop + + def setup_dir_ext(rel) + make if extdir?(curr_srcdir()) + end + + alias setup_dir_data noop + alias setup_dir_conf noop + alias setup_dir_man noop + + def update_shebang_line(path) + return if no_harm? + return if config('shebang') == 'never' + old = Shebang.load(path) + if old + $stderr.puts "warning: #{path}: Shebang line includes too many args. It is not portable and your program may not work." if old.args.size > 1 + new = new_shebang(old) + return if new.to_s == old.to_s + else + return unless config('shebang') == 'all' + new = Shebang.new(config('rubypath')) + end + $stderr.puts "updating shebang: #{File.basename(path)}" if verbose? + open_atomic_writer(path) {|output| + File.open(path, 'rb') {|f| + f.gets if old # discard + output.puts new.to_s + output.print f.read + } + } + end + + def new_shebang(old) + if /\Aruby/ =~ File.basename(old.cmd) + Shebang.new(config('rubypath'), old.args) + elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby' + Shebang.new(config('rubypath'), old.args[1..-1]) + else + return old unless config('shebang') == 'all' + Shebang.new(config('rubypath')) + end + end + + def open_atomic_writer(path, &block) + tmpfile = File.basename(path) + '.tmp' + begin + File.open(tmpfile, 'wb', &block) + File.rename tmpfile, File.basename(path) + ensure + File.unlink tmpfile if File.exist?(tmpfile) + end + end + + class Shebang + def Shebang.load(path) + line = nil + File.open(path) {|f| + line = f.gets + } + return nil unless /\A#!/ =~ line + parse(line) + end + + def Shebang.parse(line) + cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ') + new(cmd, args) + end + + def initialize(cmd, args = []) + @cmd = cmd + @args = args + end + + attr_reader :cmd + attr_reader :args + + def to_s + "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}") + end + end + + # + # TASK install + # + + def exec_install + rm_f 'InstalledFiles' + exec_task_traverse 'install' + end + + def install_dir_bin(rel) + install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755 + end + + def install_dir_lib(rel) + install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644 + end + + def install_dir_ext(rel) + return unless extdir?(curr_srcdir()) + install_files rubyextentions('.'), + "#{config('sodir')}/#{File.dirname(rel)}", + 0555 + end + + def install_dir_data(rel) + install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644 + end + + def install_dir_conf(rel) + # FIXME: should not remove current config files + # (rename previous file to .old/.org) + install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644 + end + + def install_dir_man(rel) + install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644 + end + + def install_files(list, dest, mode) + mkdir_p dest, @config.install_prefix + list.each do |fname| + install fname, dest, mode, @config.install_prefix + end + end + + def libfiles + glob_reject(%w(*.y *.output), targetfiles()) + end + + def rubyextentions(dir) + ents = glob_select("*.#{@config.dllext}", targetfiles()) + if ents.empty? + setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first" + end + ents + end + + def targetfiles + mapdir(existfiles() - hookfiles()) + end + + def mapdir(ents) + ents.map {|ent| + if File.exist?(ent) + then ent # objdir + else "#{curr_srcdir()}/#{ent}" # srcdir + end + } + end + + # picked up many entries from cvs-1.11.1/src/ignore.c + JUNK_FILES = %w( + core RCSLOG tags TAGS .make.state + .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb + *~ *.old *.bak *.BAK *.orig *.rej _$* *$ + + *.org *.in .* + ) + + def existfiles + glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.'))) + end + + def hookfiles + %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt| + %w( config setup install clean ).map {|t| sprintf(fmt, t) } + }.flatten + end + + def glob_select(pat, ents) + re = globs2re([pat]) + ents.select {|ent| re =~ ent } + end + + def glob_reject(pats, ents) + re = globs2re(pats) + ents.reject {|ent| re =~ ent } + end + + GLOB2REGEX = { + '.' => '\.', + '$' => '\$', + '#' => '\#', + '*' => '.*' + } + + def globs2re(pats) + /\A(?:#{ + pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|') + })\z/ + end + + # + # TASK test + # + + TESTDIR = 'test' + + def exec_test + unless File.directory?('test') + $stderr.puts 'no test in this package' if verbose? + return + end + $stderr.puts 'Running tests...' if verbose? + begin + require 'test/unit' + rescue LoadError + setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.' + end + runner = Test::Unit::AutoRunner.new(true) + runner.to_run << TESTDIR + runner.run + end + + # + # TASK clean + # + + def exec_clean + exec_task_traverse 'clean' + rm_f @config.savefile + rm_f 'InstalledFiles' + end + + alias clean_dir_bin noop + alias clean_dir_lib noop + alias clean_dir_data noop + alias clean_dir_conf noop + alias clean_dir_man noop + + def clean_dir_ext(rel) + return unless extdir?(curr_srcdir()) + make 'clean' if File.file?('Makefile') + end + + # + # TASK distclean + # + + def exec_distclean + exec_task_traverse 'distclean' + rm_f @config.savefile + rm_f 'InstalledFiles' + end + + alias distclean_dir_bin noop + alias distclean_dir_lib noop + + def distclean_dir_ext(rel) + return unless extdir?(curr_srcdir()) + make 'distclean' if File.file?('Makefile') + end + + alias distclean_dir_data noop + alias distclean_dir_conf noop + alias distclean_dir_man noop + + # + # Traversing + # + + def exec_task_traverse(task) + run_hook "pre-#{task}" + FILETYPES.each do |type| + if type == 'ext' and config('without-ext') == 'yes' + $stderr.puts 'skipping ext/* by user option' if verbose? + next + end + traverse task, type, "#{task}_dir_#{type}" + end + run_hook "post-#{task}" + end + + def traverse(task, rel, mid) + dive_into(rel) { + run_hook "pre-#{task}" + __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '') + directories_of(curr_srcdir()).each do |d| + traverse task, "#{rel}/#{d}", mid + end + run_hook "post-#{task}" + } + end + + def dive_into(rel) + return unless File.dir?("#{@srcdir}/#{rel}") + + dir = File.basename(rel) + Dir.mkdir dir unless File.dir?(dir) + prevdir = Dir.pwd + Dir.chdir dir + $stderr.puts '---> ' + rel if verbose? + @currdir = rel + yield + Dir.chdir prevdir + $stderr.puts '<--- ' + rel if verbose? + @currdir = File.dirname(rel) + end + + def run_hook(id) + path = [ "#{curr_srcdir()}/#{id}", + "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) } + return unless path + begin + instance_eval File.read(path), path, 1 + rescue + raise if $DEBUG + setup_rb_error "hook #{path} failed:\n" + $!.message + end + end + +end # class Installer + + +class SetupError < StandardError; end + +def setup_rb_error(msg) + raise SetupError, msg +end + +if $0 == __FILE__ + begin + ToplevelInstaller.invoke + rescue SetupError + raise if $DEBUG + $stderr.puts $!.message + $stderr.puts "Try 'ruby #{$0} --help' for detailed usage." + exit 1 + end +end diff --git a/vendor/plugins/imagesize/test/2-4-7.png b/vendor/plugins/imagesize/test/2-4-7.png new file mode 100755 index 0000000000000000000000000000000000000000..cc14a3154da1f602a49f6184eb99fa0d09111532 GIT binary patch literal 11639 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 E077HjV*mgE literal 0 HcmV?d00001 diff --git a/vendor/plugins/imagesize/test/4_1_2.gif b/vendor/plugins/imagesize/test/4_1_2.gif new file mode 100755 index 0000000000000000000000000000000000000000..2374a13952283d323ba46cf4763c2a0cd85dd73c GIT binary patch literal 10794 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 QWV#NTD=;xQFfcFx0Ab~+7ytkO literal 0 HcmV?d00001 diff --git a/vendor/plugins/imagesize/test/pbm.pbm b/vendor/plugins/imagesize/test/pbm.pbm new file mode 100755 index 0000000000000000000000000000000000000000..f61ccf548a7405d9f2dde934ec6fc0e33ddf0be3 GIT binary patch literal 637 zcmWGA;Zk-kN=+e43?Ib z5P`nFJ~RU%_M!5ND&6oRFfG z7*`Rmh7$MV2~UXoiFXFsDo5RqHRwjeA8W8+3XY~9%rJqs->^ziS8%9@|MBC;SFKw0 z`0-<0!LkYr&}7Neg=WYocQgb>Ltr!nMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$( zGz11J1OyrWF|aT&LWUq27#NwsYzGDg21X<{6C*PNGXn#|EdvGyW~eww4;z%t#K6G7 z%gDsQ%fP_!z<_~)kCBN%jDdmSodE-bAS1+l4h9AWA*gzgUQs9;WUd&L4YF4ps-D4s zfkBFq73>}sLk0$ED4WNSfk6hU9%PONlnrtN$Qv9CAn0ZlQ<9mMrUxPz7@Uhz6H8K4 d6v{J8G895GQWe}ieFGR8X3n%^U|`^Y(E#cV$J+n^ literal 0 HcmV?d00001 diff --git a/vendor/plugins/imagesize/test/tokyo_tower.jpg b/vendor/plugins/imagesize/test/tokyo_tower.jpg new file mode 100755 index 0000000000000000000000000000000000000000..bcedafdb9ff76f59933660d4986be7efe6e3295d GIT binary patch literal 32458 zcmex=7%D(~=Feb02bg4F0PAPr0`nLlJaqvukBfm3OfxVrf%Sa_ z^E?>z)6y6i8FJFn7}&rfj8KtHUA3p@o5mgM)*UgNKuoN06I~TTqmr zhlgKOLReT-SXe@k2MnMTn2kX&@^W+Y^6?7r@d=3V@$rd(2tE;r7C{Kb1EnzZf(8B` zU=ZYB2w^B-W>jKe5@ci+Wc+`ZfrWwn{}D!e1_nk}Mlb+*nSp_UnSqgsg_Vt+gOiJ! z5nYmzfr%L=DZs$U!pO|T!o!mRM=?5CNgp1Mki$z z(V&A##wJBg7oFKvCk20a_%XTIRBX|vW;K_|At|nh7MGZbUkZJc`e}2^;mf6uKf9?< zS<<>?>X9o?zAW8(^y<^EVQFP;)0S;JcJ0|WbNBG{^7iS=w;#X${JS6n6B8p73k%py z>};&2U?(UV3b8l_CKf6Qvl=x{6al&5V9>=6#wtkde|=Zf zkENPkUSTVizS1OH;F~mJjINdFHBI}3SuKBNi%{NpM*4()+ zQ@5bqHfRZW#ip8o$YLL8Gd*T8Sm6w!6_o2OqXdUg2ln!6JV+YI;2 zU_EDlHJR=EY71H2o1%vQdT)x|s(1BOJQl@w_uY-t_H)X<8NaAE+g@O$AF=TH3E z18ncBx5cF2UYLIC)860v4Xecj=l9=UbPrjUq{uEuHTU$Em zz%kxy)^Dw6{{Hc`Dq8Q$+noi|zeM>Sd$)9cp7#xjxE~#f)+XCEzu$aw`(Llxm#Q}j zujc9<%04c)_@LT}?Aq!4!MS zDZHeD?U1G?^jBD&w2D*vba;vPUUx(V7S#(-NjbFW?VXT`1GnwqgwNSljfIQ z%lj*Q`)Ajz3v34z&rDF5P|hAYS>&Zs>m*N=DgPP%UxI`%%S--KTX&Vaf0a929iRMU za<_M_x7n7wJFjlMeYyFh1ovb;8R4^94Hv>i&Y$G|`_eYwY1hKmUN`O8-wd5uH+kx9 z{m-zZv^4Cx;o6g5Wj9}~-#D%QL6rWXmxY_YN9b+5oEtJZn&m%3)9>iHVcOe&o9~wW z&#>gLZP#>g#`oj3c5u7u0UrAFjD9_1?z% zTZ&8Ca;xL6U;Wps^-?_SdC>8s>n|rqu9EsL(RMxV;O2ijf4Rd|_Zl zh4i+)P5bj#|FZY}&oF=YXNkGYh04J}9UuE9`#jL$+asj@Qp4tb{LxasrSI&%wI@d@ zw+EDMzyD{|yrUC#onQNvL2u{1i<4e$%AR!7%<=fi{C_>g+A*_kJ$-(>Oa0Ki@;U8n znSB42cBQ=3jC!py$y4+HeqVhfH?>RVdTMO+8>?Ts z6}Rjs=T7auzxyZe(%hs=nai)8sMcJ#zTb1|-ag)2QPS`KCg0!wrEa!X?fhl`8CX`Q zJ!^3k5UUb0+5hU_=f$UMth@Rm3wnPjf39!0pDzFBPj5_K*Bha?S9A9m?7g=4j9#j9 z{^|+0B)|3hUz-2)?w?0jk5rT&@2^!`ixgNoaQ z<)(EPWbOL1ZI5$KMe@_$+ixq93;%A7PyWko`~E+J^FQ7gi#IQ)+B~ue>^ojH>uq5{ zX8w!6-rMf)`nGlc!t_6;_KPBK7Ja-fxYOfh0`K-O|2EaXxtn8A;m?z#EYUxuKKkj` zV}|YG?|=P0GGp2tshrZ#z2C%sO^-1g|gvv+@)&GFB!wZC}f?bn5u{W5EJN}68n zpYUwMuO6M`)sx*Zh?shun?Z@zo|FV|O9kJx4uVi?Z0}!X70MZUvE6ycT216Kf{8v z^FMS89W&Hrym>hPj34#Jmgm(MIlTzk#oNB}>1Dlc zC!DFd_H>8)$`@_>^ZM)_M!%`9Yg(UvwddKj+s^SXZd|vWCU!XHTD`@$Jl%W8>Q#L# z_ppEY{!Uf?mk;~HJ=gig85F+Fv;X~E)ab>kUz4xCEwEmd8o2Y?&SMOhq@=gk_Lu*W zTAzQlX4($ZnI^X9Shg-by4*i|-;BTi8Iqi5AMoXwXy@&&cvkvv;FtHC|6h6j@!!Fh zyD$8*=EQh#kM#1rMLa-eo;5Oe);Z;{~6Zl$*Ojh&Hudr z!GDIkdn;A2%}v>V^DoZK|C0IV{OkV=$zQq_|GWGu^gn|| zdES@vHsJGTVRs%U=6{{4Yw%d9(NWpS}IE{z3eQ?(;$p zZ-2!wqzw`fHs$Kl^KSTIG z=6|9Y=9jNuxc%z%vn2Dn^{;BX-`-#S?mvU~i~76qffcX3Z1&s7wx9ib|I_@_Kd;%; zpY5Oh?62|S|&%l)_i8QlMFJ-B4eqkqZrpQHPq?Y|rU)wO89UHtR9_)qiS#eb+@ z|DR#S{r@+?ZE#3$gPnmD)RJao`2UC}!qeF~J|M{7&C|z~fsv7cfycuqGcTV>fPo=5 zucRo*-AN%LGD?B{90L;rCj%RUAp=8Va&duguv-YIaqH>otWX@}?gU~Z@V9G_e$QoH zj{pS)gg8+w!Q_IX5=hU0!8j$gIGKTgv4w$wA*Z~g03`l_fq_9JDI3IQ0`4^gZfq?xv7c83=Axw{)2mF1Pen5ypj+l1j&fVC}{kA4g|*;qu3dQ z7(zQjEPoLLgT+?{2IdI}v80&{4BJ~77$j~X#8ehAFz~l9Fl;-IQYbD+OioqM zMNhBl)JL?OAfs0<pl&3`Pv*4Au+| z46Y1b4E_uu43P|R49N@`47m(N4CM?p42=wJ4BZS97^X7JVwlgcgkdGaI)+UQ+ZpyS z9Ar4gaGK!)!&Qdc3=bHdGQ4K^!0?UXHzOk>J0mZnFry@+JfkY3Hlq=v1*09KE29r% z5Mv}`0%JO39%CtE4P!H7H{&G6S&R!AS2Av7+{t*5@g(C##+!@}8DBDfV*JI#%*4Ya z!X(S2#-z_=!Q{x~%@o2E%aqPk$W+DD!qmq!gJ}`d8m4Vb2boSYU1fT}^qT1_GXpa> zvlz1?vo5m*voo_la};wLa}jeLa~Jb8=0(iwn0GNBXTHq*fcXvcPZl;7VHO1zT^4H= z50+4tWR^mfI+h-mSu879wy_*xxy`&Q$aBy?Ta~N^BaYS+CaWrvE<5N8C&|;y(LXU-+g_VV!g_DJwg_j5)6@Dth zCZaClDUv19EwWbRoX7`JAyE_2FwqLp*`j+zABZuFsfl@t<%so*Z4$dC_Dft=+)+GL zyit|H_*+R`DO9ORX}!{2WiDk4IcsK~4Ms??~gR=K6hscNB`p*mglxaxN`b+vG{cD3zlFVrQ}J=Lq!SF7LA;MK6# zDAZV_aYd6&(?T;_bFStEEha5ftqiT%TIaQyw9T|LwdZPI)M3@J)XCFXq;p-DN7qre zOn0^JLp?D)AH62M?RxL@RrI6uC+Z*9|7T!okYljK;I^TVp_gHk;V#2ZMp{P6Mzf8s z81ovt8P^-{F#c$wZIWs-&*X-wu&J+UyXhg*zh>rUMP}>FUYe_zCz#JMziuI75n$0{ zal(?-(#f*ka*yRtD>JJSt4&t#t#z%ltyfvUuu->3wOL~G*jC9l(RQKj13Lw~1iJ-x z59}4~6YUq-KXOoZNO4%^@Z3?;G0Sm{<2xqai8EC*!2za^m*J^T#K~Z%$xM2v1m*@F&qfaZ%#eB+sNdNgtA( zlcy)YPH{+?lJYXuHg!_!^EBJENogGzs#`Dn3nM-(>Zfi=Ep3Ltod2rv;DJ| zXaCO$&sm?#k(-daGfyZlJMT!oTz*CV#RBbuwt@$RR)tdwKNNWvEh}a$jxF9%B2rRN za;8+Hw6*kMnO)iJvLEGP<(n%6EAlGNRBBarRz9zCt6EykQk`6Vs7A4-vF2f|W9`B^ z#=4}sL-oq_E%i?u+#6Ojay4c*o^3K{n$+~AIlOsSi)>3n%i~t}*41r%ZAER@+pXK@ zcd&G1cAV=p?wr~AuPdeNRJTF*wC+DW$vvlf4SQ$w{_jicJJ)a4KW_rtguDsYCfZM2 zF-dSz)uhLheJ5|5qA;av%9p9}Q%_DanKpkq*Ywiq4`%qx*fCRO=7gDlW@XH}I@@XX z`Z+RlI_G?!n=<#(JcoJf=F86Sp8sn>=7Jjw-4||Kq_$|3zh7F|~ zUTsX+cx{vSrbC-8Hm}>Fx@FE*;jLZU7`Ih!`>;J@`-2^kJ1*|@+IeV~^{%bE^>#1c zqqt}GUeUe%`?&VC?EAmJYX8>*1qa?7Oh5SeQ2e3Wha(POITCo}+)?kNCyu!tJAB;n z`2G{NC-$7QI=Smwz$&a_DQo*L&Y`zy1E+^+WQ7%N%N${jao05wUnYyS?UcA{% zJS3&$@TEr_YR#Nn5|S-bT-}yz3A-GsA@%9;XVA!fYH90K$ml(e!Fvmjh>VJk87p?2 zxbfnLrln_OW@YEhl{-(~eECz$$}1|Xs%zG&U8ion`UM%~XJ%z(VP#|CU}nw*kGO*- z8XQ>zg%g$73L7UHE!_A)4Q{cqeY&6?14(bx97 zY27f9t&3RQ{QlZ<(ZZ@c+l}E>Q{MaCSlv8J$Ui1@Ux~Hs$FT0-e9n!o(MX#T{to-)6sD_`6F-Q;N0lPcbAM`O<) zd3#y3TzRkd+pZlOtz|-w?(x517`9Wu?aR^FGgsz>E;^Fmwf)S6S?{~n^7z+&3@@^N z-?e+@y5l*ai;j!t7)sY#tnQY2wEq8v51Q)(ySBKxpBF8=u{wFFVOWQBV@&AXRbiN3z_j zw=i64;`X~;JKb|aSB1RYruF#RjMXbR{zj~BP@CVTbycgTFkJ4+%dV|n%-b(^?cVoe z^~$cTzANvG7RVNc2N!nj=*lS!|9|m==2G{@qfw@}_Lpfrj7nPDHGlastw*-|*J(Z8 z%lN))N6E__N27m!KN`E;@wRBG=Dp>jWe48gUZ(YSWpLMa=i8#CnS0G7R`33DG^R{x zadOx8sJ{J*UAvlp{rMQWh57Jp(OAbXkJi>&tWK%V(|Tafe5L$o)W`KPp}V-`^KPuV zyzQUu$FLXL+XK6{II8^k@o3$${|v`Pvzqq@KPn9S-S>Q()8vDbtinCKIFZ0r4fTA;~>51IsmDXR$i>UD?~Ntx<36=7g?&8TGzvn}6Qljp3!Y_S=NszMlW)XpB`}?Z@y^ z)1$G$mqiQTKkV8eWL5fa$Ev%>KOT+oFctZkw7T|qd`;-C{@pd9cgv4P+1hRl&oh@V z)4KN6^!3B8?NO6`Lf0>Uc{FO}8$PX9m!Eg-__{tP^#A1#vYD4f%P;QF3B9Vm{(jdE zdAS*@6Xso!SiMv3_M>&Y&TqSRE!$mdv3g_ZRg<3;kJg4~T^B9&cQUtF-N_K}&tmne zs-$)7S$#KFz54rOb$5FC9QT`vDEB+ z*Y*?hUv_QrE|XZ@XZG-kuOzLzzfbFW?Z@!{S3bxW7>2dSgzmb~6ME(M#<0KJ z>?BsV`))fLqZwZldLTdkYS*@~-AU_SUtgy6(C@Km-s~&oN29HCeJkRQuC2Zw!v*8!8iu`a|MKl9<|GW~|=+i~Zx#sQbSjt@~!3v^F@oYj;6mcwQ9Z1%!Zf zygM2tYySIV*nxYCMT;5lFVA|ky5rW2)p0CyKZXl9DvM?`StYHN3NGHKb=CZ>Pw3iT zeEZ~eLf1WM?%L|;xBJoB_m8iOMms+;KN@ZCrgc4cV|e+UN9%0Oj>h`6@6)>Q&M>?p zziW5y$MFBxKFDTwZPC6jT56TFw(HVj(VVcB(q&q&zWv@9w)bP`?QgHUwr=+cEzG;y zr*+|1UB&A3gI&5dfT=2{#wJZ{`P%8R`2~aCv;WyqqQaK#}9AQx~MkgX!OUUvHwbs zMy=&sruBHk--^|Zuh_I6`h>2VvHJh@52Air4`V`aPcjVqZn1j%>)WDvyOY-DcWw7Q z%J*aS3Xgv~R+p&ccWq<*#iw;uy6*Wlt$TleKU(`P`|-ouq8ZhXRyW)iE#*75J8AXz zwbn^%88ZLQSoM{M|LFHQp#@5fCC$?KWi2~ed~~ARXp)wW1QM-4=^RIj*gKwC>*W zn$UHBYd41O{`RtK$K=@GWfH5mFMR#w(YkLh3d8n?X}x;1Zf*H8t@k;hYfsv43=f(j zvD#(wbAlGUdQ(P z=Y$?UQ1-rS*Rrigqi-jFd9->3$BLsdTwR*CMPmbF_n04z4Rj3rd^DV^+(Iom_T$f?vWUX{|v~DWA^$A_|?X^$n?OKb~+ipBso!zzn|HTiYRuxI> z7JNJ!>o;R{3Cr8A9Sw$IFEry1i)Jw1d9-$7aMyPKn$RoDPm31FS*%|9QTX;@(Y&T9 zwjV>UERWq7uE9{zFB7_p?`~n}pDKaE(1#u`_uYQ9s-vO5CUiz!^iRF_=i>@4+iXwU zn!VD}@5%}fWtk<(Zy3(x`XzSDEP3{#Q>eHS4MyO&v42vI@(?%WAfjm zdj|UNo@~=BG&!a17xeMY*ANi~nde_F9yLgvq^|So+#QEfY1zH;=IQIF#pwwu%9Ouk zc>Df#eP!~0hM94NSD$Y0yX|?YN3*b$Z@!gy>m8Fz`VuF$r!5vdx$m;U{Rg)#dGj-0 zno9mC>=I;u*~{;5ZGY>_-HD4N+GU=pDp@QpkNbH1Ywo*>{|tYgq(AAK&;ImG)W24y zMJB0Vy(3;E_dPOO6yw6`B>XLnY0m4@+ww|o^38d4x=cO!?%|gP`!-Jh@Vz)|TEuI= z9HCp=+u!~v`m*1Co#KNx%aiY0fB5-RB$Mm(`z|p7t8mfi;|IQgN|t$Bj>fosS$|qI z+VTGSeOj-0H-`0UUKcHIJQ{m!!H-Alme+)?3R)~$Y8cKK*tPYO#p;#UYeN5D`XF~$ zwCr|Q(z@@mg<&rpySBc+FPd}V(b~TjtGBIKr*+?d`97_;{U46TZol8P?q%23jrae& z>{=&c-P_)IG+Nen_oKB9+DGd1wDvlDTluzY)rwoqFC|tfS*&ukN?O0t{<&zqR?Wrw z)yJQge%0BcX?erlCRp0@se1SJ<$8A2vI` z7uR2I5>dPOVrEJ4<)_9UJ*SJ#7w^~q=zZk);g>3Z4Ikcq`QpKoH+w@qady1bU!KSK zH%@NqU4O;TO?U6Vx);6o)3UvZ%d-RHX7|dxmPv^|$eT1V_ehH7f{8m88S4J|dA3ZC z^SH`qMoTxPcJamP;`R?8^~Ue9?X#I9k=m_OxA3*V=YRF$tGoZ6{~X!>Z2Jt8hd&FS z$(jfJ+Ofx~WV?7L=YxeeIaC&3S#Rv-5IN&{{-1?E_u8;Cv@F##V*9$Y@85q0|4Ze+ z=CY^0SSs^a?GMu&v3q`O8IfzDOsntrcMw zjlFVh#_DaikBgSFZ_~Q5yslZa(E8EZMxW4)zW*8ev>yJur?n?|pVq2XR^R?ctiJZ2 zL2Ixy{mbGn zRn9Zsm;QV4z4kxD%gA^A{~0WHK9lZ0W4&MRWwG zy;SYAvwCs2=X?m$@OV1yaQpHvZ~jeRbo|DSf@i{K4Gj8f;zRZ?+-`sD{O&#Lf7YAM z-8Vb2khlHCfjQ~h`;_L*@oG4xlyRl$$j7zu?aMd4pTpLFoG!k< z%Un=@mGj%wb#HgfJn_&-#@_w$&;8Fnr`$UJ^zW1pTW+Q9GF$k{Ex9jKOd>#2G{MEV zggNy=_M`pTRyTeNE^c$4An7sx;Y1nfKl&ffUQ2qr*P)+t+7(Cpqu<*UpPyI0|7!D# zs;wtF`MMHz?w{_zGci9`b#tfB{Ggc?AGkEsI+naVvC-XYS>&xKeRiH6W$70Fi+^nI z&3`CkbN*v((7L?v^lXNiy_3{xZIWNz+PD9?@P%JB_YM9toJ+3!_T23=%dN1Ee{*&n z$+|ASV50s)sSl6Xo#dwKfb{xT!;qgub(^?kd0%D#Nqt?Ra` z%I?f@j<=Q{Ys~N8y%R5d%3Z5*#~T~t%lCNs6=b)wiw5PH+%E3glI^_xOm))g4DHLJ zQJFEJtHKkvX+89+u1H$T_w{H@=EKiNV=q_LTC8q0V_v6q?aEriusw$1xn0}rB38Q} z7p?z)<%8H4iPbB7{j?rln%}2&fE(~Xlm*8j9z`Bv^?+ceWZLBDGMGn}*YyS@1fd$6|J;%mR=y}$mU zwxed_GFfAvi+{RTMZDbA){toSAx?AS)irNlNjOVuEZ!aP`T04s`wz|uMJ`E6w-3Gl zwPMfjzxUNIEbKFAIDWw4U*E?c-)rBe|JncP&ZJ*;30F<7`MN#Xb78ah*F~RMbsuc_1RDlh)o zpK|sY_i0%sSFV5aR+sa{&6>LYu=t8p>pbzUS<38 zx418EZ?k_p_n-R5djIy9+dKa=oJ);1iTXbE=4sEeT{+XPn;YqiO?{i5Q5m#5XD(mj zZ!RPE&j#}?o-plRWuJcZQrVLuA0AI&a5)#$@$REC=k;^`Q&rb`+7@4tvvh5*J1!b* zr%)X(8tH%h&+D!&wfp9TX1OTWd=-Q9rNo(K7gyvuD+W-IR2k`&AkkF`U0YhL?S_Se=~v zx@-GBt-J0%p}XEbFbr#0?zm6uZn??p+oJi0_UnWe+}|HJW7XQdd#(#rg?+TSByjeS zsotHCqGZQl2Ub6(V2PPhj4$@Z|5^0e_SEUpXWWt|v9_Uyd~052J#*=^><~P4>TSeR z_rT+i!+uz%?T%h;k-)<`seXHT?ajH zle^);o3E8jnO2$XDD7(?Rj;fLh!-yo-KQEN zsG;idJ8ogv-$h1IdFLgb)-c8FTNkfC{YCnUD=y8i4cUJb{;I!Q*Hw9Z#{TEZ`_2Dc ziPf_?S$Z z$!Wjd>{-8Ol9-X@`tI-p6;D-MnjF;UKQ7mKHdD!H0`uvA)|=#BRl9Wcr9APBOK9*d z`{DMVVZG*I&bwXTmCbw#8z1c}{oAo#|MkA)PgB1{J)gE!a?QK75jN&!eaR(>kF>ux zZ#>iKWi;(^o9nTLlN`eGAy$3$cJKGjseFI#di~s8w&ylJ%bp!=Z}dW}Zd082uRX$t zC6=s6=n~g2w*Hv#XK`;v*8VLThdEw;K9$0K`jARxVdd|?=iL1H1D8JRyCW0C{OW;q z{iR(Zw*MK}8+@wM{yw?z_Vazw;H4wi(Ol?za*`* zetTK8@a^ZLQTGeGwrD#PhUd9yz0W@`TKM5;lx$(xo^wk47^;?b?0# zYtq_pw?#|sWkT;C7R?F1Em~UF6S{ZhKCO2%R@X*v)0&+TCHrinNgH?OvdeFpVzQK3iMt zw0+n1Pq$^2PQ80@*JoSuB_{XYhl@_sna2CM_jlykNVKhUa`1jN?ajs~Qyf1$bl(4O z(qGT)`*&kJ@l2;^vpLchvn{wM?vGZsA+^^fW+u!JFP&=fdvUBPyraZ0s zl-7XyxWp$@&RtTloUvHymRhRq<^K$N{}~KQkA8hqqPbw(e}-u@C%^j0_;1gVx;@9| zXJi`6hy3U-x8J0@*m?D-vW9N0%k>JSol3v1ZC!UWV!5(NBlo$3Q;HO3Y4!FU+qwSi zTQS3J7Q+9If7=5W+~ofZ+W#Vcid{ZU@lK+E;bPl=hHTTB zyORSa?~;4_pCSFm+bwseEro9=&W$ESHbkDKD(r2d+h9e6Xcpjn5#quzY|+aHVV^`p*vUHLLMJa9|c z<{fkGJ#LfxWaoV1Jk$&qH9vkjcl=^&sZS|bDa`tx%IX;|OTGA<-(<354}8Tpyaw;$b6af1hzdjZl%AHQoB@Uo0wO`CUl%t6pViV{8EV3ouZo9GS)`jb$5#?{UY2Ex_YZ$iD@lx|)(d?{}+oBoYJ{*m`d|$NO z(Yb5wvfoK-FR#G0eSe?U{n(G; zrLVVX-7UW_nzuWz{KL^0_Pbp>%U*V^W8W$LXnn%Q3+~hR>`Y#=#VNKvjC)1aMAoob z934vcm|U_=avb$dbRwlTTAX!TZy~zl<|`8`JBdQUwD@jX`Gy45n=z^K~2C%0eH?vwI2v&V0ebvOC^>8-hJtN-cx zr~RjObIsO^9^2Q`r#j)pw-?j7cZA+#W?Hy=@~oBL?kzV^&iFm|nBDP%JzX;K*Y3Ws zil4P-@6)r+U&^PKNbB0&%MkL&Q|MGFwHL14z#QJSwN81K&E|RjAxr%C-sUl2$UVuu zBK!LF$=;_vY}n;yY`mkVI5^a4*S~6)Ki6M&aEG-{ zw33FX-l@#}eX&#c`P9FCO>zn@T(@j`rOBg*f$4mwbKZWPb(Zn*Z(rb>0RVM_5Hobsx^wbx)mBv3SD7cYpo% zi|w;C@|Iw~{NwxH;L}#RM|Smy&tl!WcVSuS74>`B*`+Jkn(Vkf34fa?{qXO8o=g7K zk5u}%-aKY{vf*FW&-y=x&w8W%I)XIiY@M!jExP8weIfsMOoN={ri-bM8b0m#V^tGl zS=BD^u44Xk(XE?b{Yu-JDY{4S)isUF(YLuHn(jo;_j0;$d$(25&2FESD!nJS$9&N{ zJ70{!dawTcvSWra*R1|ClIzJ`J07hqvshiRI{K@<8)!iN!Uz7E z&<$ESaPVxZ3w=-MF0-YIw0^ z_1gT)_TGJSl10mY=2`Z;Q`1h%L_D=D>QH}hyIo|HkCV+w#&5@F>fDRn(3qQ3 z@8y3^+WDEBuj-fS*+)H!p3fIu$TU^PUFPFnH_umT>B`~z**_=$QLsC{?6^#TAoGOh z_o`0(oR(Xmzg5<9Yld8M$%@o%mCL_e@mRcmxrA5!L78jEoY$R8Z0)~rtn{pM(A8Yu z=j*N&tetxFjkr-ui_gbjHKHdMJ~-Odb#1NBW|1Ebd%rV3{}nO$@@nyp%C1L;uKiuS zxk=lsFWAIq-edvI-$!}R{w#U6n}5^JtwNXMIo19%+_X3>mwaJC>F@i-i+z_xWt`cy z_4fhAKB*$NHgla90#z*{#iyqyf8<&1XYxrYrmo}u>GR9obsn8aPT;F8^Gp9!KU-Jl z%j>^+8GE)ai?#eKe~#aMvhxuy$!=?Hfy%lMpYpp67q2{ODaUxMe(k5M_SQ6;aE;IF z?cy7by|-DrXy5)-x4hT#27SBvz`HVMb$PyVoW#MRi<6iZwXM3cF?ScwEt$(lTdFGR zAMf6Dh-GPvb>*AcFZWLpn0;kmZ(7$S5uv?v)_SP$23a0iuz@+*ul~vJXN%3ZvN#+H z)fA42Kcc-WK3(6mKkZS=k;lq{`xnT2{@d{6$is_g{xi(5OT40!dsnAqrsDQV_ipm8 zJ1x&;pgt+Q^XYx_nWkz|GJ!L{`aOO1we)vPtlb>{@M#YHJ}$NY8IJz8z4A->^z`y7 z+g{b^Y+toU1{Y0~yyrXJ^WCoE!od4r?UAo%O&TVw-mVm2#PrLc|NLo9y^{0#KbLsr zrR0@`=YP;Y^m{E=gJ!_pnqq5*tTfxl9Tvf@ObiRS586D={}ugd=hT_EUZ1|c+RBZ4 zgFwu`S8k7GH}lSJ%v9as`ge+3+PUAGJ~0~0eXL*C{`hSr-;G0l+Uw#Q^|!_BIq%-O zlWB3yOF6?t+cvE&wLez7wf{(3x9;&_(I}5)2mX8vFMqvH>w15i*83%o)~&cNnw_8- z6S{X}*see4wBCJv-L?DvVbJ{F|BD~QeyrXY_Q&kLXsLDZ%cHSg^B;C?zg`o1pzKd! z*msuPz{g$N81Gyb%_&jg2|WXY zu;wa1mwwChoK=*}QU%p_&wt5HzWJwc+Jebvm=C|-^}G9pzsc)QnZ=nGGEb%M+#V*- zA1PG%KKy%XnAwwK^OmcxV)-2>`FvNdy$t8Xg@2;uT`E7n!OyxcOGjrCRn+Du{@+<1aod4LxA9{XXzJ*=x z({znb{~1zaUoQDp#kcpF#GbuRL+g!C7Ur!qJ$i6zq+)p4B-2Qt6}J~{=YRL_()yZ~ zo)3>6O|%bR;{KKY^UkdxG6?|tTV3??VmJFdiKn%KU(+BoyD29ecmJ2CXrS~ z-mTt+0js*~^xJ=Kp8x3Nq!8us>bd)5-&XGSQet>y<{xpSYU$tjho8OQF1~EDll920 z*2_0vi7Q6Q%KLaM-Y0fZH}{&`v|iD$*7GY?hyAwXnP=zKC}mq z%L_WD*2|oK_n%?u=~wG!mw1%E%|7kDG-ku@5FJ|&li%Xz;>Ix(UE8w1#jUxYscd6+ z@%x#xCdNGr3hvZ*1%LT)_~*s;mql%wlTV%3Q-0b1b4TOvw2B$eW~Y9YWwZ9xKUH?f zLn%`I>bj0_9rKAd_(FoC{%&1xc3aJ3O`Blr{|sjT8D#Gtdgk;{QCWBU?YuqvG+D04 z74FK^#ER3B8jsgX`tp@A z+}QX1oT{*pqvf?YE{Jjs6Xq zly&~{Xk9>6(wftsF30cxw0%y=-(vr5=DB$>zPYC_3pu?CowDywnd!Q0>tNshz-99+ z=LzcVt9g`p>s!bt=U~p{ev#e#WzR1uk$!(^*4^{7_Z$|AsciacU&@oGo3OnrakY+;U7EPzwBRfF1Pep z|EpbbGg9_k$zLoVQEeLWZ-uwHUZx_;&cF|0b9RP5Kj-f$`1|Cnju+)dKTF=1Nfvpl zHrUO7WYhm@nfDs!++TX<-M4;vy0q&MXH)jhd!K_UXEdeMdmIToDZT5&-m;ey`W85) zC7iDRoP78~>6f1cyY^VsY*sm~E`Ru8uQnkI5@1{;~eR|IkK$@tfSsFA9_Ai@5!JKmS+mRHZ96 z%a>NIUtL-E=#mS=otXWpVu=!9i43`C+DYl_lx&meRbomf*Tip zl>Dw#_}Xv#qU!#PhZ`@fo%HIoU!&fl?b}i(rtF;PlXX_5ra^F}N?*;+?LRH2|Cw!L z(ew1hV;k%L3_NcC89e_Lw>I0$tnTjUOU>EzTI$KUT}O)j^93@64zYj9z1S+!uCk?f z!{5cnnl&FE?^14PsGn2owtw*-#q&L!D!l(0;{DaumGs7BmJ7wbGCZ`c%y`r7BL}Yj z*t~MFW|YRw3f^5`En`e2`W%#nDwderci&&TQ%;`aPMyuYz@MIJNuNHwT64hUx^R_| za9DVwbJ0>8{=Tw*m!9l(Z@(+?r{BHrTbTJ$Bm1M8;wvkogSxn{_q}_$Xy-hZDZa-{ zCWy)>@*k<#>YTg#xrJg)+kt=fva;V+F{#K~{oJc(Ez9(%x_WlQ+M-hxvpZKkFnV*; zJNWi8;g_QK9(gHr*Icaq&tUa#zfC>oU)icCixZy8hSQ&H3FBF_ta(N1w{xq#l?{dO ze?NLDt)ElzN&W1qkgD`~U&FTdU*5RCaK+74n>_YSz13MK*2SH1R$}7s9TUah=-)i| zpTXNsCt+Xq`a^}!l+W+lciO&wHfuuW_H8LvUw2<#_fKMVujBWlQR}xFhONBvXf0?i z`J=_^y&J=s3d43+|43T5eEbMmf$Or8UZb1NwKTUo?rGEqD5q#o|XF3qJb)_3_Sqd`%|)XwAHP`of+~ z*Ur1PUHIAb(q;PeFz0I#fv*pCh%%m%Z?&$wR(bGP(PW*rIGMT`=Pw_<|1bAz^^1<1 z%(IOyZ}C1Ip_}A3>Bh&eX_Hut?wmN29hssKIQvNL#BEp4n#CMSIn}cN&hfiqNe&VA z`6`d&`i|;8zEC2az2YnPq)o4)uCF~69WkqSPhmr)g{rslUh!{Px4rp1+~s8ssQ+O6 zr+;zt>f?`7PWddcVE@p#(f;hC>906rk51j!o1LCFt6}O|WxJ_cH(l=z2=G)`@Z-Dn zms5o)mP<7yuKs5b{LfG=ub!gfq2Sg&|M4Qw*UpTTs^3C6G~FZV@Wc=Km-rg5b7>`w=m&ARie_?r8Z zH(OHI3!ZLZud|#!J#to6lf{nYOW*tM?9XO)V{hU9?6S0_@UC)3`L2cy6TQ7v--}PM zn!qjZu~p>qo6q+Aw@y4cqtWSR{#SP2e}*e_#k*Y3FqA)idivGRjqfdfJ`TP3XJvhw z&Z23Niqph*HSRFUI^3A4tkCCT_}g;Bn{%g+&JSfi;;?b!{lA*|Z*_eN5>8HGR+ji! z@b>Qg3;bQqKV5Zvp9HzM?ps-Qoqgrg(B*t{IqsYNyL{wd_57<+fA@W#`OUvAit+tq z^L-cBnDVN7Tz#9Gnrp|=d-+hLrNeHklg?3YUegxJ^J}GBF1vDCt}=OosHN1Sf8`(k zGc2pJjguD^yK`LSx68gyUw0o}8FMt9_3Gr0n_BH8XD@uNU|M`4rz_ik%YE^iH)fpp z{G;7bSnz!M{JOH6PXBUzi_UUo-a5iKr&OaB3Sz*k^=v{o%^n-ywL7H!|`u6 z?m3Td8Q=TQAQu;ZZpz*}`Z5XHm+O9Rt(>;w?RKBgOxce6qB$DUKOU_WJsQJyf6b${ zQu2$JXy)yP? z*Y^F+UE7^(+q52WSSPJp_{%W#fc%2*M`OKm%p_JlSiV5sPwVuag-81Brrs6Q@#W0n!sC;iU+#alsrzrV|Gvxf&Rr6p?>*c(@uA1VX8gfk-BqPTOXxc9$)?Mo83J92k-lDRBn9p^1(cg z^9(ZVU$5)yt@n$!e35?ou&N<&>-8+p2k@k5?G0S}Pl)?V+pbteU8RXzUS~u;pY<_OzqYu<-RMn- z)~fauKlYs}d_3h`z?Ac%-n)Np=m+hHY~8NMWK>uie(A50{quVF-LqwO?YMOGa#UQL zYqIQRNmWCSOXtrXyE9eu+~Rd9$$fEh8b?m_x76KVx?iVJB&%ITWUYu#v zk4Mfo@4uG1X}0~lH&2m8^-6_Xp)Prh&U*KS3@cqYjfXn?YgnY+<4Kih7$*ZCx2XVvo+f>W_oJHOlxnBIs1DAWXm&s z{9UJo{}EpQW$DxXlRxdTbJ(?W+eB^A!`w6O6!A=D)c&MipFFpI%SZNDhN|QFTc7`( zV7^d!$NX!jpH6zZ<#u(%lZ;~v(>8DD_*H**qk9zFLY^f>@r;)(4@&g3xzrl1{r-H% zPumHnU#wd>t^1j*%^tH4x4exHXc}zlD5zAr@kyzeBO8Y;9 z!I8MMPbF5z=BKL^zBJZ0>36WT9&Yt&7fBmb!{mQpyI38BM zd!qWpuj=jJPcJ?sAsq8cjx(1RwEXa6SjX+eu3ha_U*30Zaa?gU*7-})+WhOHWxszX zty^gF@o4Ooibrb$x{}r{Ty}Vw*0tX}q5JOLSpEO%2mZ!ChG8$`=huW5tj`HuRkJbd z{Jp}km)rg`lxf|Ne&@bTYoEoFiHF>l&fFGYzVgVM2|5?5)Ti1sD^I;*dPU$ie`i?i zlc5lk9F9E7`S|i< z^)|acjSoo^pD5UiKARQwFE0MIR8C#e=iamJ(}D!PeLnkjTCPp=rV~n`TFdjg{xgVg zOM3D)r=qArDpBW7sQ&Wr`>#HF{cq~=qwOY(A7{0*JQV)D!~1*a>5k(+D!(tQN`HEP z>X#S#Yu0`3{?B08Z{V;Zbz86Q1GA0u99-_KSapQ2H;mb^RCe>cG@~|)#1E-;i&FLM zU-o^wtDhQ^{>bNvc4W z$X*83RedyxOt*C%gHED95j89Z9m+q>U?ezo$}Pkz12 zCzs|H zGlXBhH}&V{=+Dz8FN({&qr7+H^zX$nkxeZJxF#JFw`o^e9VX8ov)gg`Wq*SSYU;aU z|K4$)zhha&W5r|2uYSiF+HI8yw!Q4PviO9Kw)ufWo^1aa_~YBHD>8lBImE247nBB{ zF}yI5>1?^Nzi!5_xyx3wEtfsHeSz4?d=4RV$yV7XYh68T`eQDaNaw-s9|#YF!>Ntb4ZVcFD3Vqt}H}3^VW4 z&H81(sy-rzrRd50gG-`cnj79ed`K+Q_0n=-2SuAJ#$64{Y+I5n#m-h0K$1Ej2)Q1TE`j@Zwr)$2~ma6RA zdr9}p=}QYAbUy9VD>0eme1>Inn9Xf%cIz*ZuK|xe|gi@L*(DLmq(Qx z-&M~~+?Sa3b;p*AJLmp#|Ixke&AU@qvX>w3$h{VSSibt|o~=*(KYV?A`}h)h!>nx| z+zS(#y|z7?`r|xP){zQ^XiMJwY+gT$K6^GbH{+>={~5xsKL1oJ?EdEY6Lp9u{|w2pcXZQpzU`dOaPVMyOO?<5o3%RK4%ceFuXvRyw|8aSYw>*DQlmA>m)|Uu zK5-|!$x|V&`|+%|ar2#d+z<5>9{*wW?6m&F_frzGEzd^`0I7@<9FU)tB}(Kgr&!^!97LLuPNmd6R3rFMkR77diAy*LlO@ zGVRgnD|$aqep{b;+=R`j;#EufevxGU)w%8K_gJq;Y|}OrJyNke{#e=0>YGo*GZ#;0 z{d+_{s%`%szr0VO4yBJgo-FUX&#$-h+-Zpuc?uK1RayqisXhAZJpJV#F~zmn_ky=R zT$3H-ox8@R>)zhG2fws2^4FUay`<$A?GH}_nA`Bk{TwM)ri{zLh9OQM$8Xcqc8 z8NRT;8=3UWbo%5!cb{eN?!Wkw<@&TD&*jIpSdBOsCeA%C$yIb``LeBCdyO+!oL+q? z^GHRf;PiFa3Atsa`_!cYPRIX zn-{vKcR7bnnsfVag+kpC9_>AJ%l~FTZzl zM#_ittdjLyoPW+Pt&9!!zV>>NXZ@>~_}y;Du798S!C*<_jQ8JO?B{it-K>&P^r~~7 z{=E+YZU6T6ew^{2VdMR>Ik)yyDDed!uzvdGWBBLY{~2a~tl0nL?T^i$MgL7Ri*DF_ z(>RcG-laHihx=z*x1D$WHktF}lAiMxe`9Mc*;oIa&i!oP>GVF`IvUUsH~-%w0R-QA-NzJNB>nD?e2&YkVG?AF$`r!@k7A z%$$u!%U9fTJbBG&3rCdGfj`QRlFZJ!`I_^7mVP7SI6154@z391Gxi&NmG*Y$&6|^| zyt!2pFrghh*{Akp-qp=%S zSgdwxuL->!o(EpsE@=7G+)>jy;F z&HC)~I(?bzM-!bp5`Fun%hrGD?|E*y=52j=>vEZ3d->^)Ti;ci-(2tBzs63?@WNY7 ze*0%X>xK0$l%8IjAGPJ;pM}f4*;;dsF5BHF_TwUJ#uOHPeWA)ZmtTD;Jlqyp8qBWv zRQjL3-LH3Y(-&VX+j)M)@#Pl}H?#P!ssn#=jhlCU{ytZyZJA>D#H%~+=qpI*FIzm>l-JVW`+du| zj;H6VEM9#1eADl}cGaJH@)vJEyhh5#uy3`FpW~Su{g2b!%SsHNM(W$GEnSyUwOrgF z()|Fpvs-+iyQFBuJMY@{)3OSC9)~Cw9-S;7Isfs$ev3)6Yd$5PZ9BeBXr1$%)K4#W zwe>!iW%e?R{#ktL+O%m+4A;$j92^a|FtsZtL^;xrgLsCRj!+H-Ll^Ow}iWl zA;&TE!*NaqUG}lpO=IOlF6OSwRlBn1;EFpY*O~5ebC}#X8F9jJt1{o6xt^;&#Kmu) znpv{r^W&3>iX2YXh4QP_f8G!0zf`~UU81c&%VQ3=AeIlm+y(Z({Lb<3$gx+ayt{u} zPWl!fbjRyL)V-baf=dJ1HFQZFv>hh5&zxhFQT zvUl0Me-)o6daAMeZTtK7?cqtstRq;nyk$=^?f12Qo@mqTy!a9GRow;lb1m!EA6K6- zhi`RY&?4oa`M*!p&#U~;;5y;ugrAFEe`dRU*2-_DjZ|sRi)~LQPO@L^vd1f|LC$;Q z$Jev=T)yn=RFE>mXoC6Q%F-X=DvwT2wim5(f1LP7=k1=g&!X)OVtbXM3!kPZM{D0W zeN^j2<-9+{I0(s6K`=rw5MHWfs3Z=SNnIHc1PQF_)eEW?fTRr!z&*zzb zZCiQO(F+q|jqe$*U$?bBU`4_yMr%2SwA&n4PIR0KJf_`#`Op1l|5WbEr2kl*f53Ck z=JgRjZ@o&}@z7+NIhRk*>MiH8CH%6k{@59EakG8wl9LM?Rx>64?T^#aF?eN=W+eEv zKx*1;HvXT-pExh}&3&%RV4|CKn)gM|-_Asn$Y!pvE%#<#{;hxOvBtFNW{;u||9StQ zVt40+B~j{RR3pKX46$@|Kjyqv1ihq)2vS`t=o8l z*I&pgczw(@_akiy4!8Win<(1^b^84|`m9&@)9X{_e*N69f{v|Tdh3w)ujxh_$=VyT z0<%xH+E2-y_HxV3YWD!;{k(Uc{<+cru=~hs)51%MM$?VI{G5Jr`t@@2>p}NoPhE~V z_bhU0aaekCkmt|mYm!?EkGLr{h{pL(O+BqM$!OxHfP0o^TNmU9gBFC%2|c#E0yG+& z^;cqb^yLLdW3=}gh6`@fx@y%7TFAX?Z+)NE^-G0etKW9*nycNl#XTqV|Ah~ttaX1v zuN)0$j-RJ>q9k7ZwbYU9l8F)~{~V*<1s*m37x$(va{ZNWZ8GdFv!{P{x4-ee+IpjD z)ZK?t{hyz1sgpnV!*;s&r}%31t3ZC%07-_G%C zA2B>W++}}M`SSUn_Zfc4@twF-=Gk*%Ue5BD5BtS$emQHu81pATHM1O`Xu|e&f7U_3ZI?wF-Vyg{j89mOaA5055JGZ{)_dqbnp(AI8e`% z;?yP{Hn^Kf9tt9Vmr6K$-8`VzDsKV z?}slR{^Km!|Kj>p_4wPib0xDD6g58d|FLi8;|c%x?23AJGUUJWv)Q>atEzA1O0&r| zCsmIg2@kq|b4Or~;t!!qstF-(8-vVrKfJwfQ2OKJVHv)NB9;Q5`pTnwHl2!j-+zVS z?wzt4i=~srByVig^s_PTZ)q?%F880|fNjva-IXOOpVqG1FL~*!w!5!hIe)>ox5_FV z8egUy(O}fda9l0KRBGgH_O% z?|~VojU@{nD{$HUzWs4~wcwRK8=q!;jnLn7^7-lrCiAOrzWgrhed@%@kR&l}lAG$y zrrvXThFPEIq*;_)vOlURz5bV*@+Fzz6;slSCftjgy~2I^{Ku1&e*Jdcc4@NzuCHHn zJr_-g=Iqs)J1h(XjxFaov%$zl`<;-IxlDU`koiqrlfMr#QOKM z>5-MIUPRrAkMnYjbCQT~6;Lw$?clcNh~W*P=Vs2EKi*jNJN5h9e@9zB&0fI&_}*gP zXKUBJyp^{gSG3gE&QdpDjrnzq%NdoHPZJE-y9J|m%YHj3V|a90L8qG0SC?9OkFRfR zuV37>!?Dw}ZvD0GK^ND*uQ{Cgv~nHq(_0cpy4F2Y&0O`#R%%X#zFY{G=JdkjY{pZ% zZvAIi`c%IEUgH!FA+tY~D&g}gw@*GN^wZk2Pjb&r7GuX;k?td>YqNM3<%a}bo!QRl zcKhL(J+YJZPt~QX_Ox_XZ#?ti!-r3%=l>eFnC`KB+&^=IP5i~R{~2x^f0i=0($8P# z<+bZlcT(4;?aouvY^u7?!ISc23jgLniI%$1-;rys_qsV5$_Mn9e)!K2UcdZIzI^fK z7G+7PwcqXPzR1tmb2MR^__e~!=Yg#aAzce2+#VNd7bUn?O_0{V_)`72q~r(r%YVhr z+|-x6-F38J58L%qyY7UqU-2SeWb%R9Ko+B-ldNwq^3E(zWKVE}c6#cQH>xUrX?TKcAUw zXEq$Eu(Vjc_qN>qtB=&I=CGM*Jt#aM?Rzd-zT&u{h4i`TN-WT;N$=A)g_0T@BFlIYJ5-r)t2Z~2@blm0U-E&Q8)|5M1dKd+zeWt;Zxd(*E+ zMwY4@czF45>bVQpPFGy|X06}is~R7e|GfV(FZImzYWGE#s*);B{FABvyWivIChdNU zSL~q|mwfuVboS4@cQ?~^y6dc$7Isse(6q)rt!d}l_Ov94PduL{oR$p9p0ba9hF;8X z=iupTnwc%B?JBh?e*@(HGkjnC=V{8PRdJcKwk>~h;@0o8MyDMsS1kEt81+tJmg}QK zyZO8S=0!5!Vv{s{d}SVwLaoIQ_djcT%KwyP{+Xh!maD;TdBa~{kl{bW){jN~Uu(@b z#TWn7ey&@0-gE0!^}drKGr!KBy>jP?bH|oT%8e zS6;pHYMI>n@MTB4iZ|C(`fRs}wWwcR^e-p)KZEhV;FnSFXCz*ESNg2$)G3XeEqm?# zyE?OTvl^3HB|fFs-zpL=Ps=%Y@wew>HercJJ3VHe3$~A0RvWZ_nc+*pn%SR!YZ#~W zJe_dFsYO}pmf^qY50+capOReunKZ}2#;#SG6Up=3tZvOm(FH3jHRL!Z8%;{gx;LS4vtp z&{E}Wc8SEUhPq1=owBTi&xZ4@j;r=@i}YD|xy!!)O4OFvnf>m3GE9q=>o5IWS-JbO z{JH-O3v;%-*FR`CePvcumwR!=YN4A^k?l{WP8DA*{^RDpQ|dn>r{1icxY)91^9e73 z{>%G2Ex&&G&)~LKp<%xuA8LRY#QX>oo|*zga)Q>pz3Re+GlCr#aRN zpSZQ)irD=*MO)s!p1oq?{#wnxpgTv--(x1W7e&@9#QE`4M6taFRgis@W`)~gE&~Teq+GpVXv5HaH1vM`wbfs~$}EIodBtIL0erT-a{|L7J9 zKKjy?Ce_wmyJG2uKbGAbi=JZ z=U;7=-aTI{bNjac42zSRIMyBNo~h6}E9AjK#tDr(^S2zRcsikPxemXidi%@GFaI-` zRwN21%-%U0Z@UM*E(;UhG;R5jEMLZ3Gj~qU&wRjO#OD5U-tyl5O}Ex;Qd9WwpTXzD zNzEO9_Fhx{`^Ky$aNh~uE7fTs)#-j_Mj0pHtlRd^Q2ylv@jADwO0Jq&f6m|XbKVxu zclGj#zkVivXI?*Mez0C(n)lP*IJHOL`j&L{bEUw{F&Q1$L&b>_caAiCTtXr zdvxLQdhb>NkNCr#2Oqi5ZIv(*j#2x2^z8C`D{a<35qW#$p>XFD_p|JLj^|WrxSEfu zR9hKMytbfcg4s1knQu{!3%|W9Sh)US*A~~Tx;LR$)YoY}(u_)4ol!SmCiIAud`{^9 zOP`icwbxPI@nwB!sTyDW-3u2c?zR2*=c(!6of0vH#qVpCH`Pv7>6x{*{nw2D40T^V zr?1Ssw(^>bJ;`^uC)tKPk*<~(tWsZ8_BnKbcVn&Hmxr{cH1EBdh` zL2>zU4)-OSFL`?7rd{#mm74RUo%BTCk0pXFZ_Z~dpt%F8`pqHz0>#3v4NpRfO! zv-_t~rJ>A>4Hbp*$EVDc{}%t%_e%2h#J0qCwLqKpJPH23{|w>3)x4MeoR#ZWzv6zB z=hE4SK1S8%uGT($yeCiO?aAA37B_ELfAqAezKPaE`HOGzx7-B zTWE3Wg44}%5pzpaWs1dx<2t`b{>z_k_bE0$^T~M|qrORjAK7lti+lCuSY5E^epTN; zQErQ$oVPx0y7RNlb%UF?&!0@^nRqEPvhQJ~Xz0HrX|uX3JZTkQt)lEWWZX;-AFk`T z@cL`~!RNK}{#>&uYFqSUM`yq2$NA6y*xxtaZLPi6>$c;S^-CvR`|Ky2dF#j=PhQ!T z4`1tM*r|%Tt$Vt8#>q(%&nF2o94ob`pTD2|=kgh!sxu_rR7z$4*0aBlFU?(%RaJWB z(#@mGvL)R7ZaY+!|3shu5$WD@sP9Pa zzI?IIN7ruKqtv7=UG3|2ai{;vTTI+V46QdVR5y92*WZj>x=dxJSK#!YmNxgZ%VJD7 z2;MU8{P&@_|7)WuGZy*Sd6Bg$hRhor*!%OgzMgUG++B;M8hjkb z+%F4Q?2Q+_T*jxMXft`vCkA%G=^X#c`OZ6BEK$9*Hcv`o_Qj1l-}RNXm&A1{o>ylH z)pY)Ick}G?lhulNi{G)Y-@W$*%R}C^*LIzqvpw)^W})sALATFwN3(U-Yxu>jHg|Pc zb-?T=^O6%uj=k~^A2IDL_|FhMIdKldrm|hh|C09YyZCP1y^JRtu5|V;>xvItXX!DY z)6}M1zTj-%WS*iU{Hv_L7reQs+0m!{{PZe$pNoHPuDq?c^u^gy(KRnh)pze)x-hn# zucqnC4_EE!>1UT8sVI|i_)u{C+A+}$`vcdl*;TLTpRe=X+&fOzLT>JXU{>`NKCO>OUG87x%FPN6qsor+i z@+1Rm2-AJLP_BDFr!KrY=g34Mc4z%Ze=0YM_+I7z?p5BMwm)Q+yOFnUpqzCbTU0~V z^QmUbZkHYIIemrUM&)0-XE(!5H@WCZ)+<4 zH7S|BtnZx`*y6ro+4OxepO#OJ+O=$T_R`xDKTZm5nmuh=tHi3c5v!R4w}$s6C0)xZ zjdxKsu76hW_qNHL3vG|r*DtAEkzH?Bsdewyty8Cc_wS92Zz-P?Z4|wKg+rXL=94Rn z1O78iIjlcD<+Uoark~*YhmXF#J-4HbS2}(WU)5rI9M- zpKGsVOS>$x4&cl<(i&nh(W{H;aB<+iq~~wu08(Zi)YX$gKgy;%3l^ubO}}v5p`7h z9QLkvhE%MFq{m~^!(aI}$*uTPQD%RM?=jE2gG>!CKHUvFcgnWt)4At9-qjo-Hs*m_ z9g7t@A1632R<3>2d*AAhq)LHX;M^0R`ww>+{b#T|Jmuv11BrnPHO}w(+9}K782dBn zVy8&pjZpUwr#HS%IaQTY^i1gXdtJx;r0e_{)0vD9O`Mu3acNJ*Bu*9P5unbf0dH8XjGS&%Dk0({j=^@$8>A9i(Z*{=2z&6wueu;IPQscY}wG4(>zt{ z%HKKnQm&^o7=BbPTwH#1QOfp6rSV}O+f%2t)_>UMKY5n^OXpxu-7hufdz|*qYW>y+zA4MN z+49KaMcME2v?%pIkHw}hbIdG%zBZ`-OXuV52AQX9O)7oG=d9CWv<~kp{gGqSHX)(rh{JmU{>T4lsSsgFr*2{0QonzSVX#OWAX#d{+`*p6F9&0Xm)iE4ti2mklQ$6Qq z(zn(6f!{46YkM!sFY&0K6SQ-`qTa0Yucw_^E4ehp_*1~41+)718!Nv}aoLd~o9Caj zVg4f5|Cc|@T$i6^wS9TUt}}%Zwh^_FEgo9tCZRljg%kVJ5_eXlcmIl8{Qbke)zf`% z?>r%= z&on)mpPPk$Mz{$73)U3+{nuXOdGbF#7eops4L*JJBx|MFZ z>8Gk#s#3OJXFKfCm%`>LWXkp^Q?xuaszqkzs<;3A{9^lO2e0b0^$VV~`1qv$%YRNB z`7-@umAiiRO53f?o=c1`J^1i0#^90M%6gCMAO17UJ!`w~bI+{hQ)# z@6IY#JeX$SwP#YG6T_*pvw3!>`*hQ4T>4p#U)E*|w0SJ?pFvz;^1h?DB0pyqraqY7 z;qm4A^7$-3b}v5ss{eDI#(m|V?(SA|&#g^mF^^huPD)esr#Htur~O6v_1*|dC)q=|+N@|*?z&r9uM=C)1VwB<&zw?)Tevx?p8=Rclpx&4!lRNH#H^=n_1 zdm7s0D20mM4{MG1_l~vB&njP0X5Q9wRkf>iD%xxUdh6vsemwp2@_PTDa~3^w_HjA$ zqvzz)KR5Va{G0Z+X8F_E{01l2L_|7@?bNw=y0Bog$0eJ|nyOAsi>x+?*p$m`J65}R z<;mp|%asZnvP?7zzW$qbul6+Gxx@WBn_WVle)Zme|HAUJ>*kw1g*~&v9{lnzEPc6j z!=p*&`h981ALY9{|IX*R?kB)-@pe`3%rEcy%eCJZcXZtOXXkO(>5{Fmi*J1VuC800 z7uQKWd>8hTX`Wwm-=A5*aU%a2lBYbJd4BfcBb>@v4*5-p%5C~R zt8Y=IC7@Js{Ih$kn zFRJJx!%Vr3zpd#{u_FMDZLE*`c^ zIr_x)O*`$we;rrKTGiBO#mZjw?7E*~m(i3}!5a_D>-T@G+;wN-#8YNB?w(#h?LR~R zMt{dkTe+pRPb}X)E!};dhe~JDo{2lSKYmSW&Qds;wbkOe#zp1?{{8Rvo2{uZIxzSB z)uivK#V6Tked$&EnRE5&_Wss4kEd+96QkTxDVxgvXwe`0tj5jW%(`lk$GhiWzRPj# zkm-+`=lU3@*)8&T_bdC!l=G>pGB|!EOnOjR`EJSdSN$5H5nb~;nvdbAQe3?9A!?`e(i9)2Y+8J@Z(**LK3*BSA(@jNC#Ee9yX$?M}1j zTXHDq=tlFqLiU$y-)yQ?+xf+(-s6@+Uv#$RH0hr!lfpP2mu*i`GZ8Z8`+fay%&`wC zIbKeWY@;W?`lozoqgwm!w~jCG<^9!MQ`dD_*W&J}ewEI0%?ZZ^wdSV?`kwcn7e9OR zADuXrryKrdthTvP(e%Uf{`|K-f~LJrj{`2R`x>eEtD!Gr?IR|QS(2=A3oYi$Ezdco zE@pA8u)!uw=Uv6F;s6Hom|uH7T|YVPU&?2<1S{4 zI=ku>FW2FMcb9EgyjJm=dsTerlYIW-2YH=Z8fzPkI*b#cdK=a(Hn zJT2X1*Y~1d^=E(0+#>c(EL(2A%H>xA(MRHxUp7aqx#D(2o2%IAVcl7;FXzgF=lo6J z5UT!lzW&RyxyuEaCv@8WtH1gp_~O%S)y+B=+;v-yMa;Q(>Vg|P!%3~)#vv`=$GgHOB`Imil`+PGWr%#j1cw8J$ zPQHBlqP+jt9o@%G@1Ng)=53Pyic0U(YnMhI_qh11cj-*02Cef7H!kGIyf@i*vMi7B z_{uXz!uyw8_{l#1hRFr@3UOxx0cYu!#rF6{Ce0@`~Bkm%=BBkdFBaxVv1jU>CBhkvP$1_ zo$j9r@0p&kboSCU44jh5VJb7V0$2Loer`Km&x2!5;O$pm<)VKU^Sk*xbzuDLx98x` z(q)#C&{x0Gr_xthDXx(w{k#vHm_w&&Ba@RtTQ>MgwQU;bPF zrr^uYb8!k~h7&vgGgN=}-+Ft!;;Z}9?d8f6MkG+)olhUr( ztezjg%`gv#8^Q4|{`Tb~e=Dmn(rMlLE zUB3=_U%R@to%^iQw(nx!g|t4Ev@%aPaf;t+y;iu<=hq(|ofPK0&iGG0V8Z9QU!PvR z;jhBMaJsGE_urMg?w`SO6K2Ki+7q0m_vtk2xrGIfm?fuwZ@nqpzhaYd(DIpQY{T>C z97~oIxFK=KZuQHc~=c6YIFyq37L&o=3fwOeH9kC}_ODyAlW zyZ-Xr>dl`Y95fbkd5~0N9KJW6W!H^=LNBe|`Ig&Re27UsqTh0Tad)NruZ#CvK4qV= z%lfQ7b&C*p{ZCor=jk?q~wf?wUP#$T~pk|nxg)mpQQ%O=0v zRULm)ib+pUz**XG<=-cB68qn;<9M}H;>z=bwdRlPpB=xhCaK&bkagneru0RXf%h`g zu08j7w``JXleFcmH;2!9f1Wut)ZM_{ziDRY%IggbM>rXzjb&uw0{^Z5m6B{cL9KAz z+y4yGKb5}n>bqXnJ^Jb8b@8Y&u|z2M4xM9LPZc~rJ1NE{$x!&bUOpMmv=CQq+zG`Eolqot+k` zC^$>WdD$I#WqEI(1f>)OzdzrN?(eUE6FUFA)UJq_Nat+UyN|S7S-#C#yu;&hl%dCo zf=i++f=?$E8N4~;t}t<8Pvu12$Laf`L-J?KOrDeclI8mGkMCZ6=KjxMd`I=mb>T{* zTBqpDkb8RT%XKdG9(;6Sj#Kk}YaJ_&0tQnhhJOE60p)))_N3Kax+;`rGRgGM%lv;+ z3Rz>#&y>$Aysl?+@VRc1wDwC?A;+B1A5O{)ZWETh=;~rxcjL9m#7jvMTP_%jzM6J# z-Dl;mc{gv&n)!5R`jmwH%RQ5i%73|k^v_G#lU4cCZFVop3Oil9{Qi(?m$jySeEy~6KZDPi4mZ0v&(MEcpWKfA?alFQazM6< zyzELgH8=nMiPrLkaXY7X`>&p(YQ$o(f9}^x!;c$}=dCKY%MCN|T$(X)?-9Mml$~XX z2epG%Z4q5w^YtH}7rx>U}e1(xQcyu8ys(K4Xw+{<3;SRm zFQ+C!1NA@JRXlIt!+KbBCJ6v1zS$0q0jT=!f4DM_a%Q!JFRqK$^zJ;r6 zLRP$=baK^UU7K~m)0}0ue>rmF(bK0nsyvGd4HpX5#Gf-<|7CY^%BEY6i;uETdV0my z()G-Bt2yDJ=7wIW#_l3Ii+eI9n6{d}GLF`q)AIbm9Tz9lFLQUOYWA-Rn)LFKevfyT z`pf%2{2wj;D|&5L+w4_a#JA~JT5JpHHJRe?c7KZVBtxNc=0{#;kJkm;L>k7V9@77_ z{HpHHzxJAz3FS2x#b(9uu05+$t z$J=(KxW|X)S?~JKARNh(W3_zK&+b##ta{4D^)A2O{_Ub;>GH_4Tt}W=D=wB^U^BBq zfHkD+nTW})l}U!ZJcZK*<~*v{8~DKfg(>G)vWX8-{C7+{45M7oqs%i`JcgCe&eyLX@?gb z;miD0*1!Irl2%;$9E?<(bqi=WIBP3cwPIHjC5uXp>e zo$WV&7(9JzQ?b=ZUCwb!#lE@w=e*qQ7HR0^rrs4J6Y+7jb$_^jsm=FKY?nW?pQ}s! zEL6Ga+MAnM+gu;*+THrN;jDDPBB6zj8fU+!$G=V4ZSK14_|HoBewp@V>RmC`cmFfY zJ@h$t_N}NN=Yp>u>5y8xqoS(d!(X5HlkuPX{xi&+Hm`j1RlTKKF1;;T{bZ-7Dfiai zC2gA78-A>abg#Lc{de=5mzjJ9s>T)t^Z9H)uHSggd1G<%)rvdiea4Ua`NbknDg0+} zKfU*h-R_^IPb2pnUHPi2d`8qi>E9KhYqtE(U*j`fpwDi>oE@DJK~roupE3Ena+*XU z=b;^*HbFMZZSe;W#<<^;yYIdFssPW&4<$S2N&Kv;+rN>2@qO17M^|K8HQkMJTwJ)O zLoE8{!x;h#yZ&(Qzp1hH_S+Owi$BIP6CO_Q{Ltc4ceAF>@4QMnC$p5%{Q70m^&(ZL z9|a2E$ov)CwtxN4c;BYnWcSO#LB08vzP5+lDz>jUx^oiSflntMot&)m@$p&ZgO(rU zWEb<7f7nr}uEF81`0taO+UFYlil6L zPwx4A`+M=aP2aUDKOOhkwoUwA$!8TSw%$V7-mlkYOsRF!^}A#+iDUl6kgx?$G%8bV zXHP4d&NiL%v_UGzng0ysIziTj?kiIlT=9uK%BLr%@ne#W#2!sK{Xm<0+&{bjGg#U# zjE;-j{`B39#X-ALeqGyGpmk}+aZ#J9fU@&$Z}Jn1&k6o{@|XGLak*(Px5iyaxODh% z&z?&6m&`c^{~4_3%wt?#m-q8OL)gCT-)ECDRaGw9-%Y-u@0GqZ;ajz1n~dNw?YEVg zzk_eFg-dquKRc$}{_Rg>{nPu;eE%(9^{@N0=z}iH6$!g;8Ay~qJ)QSea`D@FhmLoP zcQ)DVJU;u{Z~M1)v3~X3LCHI8jMhopCe^R~C3iS?h1u$Q<~!owzM1 zTWab;2H}rEI}gcPwlFBT$Um3*ec#1_lNZFy>$Yu^AW`1pZh!dHOQH1uGC>@L*tIU}Ru|(I7b%Ua%Ys z0|P?^h|l~P%;x};3=9k)F%~W`j}gLC7Xb6P;Px_s)G&Vqi+V8Vr=>A4GUTMCF|dI} z7@;ByXU>9)7=hgp#lQd;F$Ih0B1FJu{s5a$z`*byD`0*BlE*6bpAtEc-7Jt00Qr@X zfq}^Zf*~Qm!Vj{S$Af`^$HONxFP}+(fgv}qq$tSUNg*OKN`d_x0}}%$0~>=O14CkR zae;5JTL?&pr>nCgJCu0cZbvaUyff&xOED3)MyK~V_<17iRK1A}o&YH>0H z17iyV14B-ENdZXw11LQtWrNsEpg0yOiinJ2U|^B}iKj!@Iv{ougzW%gr{w0PFfcHI z++2{7n*w4VVPIhBC@W1(VPIhPVPIfrE6YqRXJBBy!oa|wl2e+S$-ux2iY<}c)Wl*2 z1{NNWcu8t<1_J|&0RsaAPfwR3(!Wl?5&Mu~z( zvZjKerKN>}M{0RaYDtN1Kw@%sVo{2MbAE0?VqPT!1H{iDT?|5?uvPGMbv84!G&9pR z(lZ1LLkPT*5G4f3h{z~t{Co}s#~Gv88H5-@J3=gf5d(w8R|W>=2?(*InG6iuTNxN6 zZXv`}7BDdIw=ghlJCEcaF;IHRC@Cqh($_C9FW1XVP1XYiDBL1~3g9YnGmz}l1K9@; zI|Y~2w8YY!5(QAIPR`HCFD+6iE=WvHRnSFG#AItkau$+1bb?aTQj1dal2aAJGE>Vl z^U@WZ^YcRMHraho?&1S=4N1y znFlJT;PK|e8O8w0dExTUA?Y4u0yt%W83=-@pMimasW>wooPL~xLKKoqi^?GKplr#& z%D~0I&mh7e$sos|%%H)b%V5M{&S1^pz~IW@#o*5n!Vt+2$B@jB!H~;P#8A#q!_dgk z#?Z|$fnh4cEQa|EOBhx%tYg^3u$^HK!$F2)45t|`FkEH0&G3NXDZ^`q4-DTJels#M zvNQ5B3NuPF$}_4mYBL%!S}@u%x-$AO1~Eo5CNQQm<}sEs)-X0Rb~8?5oW;11aV6tM z#+{4@8Ba1^WW34vknttsC&ph)%uGB?B22POYE1e}7EF#z-b^7(u}tYqg-lgUElhn( zGnf`Jtzp{6bdc#Z(^aMiOs|=~GBYr9Gm9}RGV3y1Fgr8*Gee#WgE*8mdh*;Sw67* zW94O)Vbx}}V)bN=U`=N&XKiDh#=4AkE9+6#tE^91zp=5giLt4(nX`GYMY3hFRkQW5 z&1GB9c7W|7+hew`?Ck84?Aq+M?EdVD>?Q1N>@(Tdu%mq`#3IfJm>h$DZr`9X~pT!nZjAg+0VIza~J1%&ZnHexdge?xoo*YxU#q! zxn^*!<2uT9hwC#pH@6bEC3hfqCU*n(4DJowC%7MS|Kt(k(c*FDiQy^b>El_>bAab2 z&u3mClz1xZ)Q zY{`j|+a>Qxu}Eo21xl4m&67GR^+sAm+FCkUx=VVK^eq`C87-M0nQEEEGG}DI%F4;Q z%NEGalszo_Movu5K`u*firhZAm-52$cJi6>Q{?x{zfurYa8$@qn4xe);e(=#qK9Is z;zGr9ioccAl|q%8l-4WVRpwH*P)<{xqI^jCgNnS0uS$)|YL#26oT?V88LHD&kE?!H zQ&$UDYggN@_Cj4k-BZ0veYN@>4PFg_z{eK3g z1~~>x3~n0=8G0Eu8SXOtWTa)3Y&6^GiZQRTn{mDI4&#p|+9s(c^Gt4-3Y+?xwwoR@ z{cC1!R%Eu$?4`Mid4l;I^XnEO76BGL7AGuOEuAduE%#Xdv@)|QvD#$y-dfi>+j^Dt z3mbKtRGTF>k8PD~6KxmTKCn};OR!sD_rPA!KGA-W{UZluhZKip4$mDm9kU$QIKFc- za4K@z>h#^&%DLA0fD5yWyGxhLIaeXqP}ftkP=St5HUglo4UPrunyo0@Gc|Y>e@+tD!<;&#jdX5@}2_NcI^Wl>+FU8AQ)KaDYsX^XiQs~%esdooTcE+=kpJb!#* z{N@DKgz$t_34ap(6Bi|ZP4Y~dlk_3kIeB{W>lBBSDJd^gZBr+uK2Nhvo0Rq<-8Ox4 z`pXRajAyMQV$tEoNI>w)okSuqDTrS}a|;Oln#8vcJpomOoe#wBpE0^OY-C$*k&M&9u67 z^~*IeYc8yHS-WGM?z)BR#nyLkVAxQ);nl{3jn_7LZ#uNuV)ME!s$1r472evljd5G$ zwh!Agwm;Yrx#Qwaubqc>S?}7qTW|OBJ&Jo~?-kwKzmIEQ%fA2ntM-3AP;lVQ!SsWV z55*t4eK_Lql_P;i&K>nWdg7SdvBSq5kMBQWdt%Q?tCKrVS)AH_+U)eUGp1*@o;5wY z^_%jVb?{Qi~BCwUpjc%xv^^}BlUTIjVK*JG|fxRG+>#m$_X zA8(c2`hC0M4(pw+y8?Ho-IKYu=)UIt^$*M*?0x9+@XVv&N4Fm*KYsnB_{pEAEzfwL zO?xi?eB}$H7kgg1y}a-$`qk6d1+RaiI1B zdHENUFNeMce7*NA_uKF9T|Xp$toUj1^Z2juU(bJ+|6%_#7d!@$6@fq{Wpoa>QWXL+@=NlIGx7^oD46OQ{eQ>62Nq{Y zX#m;r|29Jl0}lrW2PX#)Cnt{}Hy5{{C_fJmzo>+;u&A)Ggdh(XKq)XAgJ9(4=H}(& z72x9&5aHwF69Ex?A`mTt5Q+y%Vdw=5{6D}T$iX1OAi~V3#K0uT$SlbC|1JXy1JnN_ zjP?u+jI4}c0BJZeFf%YRv9PkSb8vETGoni}GB7d2Bn224Ss0m_SeRJZ**I94d5jqu zm;{+w6om{~9Rm}El?oe;*hD5S+~}mNA{uls$=IZ*>7p~c>ZITg4?iXsn~E*k)U4(* zIV8pP(Bcv^@k^nPQa^2OIefYF@n<*nDN9HZQ8PJ$F4p5 zX6_!IUfw=^`S#=2pMMu*U}9oqVqpQhiJgtr6zl{=Lm?K&z{El&VOFEYi6S5u91Obn z!B{2fVNug0=U~y~Vv~=mY#;})tC=3U$dl_Mw@-n@&;;F^`WP4ysNz^ zz5V6C{a+>pHA|cIdsWgjoZ?!O5K2LlHO16YtjFG@2i z>fC>85EnFeC_%Fn2d&kf`WpEjEIVihVE*w>TCc1$7W0bDQj3T zVMa$sXLa>+uj=Pf6*D?IAUZoHG&ogPKR@bUCeii(aI6Dp#-yqvtMtBaGXlM|XdCd`=8 zF`;2WblD`Y{QQiJjG)AtjtLVw8YXni=;)~Is+iEwP|z`l+Fda)BeIw5V0}l@eiv$M?2M-5V#jQ@qw*HrMFmP~i@bIwk2+%O_ z*9;2UdhEZ3hKGfPg@uQPf`x&HTa;zg*8l&tG$I^4JUl!yA|gBje4?U`SwT)@Q83xjEXw8_P>^ghlPWKfq_SWg@uK;rDBlf+W&eE8Xf@w77h*x9u@{Z*-=qJ z*~ioZ3@id70z4c7JUlGiqZFgoMy*wJ2{175C~LW3-`k5wyfwRebcF!1p3h_Eow@UjfDWXL}D z-_0Y#!@wZJ!NJnqDO^!8J1Qz_t)T_TeGvf>nVOo4L6$*5PKr_bPIdti5grZ}4w{OZ zmO+Y&Q4CQUQC=1nAZHs%NGMuHMFlxUIqCZcL?lFb1ULj5JK0#eINI6SS?jt7L<9s_ ncz8s3csO`EM0f;P1SB|kcsLk9#4J1_GCTqtA`&b-91Ju7NqZD1 literal 0 HcmV?d00001