From 3c9a3b05275f8d125b40a9bea78adf7667bf91dc Mon Sep 17 00:00:00 2001 From: Hendrik Beskow Date: Tue, 14 Oct 2014 14:33:10 +0200 Subject: [PATCH 001/122] Reduced object allocation per request Ruby Object allocation is rather slow, have searched for the "fast path" and for Objects which are used in nearly every call and constantized them. --- lib/webmachine.rb | 3 +- lib/webmachine/adapters/lazy_request_body.rb | 3 +- lib/webmachine/adapters/rack.rb | 27 ++++--- lib/webmachine/chunked_body.rb | 7 +- lib/webmachine/constants.rb | 78 ++++++++++++++++++++ lib/webmachine/decision/conneg.rb | 22 +++--- lib/webmachine/decision/flow.rb | 41 +++++----- lib/webmachine/decision/fsm.rb | 6 +- lib/webmachine/decision/helpers.rb | 12 +-- lib/webmachine/dispatcher.rb | 6 +- lib/webmachine/dispatcher/route.rb | 18 ++--- lib/webmachine/errors.rb | 6 +- lib/webmachine/header_negotiation.rb | 13 ++-- lib/webmachine/headers.rb | 10 ++- lib/webmachine/media_type.rb | 19 +++-- lib/webmachine/request.rb | 33 +++------ lib/webmachine/resource/callbacks.rb | 12 ++- lib/webmachine/version.rb | 6 +- webmachine.gemspec | 4 +- 19 files changed, 216 insertions(+), 110 deletions(-) create mode 100644 lib/webmachine/constants.rb diff --git a/lib/webmachine.rb b/lib/webmachine.rb index 3af9a461..0860ac32 100644 --- a/lib/webmachine.rb +++ b/lib/webmachine.rb @@ -1,4 +1,5 @@ -require 'webmachine/configuration' +require 'webmachine/configuration' +require 'webmachine/constants' require 'webmachine/cookie' require 'webmachine/headers' require 'webmachine/request' diff --git a/lib/webmachine/adapters/lazy_request_body.rb b/lib/webmachine/adapters/lazy_request_body.rb index 08e6dbed..694f56c5 100644 --- a/lib/webmachine/adapters/lazy_request_body.rb +++ b/lib/webmachine/adapters/lazy_request_body.rb @@ -1,5 +1,4 @@ - -module Webmachine +module Webmachine module Adapters # Wraps a request body so that it can be passed to # {Request} while still lazily evaluating the body. diff --git a/lib/webmachine/adapters/rack.rb b/lib/webmachine/adapters/rack.rb index d1d34fee..3e8f389d 100644 --- a/lib/webmachine/adapters/rack.rb +++ b/lib/webmachine/adapters/rack.rb @@ -1,9 +1,10 @@ +require 'webmachine/adapter' require 'rack' -require 'webmachine/version' +require 'webmachine/constants' require 'webmachine/headers' require 'webmachine/request' require 'webmachine/response' -require 'webmachine/dispatcher' +require 'webmachine/version' require 'webmachine/chunked_body' module Webmachine @@ -33,9 +34,15 @@ module Adapters # MyApplication.run # class Rack < Adapter + include Constants # Used to override default Rack server options (useful in testing) DEFAULT_OPTIONS = {} + REQUEST_URI = 'REQUEST_URI'.freeze + SERVER = 'Server'.freeze + VERSION_STRING = "#{Webmachine::SERVER_STRING} Rack/#{::Rack.version}".freeze + NEWLINE = "\n".freeze + # Start the Rack adapter def run options = DEFAULT_OPTIONS.merge({ @@ -55,17 +62,17 @@ def call(env) rack_req = ::Rack::Request.new env request = Webmachine::Request.new(rack_req.request_method, - env['REQUEST_URI'], + env[REQUEST_URI], headers, RequestBody.new(rack_req)) response = Webmachine::Response.new application.dispatcher.dispatch(request, response) - response.headers['Server'] = [Webmachine::SERVER_STRING, "Rack/#{::Rack.version}"].join(" ") + response.headers[SERVER] = VERSION_STRING rack_status = response.code - rack_headers = response.headers.flattened("\n") + rack_headers = response.headers.flattened(NEWLINE) rack_body = case response.body when String # Strings are enumerable in ruby 1.8 [response.body] @@ -76,7 +83,7 @@ def call(env) Webmachine::ChunkedBody.new(Array(response.body.call)) elsif response.body.respond_to?(:each) # This might be an IOEncoder with a Content-Length, which shouldn't be chunked. - if response.headers["Transfer-Encoding"] == "chunked" + if response.headers[TRANSFER_ENCODING] == "chunked" Webmachine::ChunkedBody.new(response.body) else response.body @@ -91,6 +98,8 @@ def call(env) end class RackResponse + ONE_FIVE = '1.5'.freeze + def initialize(body, status, headers) @body = body @status = status @@ -98,8 +107,8 @@ def initialize(body, status, headers) end def finish - @headers['Content-Type'] ||= 'text/html' if rack_release_enforcing_content_type - @headers.delete('Content-Type') if response_without_body + @headers[CONTENT_TYPE] ||= TEXT_HTML if rack_release_enforcing_content_type + @headers.delete(CONTENT_TYPE) if response_without_body [@status, @headers, @body] end @@ -110,7 +119,7 @@ def response_without_body end def rack_release_enforcing_content_type - ::Rack.release < '1.5' + ::Rack.release < ONE_FIVE end end diff --git a/lib/webmachine/chunked_body.rb b/lib/webmachine/chunked_body.rb index a1819ea9..65c4655c 100644 --- a/lib/webmachine/chunked_body.rb +++ b/lib/webmachine/chunked_body.rb @@ -1,3 +1,5 @@ +require 'webmachine/constants' + module Webmachine # {ChunkedBody} is used to wrap an {Enumerable} object (like an enumerable # {Response#body}) so it yields proper chunks for chunked transfer encoding. @@ -13,11 +15,10 @@ module Webmachine # # This is needed for Ruby webservers which don't do the chunking themselves. class ChunkedBody - # Delimiter for chunked encoding - CRLF = "\r\n" + include Constants # Final chunk in any chunked-encoding response - FINAL_CHUNK = "0#{CRLF}#{CRLF}" + FINAL_CHUNK = "0#{CRLF}#{CRLF}".freeze # Creates a new {ChunkedBody} from the given {Enumerable}. # @param [Enumerable] body the enumerable response body diff --git a/lib/webmachine/constants.rb b/lib/webmachine/constants.rb new file mode 100644 index 00000000..3d3cbc15 --- /dev/null +++ b/lib/webmachine/constants.rb @@ -0,0 +1,78 @@ +module Webmachine + module Constants + # Default HTTP linebreak + CRLF = "\r\n".freeze + + # HTTP Content-Type + CONTENT_TYPE = 'Content-Type'.freeze + + # Default Content-Type + TEXT_HTML = 'text/html'.freeze + + # HTTP Date + DATE = 'Date'.freeze + + # HTTP Transfer-Encoding + TRANSFER_ENCODING = 'Transfer-Encoding'.freeze + + # HTTP Content-Length + CONTENT_LENGTH = 'Content-Length'.freeze + + # A underscore + UNDERSCORE = '_'.freeze + + # A dash + DASH = '-'.freeze + + # A Slash + SLASH = '/'.freeze + + MATCHES_ALL = '*/*' + + # When used in a path specification, will match all remaining + # segments + MATCH_ALL = :* + + GET_METHOD = "GET".freeze + HEAD_METHOD = "HEAD".freeze + POST_METHOD = "POST".freeze + PUT_METHOD = "PUT".freeze + DELETE_METHOD = "DELETE".freeze + OPTIONS_METHOD = "OPTIONS".freeze + TRACE_METHOD = "TRACE".freeze + CONNECT_METHOD = "CONNECT".freeze + + STANDARD_HTTP_METHODS = [ + GET_METHOD, HEAD_METHOD, POST_METHOD, + PUT_METHOD, DELETE_METHOD, TRACE_METHOD, + CONNECT_METHOD, OPTIONS_METHOD + ].map!(&:freeze) + + # A colon + COLON = ':'.freeze + + # http string + HTTP = 'http'.freeze + + # Host string + HOST = 'Host'.freeze + + # HTTP Content-Encoding + CONTENT_ENCODING = 'Content-Encoding'.freeze + + # Charset string + CHARSET = 'Charset'.freeze + + # Semicolon split match + SPLIT_SEMI = /\s*,\s*/.freeze + + # Star Character + STAR = '*'.freeze + + # HTTP Location + LOCATION = 'Location'.freeze + + # identity Encoding + IDENTITY = 'identity'.freeze + end +end diff --git a/lib/webmachine/decision/conneg.rb b/lib/webmachine/decision/conneg.rb index e89d2d9e..f25447de 100644 --- a/lib/webmachine/decision/conneg.rb +++ b/lib/webmachine/decision/conneg.rb @@ -1,3 +1,4 @@ +require 'webmachine/constants' require 'webmachine/translation' require 'webmachine/media_type' @@ -7,13 +8,14 @@ module Decision # specifically, choosing media types, encodings, character sets # and languages. module Conneg + include Constants HAS_ENCODING = defined?(::Encoding) # Ruby 1.9 compat # Given the 'Accept' header and provided types, chooses an # appropriate media type. # @api private def choose_media_type(provided, header) - types = Array(header).map{|h| h.split(/\s*,\s*/) }.flatten + types = Array(header).map{|h| h.split(SPLIT_SEMI) }.flatten requested = MediaTypeList.build(types) provided = provided.map do |p| # normalize_provided MediaType.parse(p) @@ -31,9 +33,9 @@ def choose_media_type(provided, header) # @api private def choose_encoding(provided, header) encodings = provided.keys - if encoding = do_choose(encodings, header, "identity") - response.headers['Content-Encoding'] = encoding unless encoding == 'identity' - metadata['Content-Encoding'] = encoding + if encoding = do_choose(encodings, header, IDENTITY) + response.headers[CONTENT_ENCODING] = encoding unless encoding == IDENTITY + metadata[CONTENT_ENCODING] = encoding end end @@ -44,7 +46,7 @@ def choose_charset(provided, header) if provided && !provided.empty? charsets = provided.map {|c| c.first } if charset = do_choose(charsets, header, HAS_ENCODING ? Encoding.default_external.name : kcode_charset) - metadata['Charset'] = charset + metadata[CHARSET] = charset end else true @@ -56,8 +58,8 @@ def choose_charset(provided, header) # @api private def choose_language(provided, header) if provided && !provided.empty? - requested = PriorityList.build(header.split(/\s*,\s*/)) - star_priority = requested.priority_of("*") + requested = PriorityList.build(header.split(SPLIT_SEMI)) + star_priority = requested.priority_of(STAR) any_ok = star_priority && star_priority > 0.0 accepted = requested.find do |priority, range| if priority == 0.0 @@ -98,9 +100,9 @@ def language_match(range, tag) # @api private def do_choose(choices, header, default) choices = choices.dup.map {|s| s.downcase } - accepted = PriorityList.build(header.split(/\s*,\s*/)) + accepted = PriorityList.build(header.split(SPLIT_SEMI)) default_priority = accepted.priority_of(default) - star_priority = accepted.priority_of("*") + star_priority = accepted.priority_of(STAR) default_ok = (default_priority.nil? && star_priority != 0.0) || default_priority any_ok = star_priority && star_priority > 0.0 chosen = accepted.find do |priority, acceptable| @@ -118,7 +120,7 @@ def do_choose(choices, header, default) private # Matches acceptable items that include 'q' values - CONNEG_REGEX = /^\s*(\S+);\s*q=(\S*)\s*$/ + CONNEG_REGEX = /^\s*(\S+);\s*q=(\S*)\s*$/.freeze # Matches the requested media type (with potential modifiers) # against the provided types (with potential modifiers). diff --git a/lib/webmachine/decision/flow.rb b/lib/webmachine/decision/flow.rb index a3f2c16f..48d7608b 100644 --- a/lib/webmachine/decision/flow.rb +++ b/lib/webmachine/decision/flow.rb @@ -1,6 +1,7 @@ -require 'time' +require 'time' require 'digest/md5' require 'base64' +require 'webmachine/constants' require 'webmachine/decision/conneg' require 'webmachine/decision/falsey' require 'webmachine/translation' @@ -18,6 +19,7 @@ module Decision # @see https://raw.github.com/wiki/basho/webmachine/images/http-headers-status-v3.png module Flow include Base64 + include Constants # Version of the flow diagram VERSION = 3 @@ -119,9 +121,10 @@ def b7 decision_test(resource.forbidden?, 403, :b6) end + CONTENT = /content-/.freeze # Okay Content-* Headers? def b6 - decision_test(resource.valid_content_headers?(request.headers.grep(/content-/)), :b5, 501) + decision_test(resource.valid_content_headers?(request.headers.grep(CONTENT)), :b5, 501) end # Known Content-Type? @@ -147,7 +150,7 @@ def b3 # Accept exists? def c3 if !request.accept - metadata['Content-Type'] = MediaType.parse(resource.content_types_provided.first.first) + metadata[CONTENT_TYPE] = MediaType.parse(resource.content_types_provided.first.first) :d4 else :c4 @@ -161,7 +164,7 @@ def c4 if !chosen_type 406 else - metadata['Content-Type'] = chosen_type + metadata[CONTENT_TYPE] = chosen_type :d4 end end @@ -169,7 +172,7 @@ def c4 # Accept-Language exists? def d4 if !request.accept_language - if language = choose_language(resource.languages_provided, "*") + if language = choose_language(resource.languages_provided, STAR) resource.language_chosen(language) :e5 else @@ -193,7 +196,7 @@ def d5 # Accept-Charset exists? def e5 if !request.accept_charset - choose_charset(resource.charsets_provided, "*") ? :f6 : 406 + choose_charset(resource.charsets_provided, STAR) ? :f6 : 406 else :e6 end @@ -207,11 +210,11 @@ def e6 # Accept-Encoding exists? # (also, set content-type header here, now that charset is chosen) def f6 - chosen_type = metadata['Content-Type'] - if chosen_charset = metadata['Charset'] + chosen_type = metadata[CONTENT_TYPE] + if chosen_charset = metadata[CHARSET] chosen_type.params['charset'] = chosen_charset end - response.headers['Content-Type'] = chosen_type.to_s + response.headers[CONTENT_TYPE] = chosen_type.to_s if !request.accept_encoding choose_encoding(resource.encodings_provided, "identity;q=1.0,*;q=0.5") ? :g7 : 406 else @@ -243,13 +246,13 @@ def g9 # ETag in If-Match def g11 - request_etags = request.if_match.split(/\s*,\s*/).map {|etag| ETag.new(etag) } + request_etags = request.if_match.split(SPLIT_SEMI).map {|etag| ETag.new(etag) } request_etags.include?(ETag.new(resource.generate_etag)) ? :h10 : 412 end # If-Match exists? def h7 - (request.if_match && unquote(request.if_match) == '*') ? 412 : :i7 + (request.if_match && unquote(request.if_match) == STAR) ? 412 : :i7 end # If-Unmodified-Since exists? @@ -276,7 +279,7 @@ def h12 def i4 case uri = resource.moved_permanently? when String, URI - response.headers["Location"] = uri.to_s + response.headers[LOCATION] = uri.to_s 301 when Fixnum uri @@ -309,7 +312,7 @@ def j18 def k5 case uri = resource.moved_permanently? when String, URI - response.headers["Location"] = uri.to_s + response.headers[LOCATION] = uri.to_s 301 when Fixnum uri @@ -325,7 +328,7 @@ def k7 # Etag in if-none-match? def k13 - request_etags = request.if_none_match.split(/\s*,\s*/).map {|etag| ETag.new(etag) } + request_etags = request.if_none_match.split(SPLIT_SEMI).map {|etag| ETag.new(etag) } resource_etag = resource.generate_etag if resource_etag && request_etags.include?(ETag.new(resource_etag)) :j18 @@ -338,7 +341,7 @@ def k13 def l5 case uri = resource.moved_temporarily? when String, URI - response.headers["Location"] = uri.to_s + response.headers[LOCATION] = uri.to_s 307 when Fixnum uri @@ -418,7 +421,7 @@ def n11 base_uri = resource.base_uri || request.base_uri new_uri = URI.join(base_uri.to_s, uri) request.disp_path = new_uri.path - response.headers['Location'] = new_uri.to_s + response.headers[LOCATION] = new_uri.to_s result = accept_helper return result if Fixnum === result end @@ -433,7 +436,7 @@ def n11 end end if response.is_redirect? - if response.headers['Location'] + if response.headers[LOCATION] 303 else raise InvalidResource, t('do_redirect') @@ -468,7 +471,7 @@ def o16 def o18 if request.get? || request.head? add_caching_headers - content_type = metadata['Content-Type'] + content_type = metadata[CONTENT_TYPE] handler = resource.content_types_provided.find {|ct, _| content_type.type_matches?(MediaType.parse(ct)) }.last result = resource.send(handler) if Fixnum === result @@ -505,7 +508,7 @@ def p3 # New resource? def p11 - !response.headers["Location"] ? :o20 : 201 + !response.headers[LOCATION] ? :o20 : 201 end end # module Flow diff --git a/lib/webmachine/decision/fsm.rb b/lib/webmachine/decision/fsm.rb index d641a7f2..beb7c83c 100644 --- a/lib/webmachine/decision/fsm.rb +++ b/lib/webmachine/decision/fsm.rb @@ -1,6 +1,7 @@ -require 'webmachine/decision/helpers' +require 'webmachine/decision/helpers' require 'webmachine/trace' require 'webmachine/translation' +require 'webmachine/constants' module Webmachine module Decision @@ -11,6 +12,7 @@ class FSM include Helpers include Trace::FSM include Translation + include Constants attr_reader :resource, :request, :response, :metadata @@ -62,7 +64,7 @@ def respond(code, headers={}) when 404 Webmachine.render_error(code, request, response) when 304 - response.headers.delete('Content-Type') + response.headers.delete(CONTENT_TYPE) add_caching_headers end diff --git a/lib/webmachine/decision/helpers.rb b/lib/webmachine/decision/helpers.rb index 6625473c..a60d5230 100644 --- a/lib/webmachine/decision/helpers.rb +++ b/lib/webmachine/decision/helpers.rb @@ -1,10 +1,11 @@ -require 'stringio' +require 'stringio' require 'time' require 'webmachine/streaming' require 'webmachine/media_type' require 'webmachine/quoted_string' require 'webmachine/etags' require 'webmachine/header_negotiation' +require 'webmachine/constants' module Webmachine module Decision @@ -13,6 +14,7 @@ module Helpers include QuotedString include Streaming include HeaderNegotiation + include Constants # Determines if the response has a body/entity set. def has_response_body? @@ -28,8 +30,8 @@ def encode_body_if_set # Encodes the body in the selected charset and encoding. def encode_body body = response.body - chosen_charset = metadata['Charset'] - chosen_encoding = metadata['Content-Encoding'] + chosen_charset = metadata[CHARSET] + chosen_encoding = metadata[CONTENT_ENCODING] charsetter = resource.charsets_provided && resource.charsets_provided.find {|c,_| c == chosen_charset }.last || :charset_nop encoder = resource.encodings_provided[chosen_encoding] response.body = case body @@ -51,8 +53,8 @@ def encode_body if body_is_fixed_length? ensure_content_length(response) else - response.headers.delete 'Content-Length' - response.headers['Transfer-Encoding'] = 'chunked' + response.headers.delete CONTENT_LENGTH + response.headers[TRANSFER_ENCODING] = 'chunked' end end diff --git a/lib/webmachine/dispatcher.rb b/lib/webmachine/dispatcher.rb index def8961e..273cf85d 100644 --- a/lib/webmachine/dispatcher.rb +++ b/lib/webmachine/dispatcher.rb @@ -1,4 +1,4 @@ -require 'forwardable' +require 'forwardable' require 'webmachine/decision' require 'webmachine/dispatcher/route' @@ -6,6 +6,8 @@ module Webmachine # Handles dispatching incoming requests to the proper registered # resources and initializing the decision logic. class Dispatcher + WM_DISPATCH = 'wm.dispatch'.freeze + # @return [Array] the list of routes that will be # dispatched to # @see #add_route @@ -40,7 +42,7 @@ def add_route(*args, &block) # @param [Response] response the response object def dispatch(request, response) if resource = find_resource(request, response) - Webmachine::Events.instrument('wm.dispatch') do |payload| + Webmachine::Events.instrument(WM_DISPATCH) do |payload| Webmachine::Decision::FSM.new(resource, request, response).run payload[:resource] = resource.class.name diff --git a/lib/webmachine/dispatcher/route.rb b/lib/webmachine/dispatcher/route.rb index e36d3b8a..e6dbc1c6 100644 --- a/lib/webmachine/dispatcher/route.rb +++ b/lib/webmachine/dispatcher/route.rb @@ -1,12 +1,14 @@ -require 'webmachine/resource' +require 'webmachine/resource' require 'webmachine/translation' +require 'webmachine/constants' module Webmachine class Dispatcher # Pairs URIs with {Resource} classes in the {Dispatcher}. To # create routes, use {Dispatcher#add_route}. class Route - include Webmachine::Translation + include Translation + include Constants # @return [Class] the resource this route will dispatch to, a # subclass of {Resource} @@ -20,10 +22,6 @@ class Route # route (see #initialize). attr_reader :guards - # When used in a path specification, will match all remaining - # segments - MATCH_ALL = :* - # String version of MATCH_ALL, deprecated. Use the symbol instead. MATCH_ALL_STR = '*'.freeze @@ -78,11 +76,13 @@ def initialize(path_spec, *args) raise ArgumentError, t('not_resource_class', :class => resource.name) unless resource < Resource end + PATH_MATCH = /^\/(.*)/.freeze + # Determines whether the given request matches this route and # should be dispatched to the {#resource}. # @param [Reqeust] request the request object def match?(request) - tokens = request.uri.path.match(/^\/(.*)/)[1].split('/') + tokens = request.uri.path.match(PATH_MATCH)[1].split(SLASH) bind(tokens, {}) && guards.all? { |guard| guard.call(request) } end @@ -90,9 +90,9 @@ def match?(request) # route, including path bindings. # @param [Request] request the request object def apply(request) - request.disp_path = request.uri.path.match(/^\/(.*)/)[1] + request.disp_path = request.uri.path.match(PATH_MATCH)[1] request.path_info = @bindings.dup - tokens = request.disp_path.split('/') + tokens = request.disp_path.split(SLASH) depth, trailing = bind(tokens, request.path_info) request.path_tokens = trailing || [] end diff --git a/lib/webmachine/errors.rb b/lib/webmachine/errors.rb index bc93325b..733018aa 100644 --- a/lib/webmachine/errors.rb +++ b/lib/webmachine/errors.rb @@ -1,10 +1,12 @@ -require 'webmachine/header_negotiation' +require 'webmachine/header_negotiation' require 'webmachine/translation' +require 'webmachine/constants' require 'webmachine/version' module Webmachine extend HeaderNegotiation extend Translation + include Constants # Renders a standard error message body for the response. The # standard messages are defined in localization files. @@ -23,7 +25,7 @@ def self.render_error(code, req, res, options={}) {:title => title, :message => message, :version => Webmachine::SERVER_STRING}.merge(options)) - res.headers['Content-Type'] = "text/html" + res.headers[CONTENT_TYPE] = TEXT_HTML end ensure_content_length(res) ensure_date_header(res) diff --git a/lib/webmachine/header_negotiation.rb b/lib/webmachine/header_negotiation.rb index 4dc292db..2de8449e 100644 --- a/lib/webmachine/header_negotiation.rb +++ b/lib/webmachine/header_negotiation.rb @@ -1,22 +1,25 @@ +require 'webmachine/constants' + module Webmachine module HeaderNegotiation + include Constants def ensure_date_header(res) if (200..499).include?(res.code) - res.headers['Date'] ||= Time.now.httpdate + res.headers[DATE] ||= Time.now.httpdate end end def ensure_content_length(res) body = res.body case - when res.headers['Transfer-Encoding'] + when res.headers[TRANSFER_ENCODING] return when [204, 205, 304].include?(res.code) - res.headers.delete 'Content-Length' + res.headers.delete CONTENT_LENGTH when body != nil - res.headers['Content-Length'] = body.respond_to?(:bytesize) ? body.bytesize.to_s : body.length.to_s + res.headers[CONTENT_LENGTH] = body.respond_to?(:bytesize) ? body.bytesize.to_s : body.length.to_s else - res.headers['Content-Length'] = '0' + res.headers[CONTENT_LENGTH] = '0' end end end diff --git a/lib/webmachine/headers.rb b/lib/webmachine/headers.rb index a441b7aa..3e2cbf6e 100644 --- a/lib/webmachine/headers.rb +++ b/lib/webmachine/headers.rb @@ -1,13 +1,19 @@ +require 'webmachine/constants' + module Webmachine # Case-insensitive Hash of Request headers class Headers < ::Hash + include Constants + CGI_HTTP_MATCH = /^HTTP_(\w+)$/.freeze + CONTENT_TYPE_LENGTH_MATCH = /^(CONTENT_(?:TYPE|LENGTH))$/.freeze + # Convert CGI-style Hash into Request headers # @param [Hash] env a hash of CGI-style env/headers # @return [Webmachine::Headers] def self.from_cgi(env) env.inject(new) do |h,(k,v)| - if k =~ /^HTTP_(\w+)$/ || k =~ /^(CONTENT_(?:TYPE|LENGTH))$/ - h[$1.tr("_", "-")] = v + if k =~ CGI_HTTP_MATCH || k =~ CONTENT_TYPE_LENGTH_MATCH + h[$1.tr(UNDERSCORE, DASH)] = v end h end diff --git a/lib/webmachine/media_type.rb b/lib/webmachine/media_type.rb index 128ee801..07fab15d 100644 --- a/lib/webmachine/media_type.rb +++ b/lib/webmachine/media_type.rb @@ -1,14 +1,17 @@ -require 'webmachine/translation' +require 'webmachine/translation' +require 'webmachine/constants' +require 'webmachine/dispatcher/route' module Webmachine # Encapsulates a MIME media type, with logic for matching types. class MediaType extend Translation + include Constants # Matches valid media types - MEDIA_TYPE_REGEX = /^\s*([^;\s]+)\s*((?:;\s*\S+\s*)*)\s*$/ + MEDIA_TYPE_REGEX = /^\s*([^;\s]+)\s*((?:;\s*\S+\s*)*)\s*$/.freeze # Matches sub-type parameters - PARAMS_REGEX = /;\s*([^=]+)(=([^;=\s]*))?/ + PARAMS_REGEX = /;\s*([^=]+)(=([^;=\s]*))?/.freeze # Creates a new MediaType by parsing an alternate representation. # @param [MediaType, String, Array] obj the raw type @@ -48,7 +51,7 @@ def initialize(type, params={}) # Detects whether the {MediaType} represents an open wildcard # type, that is, "*/*" without any {#params}. def matches_all? - @type == "*/*" && @params.empty? + @type == MATCHES_ALL && @params.empty? end # @return [true,false] Are these two types strictly equal? @@ -97,12 +100,12 @@ def to_s # @return [String] The major type, e.g. "application", "text", "image" def major - type.split("/").first + type.split(SLASH).first end # @return [String] the minor or sub-type, e.g. "json", "html", "jpeg" def minor - type.split("/").last + type.split(SLASH).last end # @param [MediaType] other the other type @@ -110,10 +113,10 @@ def minor # ignoring params and taking into account wildcards def type_matches?(other) other = self.class.parse(other) - if ["*", "*/*", type].include?(other.type) + if [Dispatcher::Route::MATCH_ALL_STR, MATCHES_ALL, type].include?(other.type) true else - other.major == major && other.minor == "*" + other.major == major && other.minor == Dispatcher::Route::MATCH_ALL_STR end end end # class MediaType diff --git a/lib/webmachine/request.rb b/lib/webmachine/request.rb index 3ff7d8fd..46865fdb 100644 --- a/lib/webmachine/request.rb +++ b/lib/webmachine/request.rb @@ -1,29 +1,18 @@ -require 'cgi' +require 'cgi' require 'forwardable' +require 'webmachine/constants' module Webmachine # Request represents a single HTTP request sent from a client. It # should be instantiated by {Adapters} when a request is received class Request + HTTP_HEADERS_MATCH = /^(?:[a-z0-9])+(?:_[a-z0-9]+)*$/i.freeze + extend Forwardable + include Constants attr_reader :method, :uri, :headers, :body attr_accessor :disp_path, :path_info, :path_tokens - GET_METHOD = "GET" - HEAD_METHOD = "HEAD" - POST_METHOD = "POST" - PUT_METHOD = "PUT" - DELETE_METHOD = "DELETE" - OPTIONS_METHOD = "OPTIONS" - TRACE_METHOD = "TRACE" - CONNECT_METHOD = "CONNECT" - - STANDARD_HTTP_METHODS = [ - GET_METHOD, HEAD_METHOD, POST_METHOD, - PUT_METHOD, DELETE_METHOD, TRACE_METHOD, - CONNECT_METHOD, OPTIONS_METHOD - ].map!(&:freeze) - # @param [String] method the HTTP request method # @param [URI] uri the requested URI, including host, scheme and # port @@ -41,9 +30,9 @@ def initialize(method, uri, headers, body) # lowercased-underscored version of the header name, e.g. # `if_unmodified_since`. def method_missing(m, *args, &block) - if m.to_s =~ /^(?:[a-z0-9])+(?:_[a-z0-9]+)*$/i + if m.to_s =~ HTTP_HEADERS_MATCH # Access headers more easily as underscored methods. - self[m.to_s.tr('_', '-')] + self[m.to_s.tr(UNDERSCORE, DASH)] else super end @@ -59,7 +48,7 @@ def has_body? # @return [URI] def base_uri @base_uri ||= uri.dup.tap do |u| - u.path = "/" + u.path = SLASH u.query = nil end end @@ -170,13 +159,13 @@ def options? def build_uri(uri, headers) uri = URI(uri) - host, _, port = headers.fetch("Host", "").rpartition(":") + host, _, port = headers.fetch(HOST, "").rpartition(COLON) return uri if host.empty? - host = "[#{host}]" if host.include?(":") + host = "[#{host}]" if host.include?(COLON) port = 80 if port.empty? - uri.scheme = "http" + uri.scheme = HTTP uri.host, uri.port = host, port.to_i URI.parse(uri.to_s) diff --git a/lib/webmachine/resource/callbacks.rb b/lib/webmachine/resource/callbacks.rb index ecc607cc..5322e29e 100644 --- a/lib/webmachine/resource/callbacks.rb +++ b/lib/webmachine/resource/callbacks.rb @@ -1,3 +1,5 @@ +require 'webmachine/constants' + module Webmachine class Resource # These methods are the primary way your {Webmachine::Resource} @@ -6,6 +8,8 @@ class Resource # the portions of the graph that are made available to your # application. module Callbacks + include Constants + # Does the resource exist? Returning a falsey value (false or nil) # will result in a '404 Not Found' response. Defaults to true. # @return [true,false] Whether the resource exists @@ -123,7 +127,7 @@ def options # @return [Array] allowed methods on this resource # @api callback def allowed_methods - ['GET', 'HEAD'] + [GET_METHOD, HEAD_METHOD] end # HTTP methods that are known to the resource. Like @@ -134,7 +138,7 @@ def allowed_methods # @return [Array] known methods # @api callback def known_methods - ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'TRACE', 'CONNECT', 'OPTIONS'] + STANDARD_HTTP_METHODS end # This method is called when a DELETE request should be enacted, @@ -209,7 +213,7 @@ def process_post # @return an array of mediatype/handler pairs # @api callback def content_types_provided - [['text/html', :to_html]] + [[TEXT_HTML, :to_html]] end # Similarly to content_types_provided, this should return an array @@ -263,7 +267,7 @@ def language_chosen(lang) # @api callback # @see Encodings def encodings_provided - {"identity" => :encode_identity } + {IDENTITY => :encode_identity } end # If this method is implemented, it should return a list of diff --git a/lib/webmachine/version.rb b/lib/webmachine/version.rb index d1f0cce3..5f310edd 100644 --- a/lib/webmachine/version.rb +++ b/lib/webmachine/version.rb @@ -1,8 +1,8 @@ -module Webmachine +module Webmachine # Library version - VERSION = "1.2.2" + VERSION = "1.2.2".freeze # String for use in "Server" HTTP response header, which includes # the {VERSION}. - SERVER_STRING = "Webmachine-Ruby/#{VERSION}" + SERVER_STRING = "Webmachine-Ruby/#{VERSION}".freeze end diff --git a/webmachine.gemspec b/webmachine.gemspec index 07b87e7f..7a269f9c 100644 --- a/webmachine.gemspec +++ b/webmachine.gemspec @@ -1,4 +1,4 @@ -$:.push File.expand_path("../lib", __FILE__) +$:.push File.expand_path("../lib", __FILE__) require 'webmachine/version' Gem::Specification.new do |gem| @@ -13,7 +13,7 @@ Gem::Specification.new do |gem| gem.homepage = "http://github.com/seancribbs/webmachine-ruby" gem.authors = ["Sean Cribbs"] gem.email = ["sean@basho.com"] - gem.license = "Apache 2.0" + gem.license = "Apache-2.0" gem.add_runtime_dependency(%q, [">= 0.4.0"]) gem.add_runtime_dependency(%q) From 2f29a81b9cef8e178ae9021225d57fd260662313 Mon Sep 17 00:00:00 2001 From: Hendrik Beskow Date: Tue, 14 Oct 2014 14:38:54 +0200 Subject: [PATCH 002/122] add missing Constants include --- lib/webmachine/adapters/rack.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/webmachine/adapters/rack.rb b/lib/webmachine/adapters/rack.rb index 3e8f389d..54eca742 100644 --- a/lib/webmachine/adapters/rack.rb +++ b/lib/webmachine/adapters/rack.rb @@ -98,6 +98,7 @@ def call(env) end class RackResponse + include Webmachine::Constants ONE_FIVE = '1.5'.freeze def initialize(body, status, headers) From 100009a8a56a8cef2ad39580096d5ec429734a30 Mon Sep 17 00:00:00 2001 From: Hendrik Beskow Date: Tue, 14 Oct 2014 15:49:41 +0200 Subject: [PATCH 003/122] added missing constantization --- lib/webmachine/adapters/httpkit.rb | 18 +++++++++++------- lib/webmachine/adapters/rack.rb | 1 - lib/webmachine/adapters/reel.rb | 9 +++++---- lib/webmachine/adapters/webrick.rb | 12 ++++++++---- lib/webmachine/constants.rb | 8 +++----- lib/webmachine/dispatcher/route.rb | 4 ++++ 6 files changed, 31 insertions(+), 21 deletions(-) diff --git a/lib/webmachine/adapters/httpkit.rb b/lib/webmachine/adapters/httpkit.rb index 9961f8ff..ba297083 100644 --- a/lib/webmachine/adapters/httpkit.rb +++ b/lib/webmachine/adapters/httpkit.rb @@ -1,15 +1,19 @@ +require 'webmachine/adapter' +require 'webmachine/constants' +require 'webmachine/version' require 'httpkit' - require 'webmachine/version' -require 'webmachine/headers' -require 'webmachine/request' require 'webmachine/response' -require 'webmachine/dispatcher' -require 'webmachine/chunked_body' +require 'webmachine/request' +require 'webmachine/headers' module Webmachine module Adapters class HTTPkit < Adapter + include Constants + + VERSION_STRING = "#{Webmachine::SERVER_STRING} HTTPkit/#{::HTTPkit::VERSION}".freeze + def options @options ||= { :address => application.configuration.ip, @@ -49,8 +53,8 @@ def convert_request(request) # Converts Webmachine::Response to HTTPkit::Response def convert_response(response) - response.headers["Server"] = - Webmachine::SERVER_STRING + ' HTTPkit/' + ::HTTPkit::VERSION + response.headers[SERVER] = VERSION_STRING + ::HTTPkit::Response.new( response.code.to_i, diff --git a/lib/webmachine/adapters/rack.rb b/lib/webmachine/adapters/rack.rb index 54eca742..86335ac9 100644 --- a/lib/webmachine/adapters/rack.rb +++ b/lib/webmachine/adapters/rack.rb @@ -39,7 +39,6 @@ class Rack < Adapter DEFAULT_OPTIONS = {} REQUEST_URI = 'REQUEST_URI'.freeze - SERVER = 'Server'.freeze VERSION_STRING = "#{Webmachine::SERVER_STRING} Rack/#{::Rack.version}".freeze NEWLINE = "\n".freeze diff --git a/lib/webmachine/adapters/reel.rb b/lib/webmachine/adapters/reel.rb index d76b31d5..c0a45f80 100644 --- a/lib/webmachine/adapters/reel.rb +++ b/lib/webmachine/adapters/reel.rb @@ -1,14 +1,15 @@ +require 'webmachine/adapter' +require 'webmachine/constants' +require 'set' require 'reel' -require 'webmachine/version' require 'webmachine/headers' require 'webmachine/request' require 'webmachine/response' -require 'webmachine/dispatcher' -require 'set' module Webmachine module Adapters class Reel < Adapter + include Constants # Used to override default Reel server options (useful in testing) DEFAULT_OPTIONS = {} @@ -55,7 +56,7 @@ def process(connection) # state machine. Do the "Railsy" thing and handle them like POSTs # with a magical parameter if @extra_verbs.include?(request.method) - method = "POST" + method = POST_METHOD param = "_method=#{request.method}" uri = request_uri(request.url, request.headers, param) else diff --git a/lib/webmachine/adapters/webrick.rb b/lib/webmachine/adapters/webrick.rb index 18644521..4f301197 100644 --- a/lib/webmachine/adapters/webrick.rb +++ b/lib/webmachine/adapters/webrick.rb @@ -1,9 +1,11 @@ +require 'webmachine/adapter' require 'webrick' -require 'webmachine/version' +require 'webmachine/constants' require 'webmachine/headers' +require 'webmachine/adapter/lazy_request_body' require 'webmachine/request' require 'webmachine/response' -require 'webmachine/dispatcher' +require 'webmachine/version' module Webmachine module Adapters @@ -25,6 +27,8 @@ def run # WEBRick::HTTPServer that is run by the WEBrick adapter. class Server < ::WEBrick::HTTPServer + include Webmachine::Constants + def initialize(options) @application = options[:application] super(options) @@ -49,12 +53,12 @@ def service(wreq, wres) cookies = [response.headers['Set-Cookie'] || []].flatten cookies.each { |c| wres.cookies << c } - wres['Server'] = [Webmachine::SERVER_STRING, wres.config[:ServerSoftware]].join(" ") + wres[SERVER] = [Webmachine::SERVER_STRING, wres.config[:ServerSoftware]].join(" ") case response.body when String wres.body << response.body when Enumerable - wres.chunked = response.headers['Transfer-Encoding'] == 'chunked' + wres.chunked = response.headers[TRANSFER_ENCODING] == 'chunked' response.body.each {|part| wres.body << part } else if response.body.respond_to?(:call) diff --git a/lib/webmachine/constants.rb b/lib/webmachine/constants.rb index 3d3cbc15..f94a64fa 100644 --- a/lib/webmachine/constants.rb +++ b/lib/webmachine/constants.rb @@ -27,11 +27,7 @@ module Constants # A Slash SLASH = '/'.freeze - MATCHES_ALL = '*/*' - - # When used in a path specification, will match all remaining - # segments - MATCH_ALL = :* + MATCHES_ALL = '*/*'.freeze GET_METHOD = "GET".freeze HEAD_METHOD = "HEAD".freeze @@ -74,5 +70,7 @@ module Constants # identity Encoding IDENTITY = 'identity'.freeze + + SERVER = 'Server'.freeze end end diff --git a/lib/webmachine/dispatcher/route.rb b/lib/webmachine/dispatcher/route.rb index e6dbc1c6..acacf112 100644 --- a/lib/webmachine/dispatcher/route.rb +++ b/lib/webmachine/dispatcher/route.rb @@ -22,6 +22,10 @@ class Route # route (see #initialize). attr_reader :guards + # When used in a path specification, will match all remaining + # segments + MATCH_ALL = :* + # String version of MATCH_ALL, deprecated. Use the symbol instead. MATCH_ALL_STR = '*'.freeze From c3e21019ea7f81b57b05a1684617e4476c0d292f Mon Sep 17 00:00:00 2001 From: Hendrik Beskow Date: Tue, 14 Oct 2014 15:55:55 +0200 Subject: [PATCH 004/122] fix typo --- lib/webmachine/adapters/webrick.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/webmachine/adapters/webrick.rb b/lib/webmachine/adapters/webrick.rb index 4f301197..c16838fb 100644 --- a/lib/webmachine/adapters/webrick.rb +++ b/lib/webmachine/adapters/webrick.rb @@ -2,7 +2,7 @@ require 'webrick' require 'webmachine/constants' require 'webmachine/headers' -require 'webmachine/adapter/lazy_request_body' +require 'webmachine/adapters/lazy_request_body' require 'webmachine/request' require 'webmachine/response' require 'webmachine/version' From 1846c72692c0eabc8dd47da15692bd860ad605f4 Mon Sep 17 00:00:00 2001 From: Asmod4n Date: Wed, 15 Oct 2014 09:01:55 +0200 Subject: [PATCH 005/122] don't rescue "Exception" --- lib/webmachine/decision/fsm.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/webmachine/decision/fsm.rb b/lib/webmachine/decision/fsm.rb index d641a7f2..2a63c322 100644 --- a/lib/webmachine/decision/fsm.rb +++ b/lib/webmachine/decision/fsm.rb @@ -37,7 +37,7 @@ def run raise InvalidResource, t('fsm_broke', :state => state, :result => result.inspect) end end - rescue Exception => e + rescue => e Webmachine.render_error(500, request, response, :message => e.message) ensure trace_response(response) @@ -50,7 +50,7 @@ def handle_exceptions rescue MalformedRequest => e Webmachine.render_error(400, request, response, :message => e.message) 400 - rescue Exception => e + rescue => e resource.handle_exception(e) 500 end From 93fbc68e28400ec8e591919c8eaca5124df4f204 Mon Sep 17 00:00:00 2001 From: Asmod4n Date: Wed, 15 Oct 2014 09:06:50 +0200 Subject: [PATCH 006/122] raise RuntimeError instead of Exception --- spec/webmachine/decision/fsm_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/webmachine/decision/fsm_spec.rb b/spec/webmachine/decision/fsm_spec.rb index 8d20ea48..adb27ebe 100644 --- a/spec/webmachine/decision/fsm_spec.rb +++ b/spec/webmachine/decision/fsm_spec.rb @@ -6,7 +6,7 @@ subject { described_class.new(resource, request, response) } describe 'handling of exceptions from decision methods' do - let(:exception) { Exception.new } + let(:exception) { RuntimeError.new } before do allow(subject).to receive(Webmachine::Decision::Flow::START) { raise exception } @@ -24,7 +24,7 @@ end describe 'handling of exceptions from resource.handle_exception' do - let(:exception) { Exception.new('an error message') } + let(:exception) { RuntimeError.new('an error message') } before do allow(subject).to receive(Webmachine::Decision::Flow::START) { raise } @@ -50,7 +50,7 @@ end describe 'handling of exceptions from resource.finish_request' do - let(:exception) { Exception.new } + let(:exception) { RuntimeError.new } before do allow(resource).to receive(:finish_request) { raise exception } From 43468629129e10d3d62c55d2f1b6b16945f6f89e Mon Sep 17 00:00:00 2001 From: Asmod4n Date: Wed, 15 Oct 2014 09:08:21 +0200 Subject: [PATCH 007/122] Revert 93fbc68e28400ec8e591919c8eaca5124df4f204 --- spec/webmachine/decision/fsm_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/webmachine/decision/fsm_spec.rb b/spec/webmachine/decision/fsm_spec.rb index adb27ebe..8d20ea48 100644 --- a/spec/webmachine/decision/fsm_spec.rb +++ b/spec/webmachine/decision/fsm_spec.rb @@ -6,7 +6,7 @@ subject { described_class.new(resource, request, response) } describe 'handling of exceptions from decision methods' do - let(:exception) { RuntimeError.new } + let(:exception) { Exception.new } before do allow(subject).to receive(Webmachine::Decision::Flow::START) { raise exception } @@ -24,7 +24,7 @@ end describe 'handling of exceptions from resource.handle_exception' do - let(:exception) { RuntimeError.new('an error message') } + let(:exception) { Exception.new('an error message') } before do allow(subject).to receive(Webmachine::Decision::Flow::START) { raise } @@ -50,7 +50,7 @@ end describe 'handling of exceptions from resource.finish_request' do - let(:exception) { RuntimeError.new } + let(:exception) { Exception.new } before do allow(resource).to receive(:finish_request) { raise exception } From 3e561c53b8729ea65fb4f42944c1a465a723473c Mon Sep 17 00:00:00 2001 From: Asmod4n Date: Wed, 15 Oct 2014 09:09:35 +0200 Subject: [PATCH 008/122] raise RuntimeError instead of Exception --- spec/webmachine/decision/fsm_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/webmachine/decision/fsm_spec.rb b/spec/webmachine/decision/fsm_spec.rb index 8d20ea48..adb27ebe 100644 --- a/spec/webmachine/decision/fsm_spec.rb +++ b/spec/webmachine/decision/fsm_spec.rb @@ -6,7 +6,7 @@ subject { described_class.new(resource, request, response) } describe 'handling of exceptions from decision methods' do - let(:exception) { Exception.new } + let(:exception) { RuntimeError.new } before do allow(subject).to receive(Webmachine::Decision::Flow::START) { raise exception } @@ -24,7 +24,7 @@ end describe 'handling of exceptions from resource.handle_exception' do - let(:exception) { Exception.new('an error message') } + let(:exception) { RuntimeError.new('an error message') } before do allow(subject).to receive(Webmachine::Decision::Flow::START) { raise } @@ -50,7 +50,7 @@ end describe 'handling of exceptions from resource.finish_request' do - let(:exception) { Exception.new } + let(:exception) { RuntimeError.new } before do allow(resource).to receive(:finish_request) { raise exception } From 46384612155a30710a5ebb1ab9258a7b5f86d54c Mon Sep 17 00:00:00 2001 From: Asmod4n Date: Wed, 15 Oct 2014 22:22:33 +0200 Subject: [PATCH 009/122] move constants to webmachine namespace --- lib/webmachine/adapters/httpkit.rb | 2 - lib/webmachine/adapters/rack.rb | 2 - lib/webmachine/adapters/reel.rb | 1 - lib/webmachine/adapters/webrick.rb | 1 - lib/webmachine/chunked_body.rb | 2 - lib/webmachine/constants.rb | 104 +++++++++++++-------------- lib/webmachine/decision/conneg.rb | 1 - lib/webmachine/decision/flow.rb | 1 - lib/webmachine/decision/fsm.rb | 1 - lib/webmachine/decision/helpers.rb | 1 - lib/webmachine/dispatcher/route.rb | 1 - lib/webmachine/errors.rb | 1 - lib/webmachine/header_negotiation.rb | 1 - lib/webmachine/headers.rb | 1 - lib/webmachine/media_type.rb | 1 - lib/webmachine/request.rb | 2 +- lib/webmachine/resource/callbacks.rb | 2 - 17 files changed, 52 insertions(+), 73 deletions(-) diff --git a/lib/webmachine/adapters/httpkit.rb b/lib/webmachine/adapters/httpkit.rb index ba297083..2198e8f8 100644 --- a/lib/webmachine/adapters/httpkit.rb +++ b/lib/webmachine/adapters/httpkit.rb @@ -10,8 +10,6 @@ module Webmachine module Adapters class HTTPkit < Adapter - include Constants - VERSION_STRING = "#{Webmachine::SERVER_STRING} HTTPkit/#{::HTTPkit::VERSION}".freeze def options diff --git a/lib/webmachine/adapters/rack.rb b/lib/webmachine/adapters/rack.rb index 86335ac9..c1eccb72 100644 --- a/lib/webmachine/adapters/rack.rb +++ b/lib/webmachine/adapters/rack.rb @@ -34,7 +34,6 @@ module Adapters # MyApplication.run # class Rack < Adapter - include Constants # Used to override default Rack server options (useful in testing) DEFAULT_OPTIONS = {} @@ -97,7 +96,6 @@ def call(env) end class RackResponse - include Webmachine::Constants ONE_FIVE = '1.5'.freeze def initialize(body, status, headers) diff --git a/lib/webmachine/adapters/reel.rb b/lib/webmachine/adapters/reel.rb index c0a45f80..ec7aebb2 100644 --- a/lib/webmachine/adapters/reel.rb +++ b/lib/webmachine/adapters/reel.rb @@ -9,7 +9,6 @@ module Webmachine module Adapters class Reel < Adapter - include Constants # Used to override default Reel server options (useful in testing) DEFAULT_OPTIONS = {} diff --git a/lib/webmachine/adapters/webrick.rb b/lib/webmachine/adapters/webrick.rb index c16838fb..5967787b 100644 --- a/lib/webmachine/adapters/webrick.rb +++ b/lib/webmachine/adapters/webrick.rb @@ -27,7 +27,6 @@ def run # WEBRick::HTTPServer that is run by the WEBrick adapter. class Server < ::WEBrick::HTTPServer - include Webmachine::Constants def initialize(options) @application = options[:application] diff --git a/lib/webmachine/chunked_body.rb b/lib/webmachine/chunked_body.rb index 65c4655c..ac65a26c 100644 --- a/lib/webmachine/chunked_body.rb +++ b/lib/webmachine/chunked_body.rb @@ -15,8 +15,6 @@ module Webmachine # # This is needed for Ruby webservers which don't do the chunking themselves. class ChunkedBody - include Constants - # Final chunk in any chunked-encoding response FINAL_CHUNK = "0#{CRLF}#{CRLF}".freeze diff --git a/lib/webmachine/constants.rb b/lib/webmachine/constants.rb index f94a64fa..2aeb8620 100644 --- a/lib/webmachine/constants.rb +++ b/lib/webmachine/constants.rb @@ -1,76 +1,74 @@ module Webmachine - module Constants - # Default HTTP linebreak - CRLF = "\r\n".freeze + # Universal HTTP delimiter + CRLF = "\r\n".freeze - # HTTP Content-Type - CONTENT_TYPE = 'Content-Type'.freeze + # HTTP Content-Type + CONTENT_TYPE = 'Content-Type'.freeze - # Default Content-Type - TEXT_HTML = 'text/html'.freeze + # Default Content-Type + TEXT_HTML = 'text/html'.freeze - # HTTP Date - DATE = 'Date'.freeze + # HTTP Date + DATE = 'Date'.freeze - # HTTP Transfer-Encoding - TRANSFER_ENCODING = 'Transfer-Encoding'.freeze + # HTTP Transfer-Encoding + TRANSFER_ENCODING = 'Transfer-Encoding'.freeze - # HTTP Content-Length - CONTENT_LENGTH = 'Content-Length'.freeze + # HTTP Content-Length + CONTENT_LENGTH = 'Content-Length'.freeze - # A underscore - UNDERSCORE = '_'.freeze + # A underscore + UNDERSCORE = '_'.freeze - # A dash - DASH = '-'.freeze + # A dash + DASH = '-'.freeze - # A Slash - SLASH = '/'.freeze + # A Slash + SLASH = '/'.freeze - MATCHES_ALL = '*/*'.freeze + MATCHES_ALL = '*/*'.freeze - GET_METHOD = "GET".freeze - HEAD_METHOD = "HEAD".freeze - POST_METHOD = "POST".freeze - PUT_METHOD = "PUT".freeze - DELETE_METHOD = "DELETE".freeze - OPTIONS_METHOD = "OPTIONS".freeze - TRACE_METHOD = "TRACE".freeze - CONNECT_METHOD = "CONNECT".freeze + GET_METHOD = "GET".freeze + HEAD_METHOD = "HEAD".freeze + POST_METHOD = "POST".freeze + PUT_METHOD = "PUT".freeze + DELETE_METHOD = "DELETE".freeze + OPTIONS_METHOD = "OPTIONS".freeze + TRACE_METHOD = "TRACE".freeze + CONNECT_METHOD = "CONNECT".freeze - STANDARD_HTTP_METHODS = [ - GET_METHOD, HEAD_METHOD, POST_METHOD, - PUT_METHOD, DELETE_METHOD, TRACE_METHOD, - CONNECT_METHOD, OPTIONS_METHOD - ].map!(&:freeze) + STANDARD_HTTP_METHODS = [ + GET_METHOD, HEAD_METHOD, POST_METHOD, + PUT_METHOD, DELETE_METHOD, TRACE_METHOD, + CONNECT_METHOD, OPTIONS_METHOD + ].map!(&:freeze) - # A colon - COLON = ':'.freeze + # A colon + COLON = ':'.freeze - # http string - HTTP = 'http'.freeze + # http string + HTTP = 'http'.freeze - # Host string - HOST = 'Host'.freeze + # Host string + HOST = 'Host'.freeze - # HTTP Content-Encoding - CONTENT_ENCODING = 'Content-Encoding'.freeze + # HTTP Content-Encoding + CONTENT_ENCODING = 'Content-Encoding'.freeze - # Charset string - CHARSET = 'Charset'.freeze + # Charset string + CHARSET = 'Charset'.freeze - # Semicolon split match - SPLIT_SEMI = /\s*,\s*/.freeze + # Semicolon split match + SPLIT_SEMI = /\s*,\s*/.freeze - # Star Character - STAR = '*'.freeze + # Star Character + STAR = '*'.freeze - # HTTP Location - LOCATION = 'Location'.freeze + # HTTP Location + LOCATION = 'Location'.freeze - # identity Encoding - IDENTITY = 'identity'.freeze + # identity Encoding + IDENTITY = 'identity'.freeze - SERVER = 'Server'.freeze - end + SERVER = 'Server'.freeze end diff --git a/lib/webmachine/decision/conneg.rb b/lib/webmachine/decision/conneg.rb index f25447de..e4507a6b 100644 --- a/lib/webmachine/decision/conneg.rb +++ b/lib/webmachine/decision/conneg.rb @@ -8,7 +8,6 @@ module Decision # specifically, choosing media types, encodings, character sets # and languages. module Conneg - include Constants HAS_ENCODING = defined?(::Encoding) # Ruby 1.9 compat # Given the 'Accept' header and provided types, chooses an diff --git a/lib/webmachine/decision/flow.rb b/lib/webmachine/decision/flow.rb index 48d7608b..103e23e6 100644 --- a/lib/webmachine/decision/flow.rb +++ b/lib/webmachine/decision/flow.rb @@ -19,7 +19,6 @@ module Decision # @see https://raw.github.com/wiki/basho/webmachine/images/http-headers-status-v3.png module Flow include Base64 - include Constants # Version of the flow diagram VERSION = 3 diff --git a/lib/webmachine/decision/fsm.rb b/lib/webmachine/decision/fsm.rb index beb7c83c..fee2bf1e 100644 --- a/lib/webmachine/decision/fsm.rb +++ b/lib/webmachine/decision/fsm.rb @@ -12,7 +12,6 @@ class FSM include Helpers include Trace::FSM include Translation - include Constants attr_reader :resource, :request, :response, :metadata diff --git a/lib/webmachine/decision/helpers.rb b/lib/webmachine/decision/helpers.rb index a60d5230..046e1497 100644 --- a/lib/webmachine/decision/helpers.rb +++ b/lib/webmachine/decision/helpers.rb @@ -14,7 +14,6 @@ module Helpers include QuotedString include Streaming include HeaderNegotiation - include Constants # Determines if the response has a body/entity set. def has_response_body? diff --git a/lib/webmachine/dispatcher/route.rb b/lib/webmachine/dispatcher/route.rb index acacf112..dae0c60e 100644 --- a/lib/webmachine/dispatcher/route.rb +++ b/lib/webmachine/dispatcher/route.rb @@ -8,7 +8,6 @@ class Dispatcher # create routes, use {Dispatcher#add_route}. class Route include Translation - include Constants # @return [Class] the resource this route will dispatch to, a # subclass of {Resource} diff --git a/lib/webmachine/errors.rb b/lib/webmachine/errors.rb index 733018aa..e25ac53f 100644 --- a/lib/webmachine/errors.rb +++ b/lib/webmachine/errors.rb @@ -6,7 +6,6 @@ module Webmachine extend HeaderNegotiation extend Translation - include Constants # Renders a standard error message body for the response. The # standard messages are defined in localization files. diff --git a/lib/webmachine/header_negotiation.rb b/lib/webmachine/header_negotiation.rb index 2de8449e..2ad6a118 100644 --- a/lib/webmachine/header_negotiation.rb +++ b/lib/webmachine/header_negotiation.rb @@ -2,7 +2,6 @@ module Webmachine module HeaderNegotiation - include Constants def ensure_date_header(res) if (200..499).include?(res.code) res.headers[DATE] ||= Time.now.httpdate diff --git a/lib/webmachine/headers.rb b/lib/webmachine/headers.rb index 3e2cbf6e..031d4783 100644 --- a/lib/webmachine/headers.rb +++ b/lib/webmachine/headers.rb @@ -3,7 +3,6 @@ module Webmachine # Case-insensitive Hash of Request headers class Headers < ::Hash - include Constants CGI_HTTP_MATCH = /^HTTP_(\w+)$/.freeze CONTENT_TYPE_LENGTH_MATCH = /^(CONTENT_(?:TYPE|LENGTH))$/.freeze diff --git a/lib/webmachine/media_type.rb b/lib/webmachine/media_type.rb index 07fab15d..d6bdf988 100644 --- a/lib/webmachine/media_type.rb +++ b/lib/webmachine/media_type.rb @@ -6,7 +6,6 @@ module Webmachine # Encapsulates a MIME media type, with logic for matching types. class MediaType extend Translation - include Constants # Matches valid media types MEDIA_TYPE_REGEX = /^\s*([^;\s]+)\s*((?:;\s*\S+\s*)*)\s*$/.freeze diff --git a/lib/webmachine/request.rb b/lib/webmachine/request.rb index 46865fdb..d42642ff 100644 --- a/lib/webmachine/request.rb +++ b/lib/webmachine/request.rb @@ -9,7 +9,7 @@ class Request HTTP_HEADERS_MATCH = /^(?:[a-z0-9])+(?:_[a-z0-9]+)*$/i.freeze extend Forwardable - include Constants + attr_reader :method, :uri, :headers, :body attr_accessor :disp_path, :path_info, :path_tokens diff --git a/lib/webmachine/resource/callbacks.rb b/lib/webmachine/resource/callbacks.rb index 5322e29e..596aa215 100644 --- a/lib/webmachine/resource/callbacks.rb +++ b/lib/webmachine/resource/callbacks.rb @@ -8,8 +8,6 @@ class Resource # the portions of the graph that are made available to your # application. module Callbacks - include Constants - # Does the resource exist? Returning a falsey value (false or nil) # will result in a '404 Not Found' response. Defaults to true. # @return [true,false] Whether the resource exists From aa2ae6a90499d20d970db6177897a186c47bb1a3 Mon Sep 17 00:00:00 2001 From: Asmod4n Date: Thu, 16 Oct 2014 06:21:42 +0200 Subject: [PATCH 010/122] don't freeze the frozen --- lib/webmachine/constants.rb | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/webmachine/constants.rb b/lib/webmachine/constants.rb index 2aeb8620..9f387939 100644 --- a/lib/webmachine/constants.rb +++ b/lib/webmachine/constants.rb @@ -28,20 +28,21 @@ MATCHES_ALL = '*/*'.freeze - GET_METHOD = "GET".freeze - HEAD_METHOD = "HEAD".freeze - POST_METHOD = "POST".freeze - PUT_METHOD = "PUT".freeze - DELETE_METHOD = "DELETE".freeze - OPTIONS_METHOD = "OPTIONS".freeze - TRACE_METHOD = "TRACE".freeze - CONNECT_METHOD = "CONNECT".freeze + GET_METHOD = "GET" + HEAD_METHOD = "HEAD" + POST_METHOD = "POST" + PUT_METHOD = "PUT" + DELETE_METHOD = "DELETE" + OPTIONS_METHOD = "OPTIONS" + TRACE_METHOD = "TRACE" + CONNECT_METHOD = "CONNECT" STANDARD_HTTP_METHODS = [ GET_METHOD, HEAD_METHOD, POST_METHOD, PUT_METHOD, DELETE_METHOD, TRACE_METHOD, CONNECT_METHOD, OPTIONS_METHOD ].map!(&:freeze) + STANDARD_HTTP_METHODS.freeze # A colon COLON = ':'.freeze From c6f2da5c276e0935a7f784091311eb9eef6e15e5 Mon Sep 17 00:00:00 2001 From: Asmod4n Date: Thu, 16 Oct 2014 13:29:42 +0200 Subject: [PATCH 011/122] add memory test [no ci] --- memory_test.rb | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 memory_test.rb diff --git a/memory_test.rb b/memory_test.rb new file mode 100644 index 00000000..34479a5e --- /dev/null +++ b/memory_test.rb @@ -0,0 +1,35 @@ +$:.push File.expand_path("../lib", __FILE__) +require 'webmachine' + +class Constantized < Webmachine::Resource + HELLO_WORLD = "Hello World".freeze + ALLOWED_METHODS = [Webmachine::GET_METHOD].freeze + CONTENT_TYPES_PROVIDED = [[Webmachine::TEXT_HTML, :to_html]].freeze + + def allowed_methods + ALLOWED_METHODS + end + + def content_types_provided + CONTENT_TYPES_PROVIDED + end + + def to_html + HELLO_WORLD + end +end + +Webmachine.application.routes do + add ['constantized'], Constantized +end + +require 'webmachine/test' +session = Webmachine::Test::Session.new(Webmachine.application) + +require 'memory_profiler' +report = MemoryProfiler.report do + session.get('/constantized') +end + +report.pretty_print + From ea05b1a5023f4d74c5d9e2c32bef7c95917a80cb Mon Sep 17 00:00:00 2001 From: Asmod4n Date: Thu, 16 Oct 2014 13:55:20 +0200 Subject: [PATCH 012/122] let it run multiple times [ci skip] --- memory_test.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/memory_test.rb b/memory_test.rb index 34479a5e..fcb2fc25 100644 --- a/memory_test.rb +++ b/memory_test.rb @@ -3,8 +3,8 @@ class Constantized < Webmachine::Resource HELLO_WORLD = "Hello World".freeze - ALLOWED_METHODS = [Webmachine::GET_METHOD].freeze - CONTENT_TYPES_PROVIDED = [[Webmachine::TEXT_HTML, :to_html]].freeze + ALLOWED_METHODS = ['GET'.freeze].freeze + CONTENT_TYPES_PROVIDED = [['text/html'.freeze, :to_html].freeze].freeze def allowed_methods ALLOWED_METHODS @@ -25,10 +25,12 @@ def to_html require 'webmachine/test' session = Webmachine::Test::Session.new(Webmachine.application) - +CONSTANTIZED = '/constantized'.freeze require 'memory_profiler' report = MemoryProfiler.report do - session.get('/constantized') + 5.times do + session.get(CONSTANTIZED) + end end report.pretty_print From 395f7a230c83f46eac2666499641306ba4e44413 Mon Sep 17 00:00:00 2001 From: Asmod4n Date: Fri, 17 Oct 2014 09:08:43 +0200 Subject: [PATCH 013/122] improve header lookup time --- lib/webmachine/request.rb | 13 +++++++++++-- memory_test.rb | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/webmachine/request.rb b/lib/webmachine/request.rb index d42642ff..76710bb9 100644 --- a/lib/webmachine/request.rb +++ b/lib/webmachine/request.rb @@ -30,9 +30,18 @@ def initialize(method, uri, headers, body) # lowercased-underscored version of the header name, e.g. # `if_unmodified_since`. def method_missing(m, *args, &block) - if m.to_s =~ HTTP_HEADERS_MATCH + if m =~ HTTP_HEADERS_MATCH # Access headers more easily as underscored methods. - self[m.to_s.tr(UNDERSCORE, DASH)] + header_name = m.to_s.tr(UNDERSCORE, DASH) + if (header_value = headers[header_name]) + # Make future lookups faster. + self.class.class_eval <<-RUBY, __FILE__, __LINE__ + def #{m} + headers["#{header_name}"] + end + RUBY + end + header_value else super end diff --git a/memory_test.rb b/memory_test.rb index fcb2fc25..1bf0246e 100644 --- a/memory_test.rb +++ b/memory_test.rb @@ -28,7 +28,7 @@ def to_html CONSTANTIZED = '/constantized'.freeze require 'memory_profiler' report = MemoryProfiler.report do - 5.times do + 100.times do session.get(CONSTANTIZED) end end From 7ccf8c337d683778bb72eeb3d073f5c57c2be8eb Mon Sep 17 00:00:00 2001 From: Asmod4n Date: Fri, 17 Oct 2014 09:31:39 +0200 Subject: [PATCH 014/122] add missing set require i18n tries to use Set.new somewhere, but doesn't seam to require it itself. --- lib/webmachine/translation.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/webmachine/translation.rb b/lib/webmachine/translation.rb index 16210db7..eb0a932a 100644 --- a/lib/webmachine/translation.rb +++ b/lib/webmachine/translation.rb @@ -1,3 +1,4 @@ +require 'set' require 'i18n' I18n.enforce_available_locales = true if I18n.respond_to?(:enforce_available_locales) I18n.config.load_path << File.expand_path("../locale/en.yml", __FILE__) From d1636060ddde05456b6eaeb9bea4a48458970ba1 Mon Sep 17 00:00:00 2001 From: Sean Cribbs Date: Sat, 3 Jan 2015 15:29:42 -0600 Subject: [PATCH 015/122] Release 1.3.0 --- .gitignore | 2 ++ Rakefile | 1 - lib/webmachine/streaming/io_encoder.rb | 2 +- lib/webmachine/version.rb | 2 +- spec/webmachine/decision/conneg_spec.rb | 2 +- spec/webmachine/decision/helpers_spec.rb | 2 +- 6 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index c84df18a..bdc53161 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,5 @@ Gemfile.lock .rvmrc .SyncID .SyncIgnore +vendor + diff --git a/Rakefile b/Rakefile index f88cf434..531ade9f 100644 --- a/Rakefile +++ b/Rakefile @@ -51,7 +51,6 @@ task :clean_whitespace do end end -require 'rspec/core' require 'rspec/core/rake_task' desc "Run specs" diff --git a/lib/webmachine/streaming/io_encoder.rb b/lib/webmachine/streaming/io_encoder.rb index 55e069b9..615eb6ba 100644 --- a/lib/webmachine/streaming/io_encoder.rb +++ b/lib/webmachine/streaming/io_encoder.rb @@ -29,7 +29,7 @@ def copy_stream(outstream) each {|chunk| outstream << chunk } end end - + # Allows the response body to be converted to a IO object. # @return [IO,nil] the body as a IO object, or nil. def to_io diff --git a/lib/webmachine/version.rb b/lib/webmachine/version.rb index 5f310edd..752683a8 100644 --- a/lib/webmachine/version.rb +++ b/lib/webmachine/version.rb @@ -1,6 +1,6 @@ module Webmachine # Library version - VERSION = "1.2.2".freeze + VERSION = "1.3.0".freeze # String for use in "Server" HTTP response header, which includes # the {VERSION}. diff --git a/spec/webmachine/decision/conneg_spec.rb b/spec/webmachine/decision/conneg_spec.rb index 07428b0c..c3f8ef42 100644 --- a/spec/webmachine/decision/conneg_spec.rb +++ b/spec/webmachine/decision/conneg_spec.rb @@ -47,7 +47,7 @@ "bah;") }.to raise_error(Webmachine::MalformedRequest) end - + it "should choose a type when more than one accept header is present" do expect(subject.choose_media_type(["text/html"], ["text/html", "text/plain"])).to eq("text/html") diff --git a/spec/webmachine/decision/helpers_spec.rb b/spec/webmachine/decision/helpers_spec.rb index cd1b09d5..d495e045 100644 --- a/spec/webmachine/decision/helpers_spec.rb +++ b/spec/webmachine/decision/helpers_spec.rb @@ -128,7 +128,7 @@ def accept_doc; result; end subject.encode_body expect(response.body).to be_instance_of(Webmachine::Streaming::CallableEncoder) end - + it_should_behave_like "a non-String body" end From 52c35e7135c4c7b29db6d894cb75489faeb8a8a6 Mon Sep 17 00:00:00 2001 From: Asmod4n Date: Sun, 4 Jan 2015 12:48:39 +0100 Subject: [PATCH 016/122] cleanup attempts for uri building --- lib/webmachine/request.rb | 36 +++++++++++++++++++++++------ lib/webmachine/spec/adapter_lint.rb | 6 ++--- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/lib/webmachine/request.rb b/lib/webmachine/request.rb index 76710bb9..1d98ffb5 100644 --- a/lib/webmachine/request.rb +++ b/lib/webmachine/request.rb @@ -1,6 +1,7 @@ require 'cgi' require 'forwardable' require 'webmachine/constants' +require 'ipaddr' module Webmachine # Request represents a single HTTP request sent from a client. It @@ -165,19 +166,40 @@ def options? private + IPV6_MATCH = /\A\[(?
.* )\]:(? \d+ )\z/x.freeze # string like "[::1]:80" + IPV4_MATCH = /\A(?
[^:]+ ):(? \d+ )\z/x.freeze # string like "127.0.0.1:80" + + def parse_addr(string) + # Split host and port number from string. + case string + when IPV6_MATCH + address = $~[:address] + port = $~[:port] + when IPV4_MATCH + address = $~[:address] + port = $~[:port] + else # string with no port number + address = string + port = nil + end + + # Pass address, port to Addrinfo.tcp. It will raise SocketError if address or port is not valid. + Addrinfo.tcp(address, port) + end + def build_uri(uri, headers) uri = URI(uri) + if uri.host + return uri + end - host, _, port = headers.fetch(HOST, "").rpartition(COLON) - return uri if host.empty? - - host = "[#{host}]" if host.include?(COLON) - port = 80 if port.empty? + addr = parse_addr(headers.fetch(HOST)) uri.scheme = HTTP - uri.host, uri.port = host, port.to_i + uri.host = addr.ip_address + uri.port = addr.ip_port == 0 ? 80 : addr.ip_port - URI.parse(uri.to_s) + uri end end # class Request diff --git a/lib/webmachine/spec/adapter_lint.rb b/lib/webmachine/spec/adapter_lint.rb index 74244db8..36e9dde5 100644 --- a/lib/webmachine/spec/adapter_lint.rb +++ b/lib/webmachine/spec/adapter_lint.rb @@ -1,4 +1,4 @@ -require "webmachine/spec/test_resource" +require "webmachine/spec/test_resource" require "net/http" shared_examples_for :adapter_lint do @@ -57,8 +57,8 @@ let(:address) { "::1" } it "provides the IPv6 request URI" do - if RUBY_VERSION =~ /^2\.(0|1)\./ - skip "Net::HTTP regression in Ruby 2.(0|1)" + if RUBY_VERSION =~ /^2\.(0|1\2)\./ + skip "Net::HTTP regression in Ruby 2.(0|1|2)" end request = Net::HTTP::Get.new("/test") From d0d88ca08ba6f1a971afbd3289fa3d2521435b51 Mon Sep 17 00:00:00 2001 From: Asmod4n Date: Sun, 4 Jan 2015 12:51:28 +0100 Subject: [PATCH 017/122] typo --- lib/webmachine/spec/adapter_lint.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/webmachine/spec/adapter_lint.rb b/lib/webmachine/spec/adapter_lint.rb index 36e9dde5..b2f85e73 100644 --- a/lib/webmachine/spec/adapter_lint.rb +++ b/lib/webmachine/spec/adapter_lint.rb @@ -57,7 +57,7 @@ let(:address) { "::1" } it "provides the IPv6 request URI" do - if RUBY_VERSION =~ /^2\.(0|1\2)\./ + if RUBY_VERSION =~ /^2\.(0|1|2)\./ skip "Net::HTTP regression in Ruby 2.(0|1|2)" end From 2c5ff2bf69920f1ac1975be0e7b7d9977dd1df09 Mon Sep 17 00:00:00 2001 From: Asmod4n Date: Sun, 4 Jan 2015 13:00:50 +0100 Subject: [PATCH 018/122] Net::HTTP cannot handle IPv6 addresses in constructor --- lib/webmachine/spec/adapter_lint.rb | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/lib/webmachine/spec/adapter_lint.rb b/lib/webmachine/spec/adapter_lint.rb index b2f85e73..9c8f9d81 100644 --- a/lib/webmachine/spec/adapter_lint.rb +++ b/lib/webmachine/spec/adapter_lint.rb @@ -1,5 +1,6 @@ require "webmachine/spec/test_resource" require "net/http" +require 'ipaddr' shared_examples_for :adapter_lint do attr_accessor :client @@ -53,20 +54,16 @@ expect(response.body).to eq("http://#{address}:#{port}/test") end - context do - let(:address) { "::1" } + # context do + # let(:address) { "::1" } - it "provides the IPv6 request URI" do - if RUBY_VERSION =~ /^2\.(0|1|2)\./ - skip "Net::HTTP regression in Ruby 2.(0|1|2)" - end - - request = Net::HTTP::Get.new("/test") - request["Accept"] = "test/response.request_uri" - response = client.request(request) - expect(response.body).to eq("http://[#{address}]:#{port}/test") - end - end + # it "provides the IPv6 request URI" do + # request = Net::HTTP::Get.new("/test") + # request["Accept"] = "test/response.request_uri" + # response = client.request(request) + # expect(response.body).to eq("http://[#{address}]:#{port}/test") + # end + # end it "provides a string-like request body" do request = Net::HTTP::Put.new("/test") From 9c5b494497c74b10d984751370f92deb8518b08c Mon Sep 17 00:00:00 2001 From: Asmod4n Date: Sun, 4 Jan 2015 13:13:58 +0100 Subject: [PATCH 019/122] rbx fixups? --- lib/webmachine/request.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/webmachine/request.rb b/lib/webmachine/request.rb index 1d98ffb5..e170285b 100644 --- a/lib/webmachine/request.rb +++ b/lib/webmachine/request.rb @@ -2,6 +2,7 @@ require 'forwardable' require 'webmachine/constants' require 'ipaddr' +require 'socket' module Webmachine # Request represents a single HTTP request sent from a client. It From 01a1b200bbfa3a7ae5fe8f6104da002656c0e8cc Mon Sep 17 00:00:00 2001 From: Asmod4n Date: Sun, 4 Jan 2015 13:32:02 +0100 Subject: [PATCH 020/122] rbx doesn't have Addrinfo --- lib/webmachine/request.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/webmachine/request.rb b/lib/webmachine/request.rb index e170285b..65371421 100644 --- a/lib/webmachine/request.rb +++ b/lib/webmachine/request.rb @@ -2,7 +2,6 @@ require 'forwardable' require 'webmachine/constants' require 'ipaddr' -require 'socket' module Webmachine # Request represents a single HTTP request sent from a client. It @@ -185,7 +184,7 @@ def parse_addr(string) end # Pass address, port to Addrinfo.tcp. It will raise SocketError if address or port is not valid. - Addrinfo.tcp(address, port) + [IPAddr.new(address).to_s, port.to_i] end def build_uri(uri, headers) @@ -194,11 +193,11 @@ def build_uri(uri, headers) return uri end - addr = parse_addr(headers.fetch(HOST)) + addr, port = parse_addr(headers.fetch(HOST)) uri.scheme = HTTP - uri.host = addr.ip_address - uri.port = addr.ip_port == 0 ? 80 : addr.ip_port + uri.host = addr + uri.port = port == 0 ? 80 : port uri end From 57e408cb2fa975b20aa14f766f74e774118d6ed1 Mon Sep 17 00:00:00 2001 From: Asmod4n Date: Sun, 4 Jan 2015 14:43:49 +0100 Subject: [PATCH 021/122] validate dns names too --- lib/webmachine/request.rb | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/lib/webmachine/request.rb b/lib/webmachine/request.rb index 65371421..95df50dd 100644 --- a/lib/webmachine/request.rb +++ b/lib/webmachine/request.rb @@ -34,11 +34,11 @@ def method_missing(m, *args, &block) if m =~ HTTP_HEADERS_MATCH # Access headers more easily as underscored methods. header_name = m.to_s.tr(UNDERSCORE, DASH) - if (header_value = headers[header_name]) + if (header_value = @headers[header_name]) # Make future lookups faster. self.class.class_eval <<-RUBY, __FILE__, __LINE__ def #{m} - headers["#{header_name}"] + @headers["#{header_name}"] end RUBY end @@ -167,39 +167,33 @@ def options? private IPV6_MATCH = /\A\[(?
.* )\]:(? \d+ )\z/x.freeze # string like "[::1]:80" - IPV4_MATCH = /\A(?
[^:]+ ):(? \d+ )\z/x.freeze # string like "127.0.0.1:80" + HOST_MATCH = /\A(? [^:]+ ):(? \d+ )\z/x.freeze # string like "www.example.com:80" - def parse_addr(string) + def parse_host(uri, host_string) # Split host and port number from string. - case string + case host_string when IPV6_MATCH - address = $~[:address] - port = $~[:port] - when IPV4_MATCH - address = $~[:address] - port = $~[:port] + uri.host = IPAddr.new($~[:address]).to_s + uri.port = $~[:port].to_i + when HOST_MATCH + uri.host = $~[:host] + uri.port = $~[:port].to_i else # string with no port number - address = string - port = nil + uri.host = host_string end - # Pass address, port to Addrinfo.tcp. It will raise SocketError if address or port is not valid. - [IPAddr.new(address).to_s, port.to_i] + uri end def build_uri(uri, headers) uri = URI(uri) + uri.port ||= 80 + uri.scheme ||= HTTP if uri.host return uri end - addr, port = parse_addr(headers.fetch(HOST)) - - uri.scheme = HTTP - uri.host = addr - uri.port = port == 0 ? 80 : port - - uri + parse_host(uri, headers.fetch(HOST)) end end # class Request From 8e873715aa38e9dc2a8086848fd31b5e71ff5ed8 Mon Sep 17 00:00:00 2001 From: Asmod4n Date: Sun, 4 Jan 2015 14:56:15 +0100 Subject: [PATCH 022/122] try rack_req.url --- lib/webmachine/adapters/rack.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/webmachine/adapters/rack.rb b/lib/webmachine/adapters/rack.rb index c1eccb72..ca91a265 100644 --- a/lib/webmachine/adapters/rack.rb +++ b/lib/webmachine/adapters/rack.rb @@ -60,7 +60,7 @@ def call(env) rack_req = ::Rack::Request.new env request = Webmachine::Request.new(rack_req.request_method, - env[REQUEST_URI], + rack_req.url, headers, RequestBody.new(rack_req)) From 8b30af5318f59715f48d6d299bb59e2e01c6aaa8 Mon Sep 17 00:00:00 2001 From: Asmod4n Date: Sun, 4 Jan 2015 15:55:20 +0100 Subject: [PATCH 023/122] only accept IPv6 addresses when IPV6_MATCH matches --- lib/webmachine/request.rb | 2 +- lib/webmachine/spec/adapter_lint.rb | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/webmachine/request.rb b/lib/webmachine/request.rb index 95df50dd..78566a93 100644 --- a/lib/webmachine/request.rb +++ b/lib/webmachine/request.rb @@ -173,7 +173,7 @@ def parse_host(uri, host_string) # Split host and port number from string. case host_string when IPV6_MATCH - uri.host = IPAddr.new($~[:address]).to_s + uri.host = IPAddr.new($~[:address], Socket::AF_INET6).to_s uri.port = $~[:port].to_i when HOST_MATCH uri.host = $~[:host] diff --git a/lib/webmachine/spec/adapter_lint.rb b/lib/webmachine/spec/adapter_lint.rb index 9c8f9d81..61af0016 100644 --- a/lib/webmachine/spec/adapter_lint.rb +++ b/lib/webmachine/spec/adapter_lint.rb @@ -1,6 +1,5 @@ require "webmachine/spec/test_resource" require "net/http" -require 'ipaddr' shared_examples_for :adapter_lint do attr_accessor :client From ff9ec27c41c478cbb27c052d8da44cca207be9f2 Mon Sep 17 00:00:00 2001 From: Sean Cribbs Date: Sun, 4 Jan 2015 12:46:36 -0600 Subject: [PATCH 024/122] Updated CHANGELOG for 1.3.0 and commits beyond the release. --- CHANGELOG.md | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f0565a2..ee19df96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,34 @@ ### HEAD -* decode the value of the header 'Content-MD5' as base64-encoded string. +* Fixed URI construction, including handling IPv6 addresses, when the + adapter did not supply a complete hostname. + +### 1.3.0 January 3, 2015 + +1.3.0 is a feature and bugfix release that removes two adapters, +reduces memory usage, fixes bugs, and includes a bunch of new +documentation. Thank you to our new contributor @rpag! + +* Greatly reduced per-request garbage by freezing commonly used + Strings and Regexps into constants. +* Tutorial/example documentation was extracted from the README and + extended in the `documentation` directory. +* HTTPkit adapter was added. +* Hatetepe and Mongrel adapters were removed and adapters no longer + install interrupt handlers. +* The "splat" matcher in path specifications is now a Symbol `:*` + rather than a String `"*"`. Using the String version will result in + a deprecation warning. +* Requests with If-None-Match where the resource does not supply an + ETag will no longer respond with 412 or 500, but follow the success + path. +* Path fragments are now decoded. +* Simplified the interaction between the decision FSM and tracing. +* Updated specs to use RSpec 3. +* Improved handling of IO.copy_stream on Rack servers. +* Updated the Reel adapter. +* Exposed Application instance to the Adapter. +* Decode the value of the header 'Content-MD5' as base64-encoded string. ### 1.2.2 January 8, 2014 From cd1ee81646c15ede89b6849d05afc2b401d6b7f3 Mon Sep 17 00:00:00 2001 From: Beth Date: Mon, 5 Jan 2015 07:47:09 +1100 Subject: [PATCH 025/122] Added test for Rack adapter using Rack::Test to ensure we do not depend on non-Rack env vars. --- Gemfile | 1 + spec/webmachine/adapters/rack_spec.rb | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/Gemfile b/Gemfile index a966da12..a85835c6 100644 --- a/Gemfile +++ b/Gemfile @@ -11,6 +11,7 @@ group :test do gem "rspec", '~> 3.0.0' gem "rspec-its" gem "rack" + gem "rack-test" end group :webservers do diff --git a/spec/webmachine/adapters/rack_spec.rb b/spec/webmachine/adapters/rack_spec.rb index 0725b12a..3cc72399 100644 --- a/spec/webmachine/adapters/rack_spec.rb +++ b/spec/webmachine/adapters/rack_spec.rb @@ -2,6 +2,7 @@ require 'webmachine/adapters/rack' require 'spec_helper' require 'webmachine/spec/adapter_lint' +require 'rack/test' describe Webmachine::Adapters::Rack do it_should_behave_like :adapter_lint do @@ -34,3 +35,23 @@ end end end + +describe Webmachine::Adapters::Rack do + let(:app) do + Webmachine::Application.new.tap do |app| + app.add_route(["test"], Test::Resource) + app.configure do | config | + config.adapter = :Rack + end + end.adapter + end + + context "using Rack::Test" do + include Rack::Test::Methods + + it "provides the full request URI" do + rack_response = get "test", nil, {"HTTP_ACCEPT" => "test/response.request_uri"} + expect(rack_response.body).to eq "http://example.org/test" + end + end +end From 27075c2912fcf3eeeccef0bd74c235e3cbe69606 Mon Sep 17 00:00:00 2001 From: Beth Date: Mon, 5 Jan 2015 09:58:09 +1100 Subject: [PATCH 026/122] Do not tap that app. --- spec/webmachine/adapters/rack_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/webmachine/adapters/rack_spec.rb b/spec/webmachine/adapters/rack_spec.rb index 3cc72399..f0e32449 100644 --- a/spec/webmachine/adapters/rack_spec.rb +++ b/spec/webmachine/adapters/rack_spec.rb @@ -38,7 +38,7 @@ describe Webmachine::Adapters::Rack do let(:app) do - Webmachine::Application.new.tap do |app| + Webmachine::Application.new do |app| app.add_route(["test"], Test::Resource) app.configure do | config | config.adapter = :Rack From ce4643c842e9023174b20822cb2982567f20e401 Mon Sep 17 00:00:00 2001 From: Beth Date: Tue, 13 Jan 2015 09:28:59 +1100 Subject: [PATCH 027/122] Added tests for Exception handling. Renamed 'exception' to 'error' where appropriate. --- lib/webmachine/errors.rb | 2 +- lib/webmachine/events.rb | 4 +- lib/webmachine/headers.rb | 2 +- lib/webmachine/resource/callbacks.rb | 6 +-- spec/webmachine/decision/conneg_spec.rb | 2 +- spec/webmachine/decision/flow_spec.rb | 2 +- spec/webmachine/decision/fsm_spec.rb | 63 +++++++++++++++++++++---- 7 files changed, 64 insertions(+), 17 deletions(-) diff --git a/lib/webmachine/errors.rb b/lib/webmachine/errors.rb index e25ac53f..68633b82 100644 --- a/lib/webmachine/errors.rb +++ b/lib/webmachine/errors.rb @@ -39,6 +39,6 @@ class InvalidResource < Error; end # Raised when the client has submitted an invalid request, e.g. in # the case where a request header is improperly formed. Raising this - # exception will result in a 400 response. + # error will result in a 400 response. class MalformedRequest < Error; end end # module Webmachine diff --git a/lib/webmachine/events.rb b/lib/webmachine/events.rb index 1fe73d96..5040bcdc 100644 --- a/lib/webmachine/events.rb +++ b/lib/webmachine/events.rb @@ -55,9 +55,9 @@ def publish(name, *args) # and publish it. Notice that events get sent even if an error occurs # in the passed-in block. # - # If an exception happens during an instrumentation the payload will + # If an error happens during an instrumentation the payload will # have a key `:exception` with an array of two elements as value: - # a string with the name of the exception class, and the exception + # a string with the name of the error class, and the error # message. (when using the default # [AS::Notifications](http://rubydoc.info/gems/as-notifications/AS/Notifications) # backend) diff --git a/lib/webmachine/headers.rb b/lib/webmachine/headers.rb index 031d4783..44954166 100644 --- a/lib/webmachine/headers.rb +++ b/lib/webmachine/headers.rb @@ -48,7 +48,7 @@ def []=(key,value) # Returns the value for the given key. If the key can't be found, # there are several options: - # With no other arguments, it will raise a KeyError exception; + # With no other arguments, it will raise a KeyError error; # if default is given, then that will be returned; # if the optional code block is specified, then that will be run and its # result returned. diff --git a/lib/webmachine/resource/callbacks.rb b/lib/webmachine/resource/callbacks.rb index 596aa215..57bcdb9a 100644 --- a/lib/webmachine/resource/callbacks.rb +++ b/lib/webmachine/resource/callbacks.rb @@ -363,11 +363,11 @@ def generate_etag def finish_request; end # - # This method is called when an exception is raised within a subclass of + # This method is called when an error is raised within a subclass of # {Webmachine::Resource}. # - # @param [Exception] e - # The exception. + # @param [StandardError] e + # The error. # # @return [void] # diff --git a/spec/webmachine/decision/conneg_spec.rb b/spec/webmachine/decision/conneg_spec.rb index c3f8ef42..af2d5255 100644 --- a/spec/webmachine/decision/conneg_spec.rb +++ b/spec/webmachine/decision/conneg_spec.rb @@ -41,7 +41,7 @@ end - it "should raise an exception when a media-type is improperly formatted" do + it "should raise an error when a media-type is improperly formatted" do expect { subject.choose_media_type(["text/html", "application/xml"], "bah;") diff --git a/spec/webmachine/decision/flow_spec.rb b/spec/webmachine/decision/flow_spec.rb index 60bdb4e0..80a53369 100644 --- a/spec/webmachine/decision/flow_spec.rb +++ b/spec/webmachine/decision/flow_spec.rb @@ -1100,7 +1100,7 @@ def accept_all end end - describe "On exception" do + describe "On error" do context "handle_exception is inherited." do let :resource do resource_with do diff --git a/spec/webmachine/decision/fsm_spec.rb b/spec/webmachine/decision/fsm_spec.rb index adb27ebe..09491f47 100644 --- a/spec/webmachine/decision/fsm_spec.rb +++ b/spec/webmachine/decision/fsm_spec.rb @@ -5,15 +5,44 @@ subject { described_class.new(resource, request, response) } + let(:run_with_exception) do + begin + subject.run + rescue Exception + end + end + describe 'handling of exceptions from decision methods' do - let(:exception) { RuntimeError.new } + let(:exception) { Exception.new } before do allow(subject).to receive(Webmachine::Decision::Flow::START) { raise exception } end + it 'does not handle the exception' do + expect { subject.run }.to raise_error exception + end + + it 'does not call resource.handle_exception' do + expect(resource).to_not receive(:handle_exception) + run_with_exception + end + + it 'does not call resource.finish_request' do + expect(resource).to_not receive(:finish_request) + run_with_exception + end + end + + describe 'handling of errors from decision methods' do + let(:error) { RuntimeError.new } + + before do + allow(subject).to receive(Webmachine::Decision::Flow::START) { raise error } + end + it 'calls resource.handle_exception' do - expect(resource).to receive(:handle_exception).with(exception) + expect(resource).to receive(:handle_exception).with(error) subject.run end @@ -23,12 +52,12 @@ end end - describe 'handling of exceptions from resource.handle_exception' do - let(:exception) { RuntimeError.new('an error message') } + describe 'handling of errors from resource.handle_exception' do + let(:error) { RuntimeError.new('an error message') } before do allow(subject).to receive(Webmachine::Decision::Flow::START) { raise } - allow(resource).to receive(:handle_exception) { raise exception } + allow(resource).to receive(:handle_exception) { raise error } end it 'does not call resource.handle_exception again' do @@ -44,20 +73,38 @@ it 'renders an error' do expect(Webmachine). to receive(:render_error). - with(500, request, response, { :message => exception.message }) + with(500, request, response, { :message => error.message }) subject.run end end describe 'handling of exceptions from resource.finish_request' do - let(:exception) { RuntimeError.new } + let(:exception) { Exception.new } before do allow(resource).to receive(:finish_request) { raise exception } end + it 'does not call resource.handle_exception' do + expect(resource).to_not receive(:handle_exception) + run_with_exception + end + + it 'does not call resource.finish_request again' do + expect(resource).to_not receive(:finish_request).once { raise } + run_with_exception + end + end + + describe 'handling of errors from resource.finish_request' do + let(:error) { RuntimeError.new } + + before do + allow(resource).to receive(:finish_request) { raise error } + end + it 'calls resource.handle_exception' do - expect(resource).to receive(:handle_exception).with(exception) + expect(resource).to receive(:handle_exception).with(error) subject.run end From a54c36760f105322292f76416f9d989d3f7b92e7 Mon Sep 17 00:00:00 2001 From: Beth Date: Thu, 15 Jan 2015 16:59:03 +1100 Subject: [PATCH 028/122] Version 1.3.1 Signed-off-by: Beth --- CHANGELOG.md | 5 +++++ lib/webmachine/version.rb | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee19df96..43a0a463 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,12 @@ ### HEAD +### 1.3.1 January 15, 2015 + * Fixed URI construction, including handling IPv6 addresses, when the adapter did not supply a complete hostname. +* Removed dependency of Rack Adapter on REQUEST_INFO rack environment + variable which was not always present. +* Use IPAddr instead of Addrinfo as rbx does not support Addrinfo. ### 1.3.0 January 3, 2015 diff --git a/lib/webmachine/version.rb b/lib/webmachine/version.rb index 752683a8..8e3b8c12 100644 --- a/lib/webmachine/version.rb +++ b/lib/webmachine/version.rb @@ -1,6 +1,6 @@ module Webmachine # Library version - VERSION = "1.3.0".freeze + VERSION = "1.3.1".freeze # String for use in "Server" HTTP response header, which includes # the {VERSION}. From 50f84c56af89785ce7e43d958d8ebd4cde7c6c86 Mon Sep 17 00:00:00 2001 From: Beth Date: Thu, 15 Jan 2015 19:05:41 +1100 Subject: [PATCH 029/122] Updated Travis CI snippet. Badge in README is showing red even though build is green (failing with some tests ignored) in Travis. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eefa9946..dad53a24 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# webmachine for Ruby [![travis](https://travis-ci.org/seancribbs/webmachine-ruby.png?branch=master)](http://travis-ci.org/seancribbs/webmachine-ruby) +# webmachine for Ruby [![Build Status](https://travis-ci.org/seancribbs/webmachine-ruby.svg)](https://travis-ci.org/seancribbs/webmachine-ruby) webmachine-ruby is a port of [Webmachine](https://github.com/basho/webmachine), which is written in From fcf27c9c118c6689fac6f07ebd2beb6592386446 Mon Sep 17 00:00:00 2001 From: Beth Date: Thu, 15 Jan 2015 19:24:37 +1100 Subject: [PATCH 030/122] Whitespace change to kick Travis off again. --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index bdc53161..da6e7dd4 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,3 @@ Gemfile.lock .SyncID .SyncIgnore vendor - From 7e9cd6aa456890d35819f2f153b33418d67c21c2 Mon Sep 17 00:00:00 2001 From: Julian Doherty Date: Sat, 7 Mar 2015 23:44:44 +1100 Subject: [PATCH 031/122] Store routing tokens on request. Use them for routing match tests This introduces a `routing_tokens` attribute on `Webmachine::Request`, and uses it to lazily instantiate the tokens used by `Webmachine::Dispatcher::Route#match?`. This is to allow requests to optionally override the tokens generated by splitting the uri path. This is useful if webmachine isn't hosted at the root path of the uri (as when rack map is used). This SHOULD also give a performance increase for request routing, as previously the uri was matched against a regex for every routing test, and then again when the route was applied after it matched. With this approach, the regex is run on the uri once only and then memomized in the request. (note - SHOULD be faster... haven't actually benchmarked it) --- lib/webmachine/dispatcher/route.rb | 8 +++----- lib/webmachine/request.rb | 7 +++++++ spec/webmachine/dispatcher/route_spec.rb | 19 ++++++++++++++++++- spec/webmachine/request_spec.rb | 19 +++++++++++++++++++ 4 files changed, 47 insertions(+), 6 deletions(-) diff --git a/lib/webmachine/dispatcher/route.rb b/lib/webmachine/dispatcher/route.rb index dae0c60e..08fbd762 100644 --- a/lib/webmachine/dispatcher/route.rb +++ b/lib/webmachine/dispatcher/route.rb @@ -79,13 +79,11 @@ def initialize(path_spec, *args) raise ArgumentError, t('not_resource_class', :class => resource.name) unless resource < Resource end - PATH_MATCH = /^\/(.*)/.freeze - # Determines whether the given request matches this route and # should be dispatched to the {#resource}. # @param [Reqeust] request the request object def match?(request) - tokens = request.uri.path.match(PATH_MATCH)[1].split(SLASH) + tokens = request.routing_tokens bind(tokens, {}) && guards.all? { |guard| guard.call(request) } end @@ -93,9 +91,9 @@ def match?(request) # route, including path bindings. # @param [Request] request the request object def apply(request) - request.disp_path = request.uri.path.match(PATH_MATCH)[1] + request.disp_path = request.routing_tokens.join(SLASH) request.path_info = @bindings.dup - tokens = request.disp_path.split(SLASH) + tokens = request.routing_tokens depth, trailing = bind(tokens, request.path_info) request.path_tokens = trailing || [] end diff --git a/lib/webmachine/request.rb b/lib/webmachine/request.rb index 78566a93..44633417 100644 --- a/lib/webmachine/request.rb +++ b/lib/webmachine/request.rb @@ -13,6 +13,7 @@ class Request attr_reader :method, :uri, :headers, :body attr_accessor :disp_path, :path_info, :path_tokens + attr_writer :routing_tokens # @param [String] method the HTTP request method # @param [URI] uri the requested URI, including host, scheme and @@ -164,6 +165,12 @@ def options? method == OPTIONS_METHOD end + ROUTING_PATH_MATCH = /^\/(.*)/.freeze + + def routing_tokens + @routing_tokens ||= uri.path.match(ROUTING_PATH_MATCH)[1].split(SLASH) + end + private IPV6_MATCH = /\A\[(?
.* )\]:(? \d+ )\z/x.freeze # string like "[::1]:80" diff --git a/spec/webmachine/dispatcher/route_spec.rb b/spec/webmachine/dispatcher/route_spec.rb index c5cdbb77..56d50fbc 100644 --- a/spec/webmachine/dispatcher/route_spec.rb +++ b/spec/webmachine/dispatcher/route_spec.rb @@ -30,7 +30,13 @@ def warn(*msgs); end # silence warnings for tests matcher :match_route do |*expected| route = Webmachine::Dispatcher::Route.new(expected[0], Class.new(Webmachine::Resource), expected[1] || {}) match do |actual| - request.uri.path = actual if String === actual + case actual + when String + request.uri.path = actual if String === actual + when Array + request.uri.path = "/some/route/" + actual.join("/") + request.routing_tokens = actual + end route.match?(request) end @@ -124,6 +130,17 @@ def call(request) end end end + + context "with a request with explicitly specified routing tokens" do + subject { ["foo", "bar"] } + it { is_expected.to match_route(["foo", "bar"]) } + it { is_expected.to match_route(["foo", :id]) } + it { is_expected.to match_route ['*'] } + it { is_expected.to match_route [:*] } + it { is_expected.not_to match_route(["some", "route", "foo", "bar"]) } + it { is_expected.not_to match_route %w{foo} } + it { is_expected.not_to match_route [:id] } + end end context "applying bindings" do diff --git a/spec/webmachine/request_spec.rb b/spec/webmachine/request_spec.rb index ff08b344..232499b6 100644 --- a/spec/webmachine/request_spec.rb +++ b/spec/webmachine/request_spec.rb @@ -239,4 +239,23 @@ def body; block_given? ? yield(@body) : @body; end end end + describe '#routing_tokens' do + subject { request.routing_tokens } + + context "haven't be explicitly set" do + it "extracts the routing tokens from the path portion of the uri" do + expect(subject).to eq(["some", "resource"]) + end + end + + context "have been explicitly set" do + before { request.routing_tokens = ["foo", "bar"] } + + it "uses the specified routing_tokens" do + expect(subject).to eq(["foo", "bar"]) + end + end + + end + end From 7f7b54670891f632a3a19eb6954960c863f4268a Mon Sep 17 00:00:00 2001 From: Julian Doherty Date: Sun, 8 Mar 2015 00:17:02 +1100 Subject: [PATCH 032/122] add RackMapped adapter that correctly handles routing when hosted from a rack mapped URI `Webmachine::Adapters::RackMapped` is implemented as a subclass of `Webmachine::Adapters::Rack`, and simply overrides the way the `Webmachine::Request` is built to explicitly set the `routing_tokens` from the rack request `PATH_INFO` string - rather than from the full uri path string as the base rack adapter does. Rack provides the path that the app should use in the `PATH_INFO` env var. This is the correct value to use for routing etc to work with mapped apps. Note, this was done as a separate class as suggested by @bethesque to preserve backward compatibility. If any webmachine apps are running as mapped rack apps already, they may have gotten around not being able to host the app on a mapped path by specifying the full URI path in the routing config - which would no longer work if this change was made on the base rack adapter. --- lib/webmachine/adapters/rack.rb | 24 +++++++++++++++---- spec/webmachine/adapters/rack_spec.rb | 34 +++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/lib/webmachine/adapters/rack.rb b/lib/webmachine/adapters/rack.rb index ca91a265..ccbf2eef 100644 --- a/lib/webmachine/adapters/rack.rb +++ b/lib/webmachine/adapters/rack.rb @@ -59,10 +59,7 @@ def call(env) headers = Webmachine::Headers.from_cgi(env) rack_req = ::Rack::Request.new env - request = Webmachine::Request.new(rack_req.request_method, - rack_req.url, - headers, - RequestBody.new(rack_req)) + request = build_webmachine_request(rack_req, headers) response = Webmachine::Response.new application.dispatcher.dispatch(request, response) @@ -95,6 +92,14 @@ def call(env) rack_res.finish end + private + def build_webmachine_request(rack_req, headers) + Webmachine::Request.new(rack_req.request_method, + rack_req.url, + headers, + RequestBody.new(rack_req)) + end + class RackResponse ONE_FIVE = '1.5'.freeze @@ -167,5 +172,16 @@ def each end # class RequestBody end # class Rack + class RackMapped < Rack + def build_webmachine_request(rack_req, headers) + request = super + routing_match = rack_req.path_info.match(Webmachine::Request::ROUTING_PATH_MATCH) + routing_path = routing_match ? routing_match[1] : "" + routing_tokens = routing_path.split(SLASH) + request.routing_tokens = routing_tokens + request + end + end + end # module Adapters end # module Webmachine diff --git a/spec/webmachine/adapters/rack_spec.rb b/spec/webmachine/adapters/rack_spec.rb index f0e32449..b7d0f76f 100644 --- a/spec/webmachine/adapters/rack_spec.rb +++ b/spec/webmachine/adapters/rack_spec.rb @@ -14,6 +14,16 @@ end end +describe Webmachine::Adapters::RackMapped do + it_should_behave_like :adapter_lint do + it "should set Server header" do + response = client.request(Net::HTTP::Get.new("/test")) + expect(response["Server"]).to match(/Webmachine/) + expect(response["Server"]).to match(/Rack/) + end + end +end + describe Webmachine::Adapters::Rack::RackResponse do context "on Rack < 1.5 release" do before { allow(Rack).to receive_messages(:release => "1.4") } @@ -55,3 +65,27 @@ end end end + +describe Webmachine::Adapters::RackMapped do + let(:app) do + Rack::Builder.new do + map '/some/route' do + run(Webmachine::Application.new do |app| + app.add_route(["test"], Test::Resource) + app.configure do | config | + config.adapter = :RackMapped + end + end.adapter) + end + end + end + + context "using Rack::Test" do + include Rack::Test::Methods + + it "provides the full request URI" do + rack_response = get "some/route/test", nil, {"HTTP_ACCEPT" => "test/response.request_uri"} + expect(rack_response.body).to eq "http://example.org/some/route/test" + end + end +end From 4a1d99a6d5f625ca16755d10d77de61e95aaace9 Mon Sep 17 00:00:00 2001 From: Julian Doherty Date: Tue, 10 Mar 2015 09:12:15 +1100 Subject: [PATCH 033/122] refactor request so routing_tokens are immutable and passed to constructor as suggested by @bethesque at https://github.com/seancribbs/webmachine-ruby/pull/223/files#r25999998 --- lib/webmachine/adapters/rack.rb | 15 ++++++++------ lib/webmachine/request.rb | 10 +++------- spec/webmachine/dispatcher/route_spec.rb | 25 +++++++++++------------- spec/webmachine/request_spec.rb | 16 ++++++++------- 4 files changed, 32 insertions(+), 34 deletions(-) diff --git a/lib/webmachine/adapters/rack.rb b/lib/webmachine/adapters/rack.rb index ccbf2eef..30624517 100644 --- a/lib/webmachine/adapters/rack.rb +++ b/lib/webmachine/adapters/rack.rb @@ -97,7 +97,13 @@ def build_webmachine_request(rack_req, headers) Webmachine::Request.new(rack_req.request_method, rack_req.url, headers, - RequestBody.new(rack_req)) + RequestBody.new(rack_req), + routing_tokens(rack_req) + ) + end + + def routing_tokens(rack_req) + nil # no-op for default, un-mapped rack adapter end class RackResponse @@ -173,13 +179,10 @@ def each end # class Rack class RackMapped < Rack - def build_webmachine_request(rack_req, headers) - request = super + def routing_tokens(rack_req) routing_match = rack_req.path_info.match(Webmachine::Request::ROUTING_PATH_MATCH) routing_path = routing_match ? routing_match[1] : "" - routing_tokens = routing_path.split(SLASH) - request.routing_tokens = routing_tokens - request + routing_path.split(SLASH) end end diff --git a/lib/webmachine/request.rb b/lib/webmachine/request.rb index 44633417..892c05e6 100644 --- a/lib/webmachine/request.rb +++ b/lib/webmachine/request.rb @@ -11,9 +11,8 @@ class Request extend Forwardable - attr_reader :method, :uri, :headers, :body + attr_reader :method, :uri, :headers, :body, :routing_tokens attr_accessor :disp_path, :path_info, :path_tokens - attr_writer :routing_tokens # @param [String] method the HTTP request method # @param [URI] uri the requested URI, including host, scheme and @@ -21,9 +20,10 @@ class Request # @param [Headers] headers the HTTP request headers # @param [String,#to_s,#each,nil] body the entity included in the # request, if present - def initialize(method, uri, headers, body) + def initialize(method, uri, headers, body, routing_tokens=nil) @method, @headers, @body = method, headers, body @uri = build_uri(uri, headers) + @routing_tokens = routing_tokens || @uri.path.match(ROUTING_PATH_MATCH)[1].split(SLASH) end def_delegators :headers, :[] @@ -167,10 +167,6 @@ def options? ROUTING_PATH_MATCH = /^\/(.*)/.freeze - def routing_tokens - @routing_tokens ||= uri.path.match(ROUTING_PATH_MATCH)[1].split(SLASH) - end - private IPV6_MATCH = /\A\[(?
.* )\]:(? \d+ )\z/x.freeze # string like "[::1]:80" diff --git a/spec/webmachine/dispatcher/route_spec.rb b/spec/webmachine/dispatcher/route_spec.rb index 56d50fbc..c97f56dc 100644 --- a/spec/webmachine/dispatcher/route_spec.rb +++ b/spec/webmachine/dispatcher/route_spec.rb @@ -7,7 +7,8 @@ def warn(*msgs); end # silence warnings for tests describe Webmachine::Dispatcher::Route do let(:method) { "GET" } let(:uri) { URI.parse("http://localhost:8080/") } - let(:request){ Webmachine::Request.new(method, uri, Webmachine::Headers.new, "") } + let(:routing_tokens) { nil } + let(:request){ Webmachine::Request.new(method, uri, Webmachine::Headers.new, "", routing_tokens) } let(:resource){ Class.new(Webmachine::Resource) } describe '#apply' do @@ -16,9 +17,7 @@ def warn(*msgs); end # silence warnings for tests } describe 'a path_info fragment' do - before do - uri.path = '/hello/planet%20earth%20++' - end + let(:uri) { URI.parse("http://localhost:8080/hello/planet%20earth%20++") } it 'should decode the value' do route.apply(request) @@ -30,14 +29,10 @@ def warn(*msgs); end # silence warnings for tests matcher :match_route do |*expected| route = Webmachine::Dispatcher::Route.new(expected[0], Class.new(Webmachine::Resource), expected[1] || {}) match do |actual| - case actual - when String - request.uri.path = actual if String === actual - when Array - request.uri.path = "/some/route/" + actual.join("/") - request.routing_tokens = actual - end - route.match?(request) + uri = URI.parse("http://localhost:8080") + uri.path = actual + req = Webmachine::Request.new("GET", uri, Webmachine::Headers.new, "", routing_tokens) + route.match?(req) end failure_message do |_| @@ -132,7 +127,8 @@ def call(request) end context "with a request with explicitly specified routing tokens" do - subject { ["foo", "bar"] } + subject { "/some/route/foo/bar" } + let(:routing_tokens) { ["foo", "bar"] } it { is_expected.to match_route(["foo", "bar"]) } it { is_expected.to match_route(["foo", :id]) } it { is_expected.to match_route ['*'] } @@ -187,7 +183,8 @@ def call(request) context "on a deep path" do subject { described_class.new(%w{foo bar baz}, resource) } - before { request.uri.path = "/foo/bar/baz"; subject.apply(request) } + let(:uri) { URI.parse("http://localhost:8080/foo/bar/baz") } + before { subject.apply(request) } it "should assign the dispatched path as the path past the initial slash" do expect(request.disp_path).to eq("foo/bar/baz") diff --git a/spec/webmachine/request_spec.rb b/spec/webmachine/request_spec.rb index 232499b6..6d61666f 100644 --- a/spec/webmachine/request_spec.rb +++ b/spec/webmachine/request_spec.rb @@ -3,11 +3,12 @@ describe Webmachine::Request do subject { request } - let(:uri) { URI.parse("http://localhost:8080/some/resource") } - let(:http_method) { "GET" } - let(:headers) { Webmachine::Headers.new } - let(:body) { "" } - let(:request) { Webmachine::Request.new(http_method, uri, headers, body) } + let(:uri) { URI.parse("http://localhost:8080/some/resource") } + let(:http_method) { "GET" } + let(:headers) { Webmachine::Headers.new } + let(:body) { "" } + let(:routing_tokens) { nil } + let(:request) { Webmachine::Request.new(http_method, uri, headers, body, routing_tokens) } it "should provide access to the headers via brackets" do subject.headers['Accept'] = "*/*" @@ -242,14 +243,15 @@ def body; block_given? ? yield(@body) : @body; end describe '#routing_tokens' do subject { request.routing_tokens } - context "haven't be explicitly set" do + context "haven't been explicitly set" do + let(:routing_tokens) { nil } it "extracts the routing tokens from the path portion of the uri" do expect(subject).to eq(["some", "resource"]) end end context "have been explicitly set" do - before { request.routing_tokens = ["foo", "bar"] } + let(:routing_tokens) { ["foo", "bar"] } it "uses the specified routing_tokens" do expect(subject).to eq(["foo", "bar"]) From 7e0c4dce2f74c0b6622c2da316464c132b0c2669 Mon Sep 17 00:00:00 2001 From: Julian Doherty Date: Tue, 10 Mar 2015 15:29:53 +1100 Subject: [PATCH 034/122] make routing_tokens protected rather than private --- lib/webmachine/adapters/rack.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/webmachine/adapters/rack.rb b/lib/webmachine/adapters/rack.rb index 30624517..55b2b8e4 100644 --- a/lib/webmachine/adapters/rack.rb +++ b/lib/webmachine/adapters/rack.rb @@ -92,6 +92,11 @@ def call(env) rack_res.finish end + protected + def routing_tokens(rack_req) + nil # no-op for default, un-mapped rack adapter + end + private def build_webmachine_request(rack_req, headers) Webmachine::Request.new(rack_req.request_method, @@ -102,10 +107,6 @@ def build_webmachine_request(rack_req, headers) ) end - def routing_tokens(rack_req) - nil # no-op for default, un-mapped rack adapter - end - class RackResponse ONE_FIVE = '1.5'.freeze @@ -179,6 +180,7 @@ def each end # class Rack class RackMapped < Rack + protected def routing_tokens(rack_req) routing_match = rack_req.path_info.match(Webmachine::Request::ROUTING_PATH_MATCH) routing_path = routing_match ? routing_match[1] : "" From c288d08323a1a86734bf69cd4370442bf5858bcf Mon Sep 17 00:00:00 2001 From: Julian Doherty Date: Tue, 10 Mar 2015 16:39:32 +1100 Subject: [PATCH 035/122] added comments around RackMapped --- lib/webmachine/adapters/rack.rb | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/lib/webmachine/adapters/rack.rb b/lib/webmachine/adapters/rack.rb index 55b2b8e4..012728c5 100644 --- a/lib/webmachine/adapters/rack.rb +++ b/lib/webmachine/adapters/rack.rb @@ -12,9 +12,12 @@ module Adapters # A minimal "shim" adapter to allow Webmachine to interface with Rack. The # intention here is to allow Webmachine to run under Rack-compatible # web-servers, like unicorn and pow. + # # The adapter expects your Webmachine application to be mounted at the root path - # it will NOT allow you to nest your Webmachine application at an arbitrary path # eg. map "/api" { run MyWebmachineAPI } + # To use map your Webmachine application at an arbitrary path, use the + # `Webmachine::Adapters::RackMapped` subclass instead. # # To use this adapter, create a config.ru file and populate it like so: # @@ -179,6 +182,24 @@ def each end # class RequestBody end # class Rack + # Provides the same functionality as the parent Webmachine::Adapters::Rack + # adapter, but allows the Webmachine application to be hosted at an + # arbitrary path in a parent Rack application (as in Rack `map` or Rails + # routing `mount`) + # + # This functionality is separated out from the parent class to preserve + # backward compatibility in the behaviour of the parent Rack adpater. + # + # To use the adapter in a parent Rack application, map the Webmachine + # application as follows in a rackup file or Rack::Builder: + # + # map '/foo' do + # run SomeotherRackApp + # + # map '/bar' do + # run MyWebmachineApp.adapter + # end + # end class RackMapped < Rack protected def routing_tokens(rack_req) From 1ba23677ef756ff2aa1d44eab094a03fae3144be Mon Sep 17 00:00:00 2001 From: Julian Doherty Date: Wed, 11 Mar 2015 00:24:36 +1100 Subject: [PATCH 036/122] allow `base_uri` to be specified when creating request --- lib/webmachine/request.rb | 4 ++-- spec/webmachine/request_spec.rb | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/webmachine/request.rb b/lib/webmachine/request.rb index 892c05e6..ccd59e53 100644 --- a/lib/webmachine/request.rb +++ b/lib/webmachine/request.rb @@ -20,8 +20,8 @@ class Request # @param [Headers] headers the HTTP request headers # @param [String,#to_s,#each,nil] body the entity included in the # request, if present - def initialize(method, uri, headers, body, routing_tokens=nil) - @method, @headers, @body = method, headers, body + def initialize(method, uri, headers, body, routing_tokens=nil, base_uri=nil) + @method, @headers, @body, @base_uri = method, headers, body, base_uri @uri = build_uri(uri, headers) @routing_tokens = routing_tokens || @uri.path.match(ROUTING_PATH_MATCH)[1].split(SLASH) end diff --git a/spec/webmachine/request_spec.rb b/spec/webmachine/request_spec.rb index 6d61666f..bfcab25c 100644 --- a/spec/webmachine/request_spec.rb +++ b/spec/webmachine/request_spec.rb @@ -8,7 +8,8 @@ let(:headers) { Webmachine::Headers.new } let(:body) { "" } let(:routing_tokens) { nil } - let(:request) { Webmachine::Request.new(http_method, uri, headers, body, routing_tokens) } + let(:base_uri) { nil } + let(:request) { Webmachine::Request.new(http_method, uri, headers, body, routing_tokens, base_uri) } it "should provide access to the headers via brackets" do subject.headers['Accept'] = "*/*" @@ -31,8 +32,17 @@ expect(subject.content_md5).to be_nil end - it "should calculate a base URI" do - expect(subject.base_uri).to eq(URI.parse("http://localhost:8080/")) + context "base_uri" do + it "should calculate a base URI" do + expect(subject.base_uri).to eq(URI.parse("http://localhost:8080/")) + end + + context "when base_uri has been explicitly set" do + let(:base_uri) { URI.parse("http://localhost:8080/some_base_uri/here") } + it "should use the provided base_uri" do + expect(subject.base_uri).to eq(URI.parse("http://localhost:8080/some_base_uri/here")) + end + end end it "should provide a hash of query parameters" do From 33c52f4129c4dd22f6aea8545512589bf5c76239 Mon Sep 17 00:00:00 2001 From: Julian Doherty Date: Wed, 11 Mar 2015 00:25:09 +1100 Subject: [PATCH 037/122] specify explicit base_uri from rack SCRIPT_NAME when creating request for RackMapped --- lib/webmachine/adapters/rack.rb | 15 ++++++++++++- spec/webmachine/adapters/rack_spec.rb | 32 +++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/lib/webmachine/adapters/rack.rb b/lib/webmachine/adapters/rack.rb index 012728c5..a011de44 100644 --- a/lib/webmachine/adapters/rack.rb +++ b/lib/webmachine/adapters/rack.rb @@ -100,13 +100,18 @@ def routing_tokens(rack_req) nil # no-op for default, un-mapped rack adapter end + def base_uri(rack_req) + nil # no-op for default, un-mapped rack adapter + end + private def build_webmachine_request(rack_req, headers) Webmachine::Request.new(rack_req.request_method, rack_req.url, headers, RequestBody.new(rack_req), - routing_tokens(rack_req) + routing_tokens(rack_req), + base_uri(rack_req) ) end @@ -207,6 +212,14 @@ def routing_tokens(rack_req) routing_path = routing_match ? routing_match[1] : "" routing_path.split(SLASH) end + + def base_uri(rack_req) + # rack SCRIPT_NAME env var doesn't end with "/". This causes weird + # behavour when URI.join concatenates URI components in + # Webmachine::Decision::Flow#n11 + script_name = rack_req.script_name + SLASH + URI.join(rack_req.base_url, script_name) + end end end # module Adapters diff --git a/spec/webmachine/adapters/rack_spec.rb b/spec/webmachine/adapters/rack_spec.rb index b7d0f76f..645211a8 100644 --- a/spec/webmachine/adapters/rack_spec.rb +++ b/spec/webmachine/adapters/rack_spec.rb @@ -67,11 +67,38 @@ end describe Webmachine::Adapters::RackMapped do + class CreateResource < Webmachine::Resource + def allowed_methods + ["POST"] + end + + def content_types_accepted + [["application/json", :from_json]] + end + + def content_types_provided + [["application/json", :to_json]] + end + + def post_is_create? + true + end + + def create_path + "created_path_here/123" + end + + def from_json + response.body = %{ {"foo": "bar"} } + end + end + let(:app) do Rack::Builder.new do map '/some/route' do run(Webmachine::Application.new do |app| app.add_route(["test"], Test::Resource) + app.add_route(["create_test"], CreateResource) app.configure do | config | config.adapter = :RackMapped end @@ -87,5 +114,10 @@ rack_response = get "some/route/test", nil, {"HTTP_ACCEPT" => "test/response.request_uri"} expect(rack_response.body).to eq "http://example.org/some/route/test" end + + it "provides LOCATION header using custom base_uri when creating from POST request" do + rack_response = post "/some/route/create_test", %{{"foo": "bar"}}, {"HTTP_ACCEPT" => "application/json", "CONTENT_TYPE" => "application/json"} + expect(rack_response.headers["Location"]).to eq("http://example.org/some/route/created_path_here/123") + end end end From d4c05b54d8e55a1306abea41db5df2728698f3fc Mon Sep 17 00:00:00 2001 From: Julian Doherty Date: Wed, 11 Mar 2015 00:37:32 +1100 Subject: [PATCH 038/122] refactored @base_uri instantiation to have same pattern as @routing_tokens --- lib/webmachine/request.rb | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/lib/webmachine/request.rb b/lib/webmachine/request.rb index ccd59e53..bad4f1f3 100644 --- a/lib/webmachine/request.rb +++ b/lib/webmachine/request.rb @@ -8,10 +8,11 @@ module Webmachine # should be instantiated by {Adapters} when a request is received class Request HTTP_HEADERS_MATCH = /^(?:[a-z0-9])+(?:_[a-z0-9]+)*$/i.freeze + ROUTING_PATH_MATCH = /^\/(.*)/.freeze extend Forwardable - attr_reader :method, :uri, :headers, :body, :routing_tokens + attr_reader :method, :uri, :headers, :body, :routing_tokens, :base_uri attr_accessor :disp_path, :path_info, :path_tokens # @param [String] method the HTTP request method @@ -21,9 +22,13 @@ class Request # @param [String,#to_s,#each,nil] body the entity included in the # request, if present def initialize(method, uri, headers, body, routing_tokens=nil, base_uri=nil) - @method, @headers, @body, @base_uri = method, headers, body, base_uri + @method, @headers, @body = method, headers, body @uri = build_uri(uri, headers) @routing_tokens = routing_tokens || @uri.path.match(ROUTING_PATH_MATCH)[1].split(SLASH) + @base_uri = base_uri || @uri.dup.tap do |u| + u.path = SLASH + u.query = nil + end end def_delegators :headers, :[] @@ -54,16 +59,6 @@ def has_body? !(body.nil? || body.empty?) end - # The root URI for the request, ignoring path and query. This is - # useful for calculating relative paths to resources. - # @return [URI] - def base_uri - @base_uri ||= uri.dup.tap do |u| - u.path = SLASH - u.query = nil - end - end - # Returns a hash of query parameters (they come after the ? in the # URI). Note that this does NOT work in the same way as Rails, # i.e. it does not support nested arrays and hashes. @@ -165,8 +160,6 @@ def options? method == OPTIONS_METHOD end - ROUTING_PATH_MATCH = /^\/(.*)/.freeze - private IPV6_MATCH = /\A\[(?
.* )\]:(? \d+ )\z/x.freeze # string like "[::1]:80" From b929920eb961d86e7fb25e3f74a659bad2736f8c Mon Sep 17 00:00:00 2001 From: Julian Doherty Date: Sun, 15 Mar 2015 23:52:30 +1100 Subject: [PATCH 039/122] updated documentation about rack to mention RackMapped --- documentation/adapters.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/documentation/adapters.md b/documentation/adapters.md index 78b83b57..69b3565a 100644 --- a/documentation/adapters.md +++ b/documentation/adapters.md @@ -10,14 +10,16 @@ run on any webserver that provides a Rack interface. It also lets it run on In order to be compatible with popular deployment stacks, Webmachine has a [Rack](https://github.com/rack/rack) adapter (thanks to Jamis Buck). -Webmachine can be used with Rack middlware features such as Rack::Map and Rack::Cascade as long as: - -1. The Webmachine app is mounted at the root directory. -2. Any requests/responses that are handled by the Webmachine app are not modified by the middleware. The behaviours that are encapsulated in Webmachine assume that no modifications +Webmachine can be used with Rack middlware features such as Rack::Map and Rack::Cascade as long as any requests/responses that are handled by the Webmachine app are **not** modified by the middleware. The behaviours that are encapsulated in Webmachine assume that no modifications are done to requests or response outside of Webmachine. Keep in mind that Webmachine already supports many things that Rack middleware is used for with other HTTP frameworks (eg. etags, specifying supported/preferred Accept and Content-Types). +The base `Webmachine::Adapters::Rack` class assumes the Webmachine application +is mounted at the route path `/` (i.e. not using `Rack::Builder#map` or Rails +`ActionDispatch::Routing::Mapper::Base#mount`). In order to +map to a subpath, use the `Webmachine::Adapters::RackMapped` adapter instead. + For an example of using Webmachine with Rack middleware, see the [Pact Broker][middleware-example]. See the [Rack Adapter API docs][rack-adapter-api-docs] for more information. From 940a0b03f390125ea729cb101c09f8e3b3803b59 Mon Sep 17 00:00:00 2001 From: Beth Date: Fri, 20 Mar 2015 10:12:29 +1100 Subject: [PATCH 040/122] Moved RackMapped class into its own file. --- lib/webmachine/adapters/rack.rb | 36 ---------- lib/webmachine/adapters/rack_mapped.rb | 42 ++++++++++++ spec/webmachine/adapters/rack_mapped_spec.rb | 71 ++++++++++++++++++++ spec/webmachine/adapters/rack_spec.rb | 66 ------------------ 4 files changed, 113 insertions(+), 102 deletions(-) create mode 100644 lib/webmachine/adapters/rack_mapped.rb create mode 100644 spec/webmachine/adapters/rack_mapped_spec.rb diff --git a/lib/webmachine/adapters/rack.rb b/lib/webmachine/adapters/rack.rb index a011de44..54265865 100644 --- a/lib/webmachine/adapters/rack.rb +++ b/lib/webmachine/adapters/rack.rb @@ -186,41 +186,5 @@ def each end end # class RequestBody end # class Rack - - # Provides the same functionality as the parent Webmachine::Adapters::Rack - # adapter, but allows the Webmachine application to be hosted at an - # arbitrary path in a parent Rack application (as in Rack `map` or Rails - # routing `mount`) - # - # This functionality is separated out from the parent class to preserve - # backward compatibility in the behaviour of the parent Rack adpater. - # - # To use the adapter in a parent Rack application, map the Webmachine - # application as follows in a rackup file or Rack::Builder: - # - # map '/foo' do - # run SomeotherRackApp - # - # map '/bar' do - # run MyWebmachineApp.adapter - # end - # end - class RackMapped < Rack - protected - def routing_tokens(rack_req) - routing_match = rack_req.path_info.match(Webmachine::Request::ROUTING_PATH_MATCH) - routing_path = routing_match ? routing_match[1] : "" - routing_path.split(SLASH) - end - - def base_uri(rack_req) - # rack SCRIPT_NAME env var doesn't end with "/". This causes weird - # behavour when URI.join concatenates URI components in - # Webmachine::Decision::Flow#n11 - script_name = rack_req.script_name + SLASH - URI.join(rack_req.base_url, script_name) - end - end - end # module Adapters end # module Webmachine diff --git a/lib/webmachine/adapters/rack_mapped.rb b/lib/webmachine/adapters/rack_mapped.rb new file mode 100644 index 00000000..01b1bd8b --- /dev/null +++ b/lib/webmachine/adapters/rack_mapped.rb @@ -0,0 +1,42 @@ +require 'webmachine/adapters/rack' + +module Webmachine + module Adapters + # Provides the same functionality as the parent Webmachine::Adapters::Rack + # adapter, but allows the Webmachine application to be hosted at an + # arbitrary path in a parent Rack application (as in Rack `map` or Rails + # routing `mount`) + # + # This functionality is separated out from the parent class to preserve + # backward compatibility in the behaviour of the parent Rack adpater. + # + # To use the adapter in a parent Rack application, map the Webmachine + # application as follows in a rackup file or Rack::Builder: + # + # map '/foo' do + # run SomeotherRackApp + # + # map '/bar' do + # run MyWebmachineApp.adapter + # end + # end + class RackMapped < Rack + + protected + + def routing_tokens(rack_req) + routing_match = rack_req.path_info.match(Webmachine::Request::ROUTING_PATH_MATCH) + routing_path = routing_match ? routing_match[1] : "" + routing_path.split(SLASH) + end + + def base_uri(rack_req) + # rack SCRIPT_NAME env var doesn't end with "/". This causes weird + # behavour when URI.join concatenates URI components in + # Webmachine::Decision::Flow#n11 + script_name = rack_req.script_name + SLASH + URI.join(rack_req.base_url, script_name) + end + end # class RackMapped + end # module Adapters +end # module Webmachine diff --git a/spec/webmachine/adapters/rack_mapped_spec.rb b/spec/webmachine/adapters/rack_mapped_spec.rb new file mode 100644 index 00000000..6e82848f --- /dev/null +++ b/spec/webmachine/adapters/rack_mapped_spec.rb @@ -0,0 +1,71 @@ +require 'webmachine/adapter' +require 'webmachine/adapters/rack_mapped' +require 'spec_helper' +require 'webmachine/spec/adapter_lint' +require 'rack/test' + +describe Webmachine::Adapters::RackMapped do + it_should_behave_like :adapter_lint do + it "should set Server header" do + response = client.request(Net::HTTP::Get.new("/test")) + expect(response["Server"]).to match(/Webmachine/) + expect(response["Server"]).to match(/Rack/) + end + end +end + +describe Webmachine::Adapters::RackMapped do + class CreateResource < Webmachine::Resource + def allowed_methods + ["POST"] + end + + def content_types_accepted + [["application/json", :from_json]] + end + + def content_types_provided + [["application/json", :to_json]] + end + + def post_is_create? + true + end + + def create_path + "created_path_here/123" + end + + def from_json + response.body = %{ {"foo": "bar"} } + end + end + + let(:app) do + Rack::Builder.new do + map '/some/route' do + run(Webmachine::Application.new do |app| + app.add_route(["test"], Test::Resource) + app.add_route(["create_test"], CreateResource) + app.configure do | config | + config.adapter = :RackMapped + end + end.adapter) + end + end + end + + context "using Rack::Test" do + include Rack::Test::Methods + + it "provides the full request URI" do + rack_response = get "some/route/test", nil, {"HTTP_ACCEPT" => "test/response.request_uri"} + expect(rack_response.body).to eq "http://example.org/some/route/test" + end + + it "provides LOCATION header using custom base_uri when creating from POST request" do + rack_response = post "/some/route/create_test", %{{"foo": "bar"}}, {"HTTP_ACCEPT" => "application/json", "CONTENT_TYPE" => "application/json"} + expect(rack_response.headers["Location"]).to eq("http://example.org/some/route/created_path_here/123") + end + end +end diff --git a/spec/webmachine/adapters/rack_spec.rb b/spec/webmachine/adapters/rack_spec.rb index 645211a8..f0e32449 100644 --- a/spec/webmachine/adapters/rack_spec.rb +++ b/spec/webmachine/adapters/rack_spec.rb @@ -14,16 +14,6 @@ end end -describe Webmachine::Adapters::RackMapped do - it_should_behave_like :adapter_lint do - it "should set Server header" do - response = client.request(Net::HTTP::Get.new("/test")) - expect(response["Server"]).to match(/Webmachine/) - expect(response["Server"]).to match(/Rack/) - end - end -end - describe Webmachine::Adapters::Rack::RackResponse do context "on Rack < 1.5 release" do before { allow(Rack).to receive_messages(:release => "1.4") } @@ -65,59 +55,3 @@ end end end - -describe Webmachine::Adapters::RackMapped do - class CreateResource < Webmachine::Resource - def allowed_methods - ["POST"] - end - - def content_types_accepted - [["application/json", :from_json]] - end - - def content_types_provided - [["application/json", :to_json]] - end - - def post_is_create? - true - end - - def create_path - "created_path_here/123" - end - - def from_json - response.body = %{ {"foo": "bar"} } - end - end - - let(:app) do - Rack::Builder.new do - map '/some/route' do - run(Webmachine::Application.new do |app| - app.add_route(["test"], Test::Resource) - app.add_route(["create_test"], CreateResource) - app.configure do | config | - config.adapter = :RackMapped - end - end.adapter) - end - end - end - - context "using Rack::Test" do - include Rack::Test::Methods - - it "provides the full request URI" do - rack_response = get "some/route/test", nil, {"HTTP_ACCEPT" => "test/response.request_uri"} - expect(rack_response.body).to eq "http://example.org/some/route/test" - end - - it "provides LOCATION header using custom base_uri when creating from POST request" do - rack_response = post "/some/route/create_test", %{{"foo": "bar"}}, {"HTTP_ACCEPT" => "application/json", "CONTENT_TYPE" => "application/json"} - expect(rack_response.headers["Location"]).to eq("http://example.org/some/route/created_path_here/123") - end - end -end From 089ea5513f2668241e281495a97c58371bde523b Mon Sep 17 00:00:00 2001 From: Beth Date: Fri, 20 Mar 2015 11:24:01 +1100 Subject: [PATCH 041/122] Version 1.4.0 --- CHANGELOG.md | 6 ++++++ lib/webmachine/version.rb | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43a0a463..1358cc73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ ### HEAD +### 1.4.0 March 20, 2015 + +* Added RackMapped adapter which allows Webmachine apps to be mounted + at a non-root path using Rack::Map. + Thanks to [Julian Doherty](https://github.com/madlep) for writing this. + ### 1.3.1 January 15, 2015 * Fixed URI construction, including handling IPv6 addresses, when the diff --git a/lib/webmachine/version.rb b/lib/webmachine/version.rb index 8e3b8c12..5c475f85 100644 --- a/lib/webmachine/version.rb +++ b/lib/webmachine/version.rb @@ -1,6 +1,6 @@ module Webmachine # Library version - VERSION = "1.3.1".freeze + VERSION = "1.4.0".freeze # String for use in "Server" HTTP response header, which includes # the {VERSION}. From f87b53b719ffbdacf3d6ca56944522f9e2e7346e Mon Sep 17 00:00:00 2001 From: Beth Date: Fri, 20 Mar 2015 13:28:14 +1100 Subject: [PATCH 042/122] Use bundler gem tasks instead of custom tasks. rake release was raising 'Circular dependency detected' errors. --- Rakefile | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/Rakefile b/Rakefile index 531ade9f..9c5f3a5e 100644 --- a/Rakefile +++ b/Rakefile @@ -1,5 +1,4 @@ -require 'rubygems' -require 'rubygems/package_task' +require "bundler/gem_tasks" begin require 'yard' @@ -11,26 +10,12 @@ begin rescue LoadError end -def gemspec - $webmachine_gemspec ||= Gem::Specification.load("webmachine.gemspec") +desc "Validate the gemspec file." +task :validate_gemspec do + Gem::Specification.load("webmachine.gemspec").validate end -Gem::PackageTask.new(gemspec) do |pkg| - pkg.need_zip = false - pkg.need_tar = false -end - -task :gem => :gemspec - -desc %{Validate the gemspec file.} -task :gemspec do - gemspec.validate -end - -desc %{Release the gem to RubyGems.org} -task :release => :gem do - system "gem push pkg/#{gemspec.name}-#{gemspec.version}.gem" -end +task :build => :validate_gemspec desc "Cleans up white space in source files" task :clean_whitespace do From 7cdae39cce0210048a81733d7318439892ce39fc Mon Sep 17 00:00:00 2001 From: jurre Date: Wed, 3 Jun 2015 08:42:13 +0200 Subject: [PATCH 043/122] Correct IRWebmachine url in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dad53a24..74919582 100644 --- a/README.md +++ b/README.md @@ -163,7 +163,7 @@ the "visual debugger". Learn how to configure it [here][visual-debugger]. ## Related libraries -* [irwebmachine](https://github.com/robgleeson/irwebmachine) - IRB/Pry debugging of Webmachine applications +* [irwebmachine](https://github.com/generalassembly/irwebmachine) - IRB/Pry debugging of Webmachine applications * [webmachine-test](https://github.com/bernd/webmachine-test) - Helpers for testing Webmachine applications * [webmachine-linking](https://github.com/petejohanson/webmachine-linking) - Helpers for linking between Resources, and Web Linking * [webmachine-sprockets](https://github.com/lgierth/webmachine-sprockets) - Integration with Sprockets assets packaging system From 61adfa36b3ecaa0ef86dbf9c87564a4c16afd1a9 Mon Sep 17 00:00:00 2001 From: Jim van Musscher Date: Sat, 15 Aug 2015 13:38:52 +0200 Subject: [PATCH 044/122] Fix Travis CI status button. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 74919582..935b215a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# webmachine for Ruby [![Build Status](https://travis-ci.org/seancribbs/webmachine-ruby.svg)](https://travis-ci.org/seancribbs/webmachine-ruby) +# webmachine for Ruby [![Build Status](https://travis-ci.org/webmachine/webmachine-ruby.svg)](https://travis-ci.org/webmachine/webmachine-ruby) webmachine-ruby is a port of [Webmachine](https://github.com/basho/webmachine), which is written in From 3fa811942926c9b9bcde4110e84271de3f8b5767 Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Thu, 20 Aug 2015 08:21:00 +1000 Subject: [PATCH 045/122] Updating link to finite state machine diagram. --- documentation/how-it-works.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/how-it-works.md b/documentation/how-it-works.md index 70d49087..323dfd1a 100644 --- a/documentation/how-it-works.md +++ b/documentation/how-it-works.md @@ -71,6 +71,6 @@ end * A collection resource (eg. /orders) should be implemented as a separate class to a single object resource (eg. /orders/1), as the routes represent different underlying objects with different "facts". For example, the orders _collection_ resource probably always exists (but may be empty), however the order with ID 1 may or may not exist. [callbacks]: https://github.com/seancribbs/webmachine-ruby/blob/master/lib/webmachine/resource/callbacks.rb -[diagram]: http://webmachine.basho.com/images/http-headers-status-v3.png +[diagram]: https://webmachine.github.io/images/http-headers-status-v3.png [flow]: https://github.com/seancribbs/webmachine-ruby/blob/master/lib/webmachine/decision/flow.rb [examples]: /documentation/examples.md From bc7b147c5c7369c6e841d3eef30efe9f454ed108 Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Thu, 20 Aug 2015 08:34:40 +1000 Subject: [PATCH 046/122] Added comments about PUT to a non-existent resource. --- documentation/examples.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/documentation/examples.md b/documentation/examples.md index 08f25538..86cca70d 100644 --- a/documentation/examples.md +++ b/documentation/examples.md @@ -137,6 +137,8 @@ class OrderResource < Webmachine::Resource [["application/json", :from_json]] end + # Note that returning falsey will NOT result in a 404 for PUT requests. + # See note below. def resource_exists? order end @@ -166,8 +168,10 @@ class OrderResource < Webmachine::Resource end ``` +If you wish to disallow PUT to a non-existent resource, read more [here](https://github.com/webmachine/webmachine-ruby/issues/207#issuecomment-132604379). + # PATCH -* Webmachine does not currently support PATCH requests. See https://github.com/seancribbs/webmachine-ruby/issues/109 for more information and https://github.com/bethesque/pact_broker/blob/2918814e70bbda14df68598a6a41502a5eac4308/lib/pact_broker/api/resources/pacticipant.rb for a dirty hack to make it work if you need to. +* Webmachine does not currently support PATCH requests. See https://github.com/webmachine/webmachine-ruby/issues/109 for more information and https://github.com/bethesque/pact_broker/blob/2918814e70bbda14df68598a6a41502a5eac4308/lib/pact_broker/api/resources/pacticipant.rb for a dirty hack to make it work if you need to. # DELETE * Override `resource_exists?` and `delete_resource` From 0998bb75980f6722544f9286d0c1907a1833c6a0 Mon Sep 17 00:00:00 2001 From: Russell Garner Date: Tue, 5 Apr 2016 21:07:22 +0100 Subject: [PATCH 047/122] Fix timeout deprecation on recent rubies * Use Timeout.timeout, not Object#timeout --- lib/webmachine/spec/adapter_lint.rb | 2 +- spec/webmachine/adapters/reel_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/webmachine/spec/adapter_lint.rb b/lib/webmachine/spec/adapter_lint.rb index 61af0016..fe978f5b 100644 --- a/lib/webmachine/spec/adapter_lint.rb +++ b/lib/webmachine/spec/adapter_lint.rb @@ -22,7 +22,7 @@ let(:client) do client = Net::HTTP.new(application.configuration.ip, port) # Wait until the server is responsive - timeout(5) do + Timeout.timeout(5) do begin client.start rescue Errno::ECONNREFUSED diff --git a/spec/webmachine/adapters/reel_spec.rb b/spec/webmachine/adapters/reel_spec.rb index 9d954b44..24e62560 100644 --- a/spec/webmachine/adapters/reel_spec.rb +++ b/spec/webmachine/adapters/reel_spec.rb @@ -56,7 +56,7 @@ def reel_server(adptr = adapter) thread = Thread.new { adptr.run } begin - timeout(5) do + Timeout.timeout(5) do begin sock = TCPSocket.new(adptr.application.configuration.ip, adptr.application.configuration.port) begin From be9a9927966595c8315baa934a2c1b62532dd3f0 Mon Sep 17 00:00:00 2001 From: Russell Garner Date: Tue, 5 Apr 2016 22:01:29 +0100 Subject: [PATCH 048/122] Don't run celluloid in backported mode * http://git.io/vJf3J * This appears consistently to fix the red Reel tests --- lib/webmachine/adapters/reel.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/webmachine/adapters/reel.rb b/lib/webmachine/adapters/reel.rb index ec7aebb2..5a084227 100644 --- a/lib/webmachine/adapters/reel.rb +++ b/lib/webmachine/adapters/reel.rb @@ -1,6 +1,7 @@ require 'webmachine/adapter' require 'webmachine/constants' require 'set' +require 'celluloid/current' require 'reel' require 'webmachine/headers' require 'webmachine/request' From 9088c33d686d64cc7f07ff496d19efacc8351099 Mon Sep 17 00:00:00 2001 From: Russell Garner Date: Tue, 5 Apr 2016 22:13:13 +0100 Subject: [PATCH 049/122] Add ruby 2.3.0 to travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index f3dad088..fc7e66b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ rvm: - 1.9.3 - 2.0.0 - 2.1.2 + - 2.3.0 - ruby-head - jruby - rbx-2 From 07f02c22cc11840f9b539da9ba419e13ef257785 Mon Sep 17 00:00:00 2001 From: Russell Garner Date: Wed, 6 Apr 2016 09:54:51 +0100 Subject: [PATCH 050/122] Update bundler before install * Avoids NoMethodError: undefined method `spec' for nil:NilClass * Similar approach used in https://github.com/thoughtbot/factory_girl/commit/3c0547fa508d212f79050301d5622434e4731c48 --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index fc7e66b4..fd44be2c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,10 @@ matrix: - rvm: ruby-head - rvm: jruby +before_install: + - gem update --system + - gem update bundler + bundler_args: --without guard docs script: bundle exec rspec spec/ -b From 81c4eea1220e4193872f0e0edf245bc90ea1f38f Mon Sep 17 00:00:00 2001 From: Russell Garner Date: Wed, 6 Apr 2016 21:23:02 +0100 Subject: [PATCH 051/122] Fix port collisions in adapter_lint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to 'reserve' a free TCP Server port, we create a TCPServer, take a note of its port number, and then immediately close it. We'd then ask our adapter to use the port we just finished with via that adapter's configuration. While this isn't a particularly safe way of 'reserving' a port, it's the best we can do with heterogeneous adapters that have a one-way config method. However, this would cause intermittent test failures when our 'canary' socket did not get out of the way in time for an adapter to bind its server. Socket#close does not actually block until the socket is closed at OS level, it just frees the Ruby handle to it. Actually waiting for the socket to become free or garbage-collecting it to force the issue is counterproductive – we'd need to poll the port or run a full GC, which would take more time than a simple sleep. Additionally, the sleep needs to be tuned so that tests are not unduly slowed by it – too quick and we'll see failures, too slow and our builds will reflect it. --- lib/webmachine/spec/adapter_lint.rb | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/webmachine/spec/adapter_lint.rb b/lib/webmachine/spec/adapter_lint.rb index fe978f5b..d50e642d 100644 --- a/lib/webmachine/spec/adapter_lint.rb +++ b/lib/webmachine/spec/adapter_lint.rb @@ -5,7 +5,19 @@ attr_accessor :client let(:address) { "127.0.0.1" } - let(:port) { s = TCPServer.new(address, 0); p = s.addr[1]; s.close; p } + let(:port) do + s = TCPServer.new(address, 0) + p = s.addr[1] + s.close # This does not close the socket at OS level, just frees from Ruby. + # The socket will be in TIME_WAIT http://www.ssfnet.org/Exchange/tcp/tcpTutorialNotes.html + # "The main thing to recognize about connection teardown is that a connection in + # the TIME_WAIT state cannot move to the CLOSED state until it has waited for two times + # the maximum amount of time an IP datagram might live in the Inter net." + + sleep(0.005) # This is just about the best we can do. Any more slows the tests, + # any less and we get intermittent silent port collisions + p + end let(:application) do application = Webmachine::Application.new From 2e6d38f1d3b28ac7853f5011eb7dbe8a36cb8310 Mon Sep 17 00:00:00 2001 From: Russell Garner Date: Thu, 7 Apr 2016 09:37:34 +0100 Subject: [PATCH 052/122] Revert back to before(:all) for adapter_lint Using let-style RSpec and lazily creating our servers before every test is good from a test purity point of view but increases greatly the risk of port collisions when we attempt to find a free port to run our adapter in adapter_lint (bearing in mind that Socket#close only releases the Ruby resources, and the socket persists in a TIME_WAIT state for an indeterminate period of time at OS level). Revert to before(:all) and create only one server that will be used for the duration of all tests in adapter_lint. We still need to sleep to ensure our 'free' ports are available, but we reduce the risk of servers being unavailable. This also has the happy side effect of making the tests somewhat faster. --- lib/webmachine/spec/adapter_lint.rb | 80 +++++++++++++++-------------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/lib/webmachine/spec/adapter_lint.rb b/lib/webmachine/spec/adapter_lint.rb index d50e642d..3bb08359 100644 --- a/lib/webmachine/spec/adapter_lint.rb +++ b/lib/webmachine/spec/adapter_lint.rb @@ -1,40 +1,42 @@ require "webmachine/spec/test_resource" require "net/http" +ADDRESS = "127.0.0.1" + shared_examples_for :adapter_lint do - attr_accessor :client - - let(:address) { "127.0.0.1" } - let(:port) do - s = TCPServer.new(address, 0) - p = s.addr[1] - s.close # This does not close the socket at OS level, just frees from Ruby. - # The socket will be in TIME_WAIT http://www.ssfnet.org/Exchange/tcp/tcpTutorialNotes.html - # "The main thing to recognize about connection teardown is that a connection in - # the TIME_WAIT state cannot move to the CLOSED state until it has waited for two times - # the maximum amount of time an IP datagram might live in the Inter net." - - sleep(0.005) # This is just about the best we can do. Any more slows the tests, - # any less and we get intermittent silent port collisions - p - end - - let(:application) do - application = Webmachine::Application.new - application.dispatcher.add_route ["test"], Test::Resource - - application.configure do |c| - c.ip = address - c.port = port + attr_reader :client + + class TestApplicationNotResponsive < Timeout::Error; end + + def find_free_port + temp_server = TCPServer.new(ADDRESS, 0) + port = temp_server.addr[1] + temp_server.close # only frees Ruby resource, socket is in TIME_WAIT at OS level + # so we can't have our adapter use it too quickly + + sleep(0.1) # 'Wait' for temp_server to *really* close, not just TIME_WAIT + port + end + + def create_test_application(port) + Webmachine::Application.new.tap do |application| + application.dispatcher.add_route ["test"], Test::Resource + + application.configure do |c| + c.ip = ADDRESS + c.port = port + end end + end - application + def run_application(adapter_class, application) + adapter = adapter_class.new(application) + Thread.abort_on_exception = true + Thread.new { adapter.run } end - let(:client) do - client = Net::HTTP.new(application.configuration.ip, port) - # Wait until the server is responsive - Timeout.timeout(5) do + def wait_until_server_responds_to(client) + Timeout.timeout(5, TestApplicationNotResponsive) do begin client.start rescue Errno::ECONNREFUSED @@ -42,19 +44,21 @@ retry end end - client end - before do - @adapter = described_class.new(application) + before(:all) do + @port = find_free_port + application = create_test_application(@port) - Thread.abort_on_exception = true - @server_thread = Thread.new { @adapter.run } - sleep(0.01) + adapter_class = described_class + @server_thread = run_application(adapter_class, application) + + @client = Net::HTTP.new(application.configuration.ip, @port) + wait_until_server_responds_to(client) end - after do - client.finish + after(:all) do + @client.finish @server_thread.kill end @@ -62,7 +66,7 @@ request = Net::HTTP::Get.new("/test") request["Accept"] = "test/response.request_uri" response = client.request(request) - expect(response.body).to eq("http://#{address}:#{port}/test") + expect(response.body).to eq("http://#{ADDRESS}:#{@port}/test") end # context do From 5646586e3da1373bc191f0ab7d737c991dc8535f Mon Sep 17 00:00:00 2001 From: Russell Garner Date: Sat, 9 Apr 2016 20:58:24 +0100 Subject: [PATCH 053/122] Add ruby 2.2.0 to .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index fd44be2c..3da2534d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ rvm: - 1.9.3 - 2.0.0 - 2.1.2 + - 2.2.0 - 2.3.0 - ruby-head - jruby From 945933853991aa6fa49191ea8e18423a90d83952 Mon Sep 17 00:00:00 2001 From: Ryan Festag Date: Sat, 23 Apr 2016 08:32:56 -0600 Subject: [PATCH 054/122] Added support for regex in path spec. Supports adding :captures path_info element for any capture groups --- lib/webmachine/dispatcher/route.rb | 7 +++++++ spec/webmachine/dispatcher/route_spec.rb | 16 +++++++++++++++- spec/webmachine/dispatcher_spec.rb | 15 +++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/lib/webmachine/dispatcher/route.rb b/lib/webmachine/dispatcher/route.rb index 08fbd762..1f6ef59b 100644 --- a/lib/webmachine/dispatcher/route.rb +++ b/lib/webmachine/dispatcher/route.rb @@ -119,6 +119,13 @@ def bind(tokens, bindings) return [depth, tokens] when tokens.empty? return false + when Regexp === spec.first + matches = spec.first.match URI.decode(tokens.first) + if matches + bindings[:captures] = (bindings[:captures] || []) + matches.captures + else + return false + end when Symbol === spec.first bindings[spec.first] = URI.decode(tokens.first) when spec.first == tokens.first diff --git a/spec/webmachine/dispatcher/route_spec.rb b/spec/webmachine/dispatcher/route_spec.rb index c97f56dc..d22f1b72 100644 --- a/spec/webmachine/dispatcher/route_spec.rb +++ b/spec/webmachine/dispatcher/route_spec.rb @@ -180,7 +180,6 @@ def call(request) end end end - context "on a deep path" do subject { described_class.new(%w{foo bar baz}, resource) } let(:uri) { URI.parse("http://localhost:8080/foo/bar/baz") } @@ -205,6 +204,21 @@ def call(request) expect(request.path_info).to eq({:id => "bar"}) end end + context "with regex" do + subject { described_class.new([/foo/, /(.*)/, 'baz'], resource) } + + it "should assign the captures path variables" do + expect(request.path_info).to eq({:captures => ["bar"]}) + end + end + context "with multi-capture regex" do + subject { described_class.new([/foo/, /(.*)/, /baz\.(.*)/], resource) } + let(:uri) { URI.parse("http://localhost:8080/foo/bar/baz.json") } + + it "should assign the captures path variables" do + expect(request.path_info).to eq({:captures => ["bar", "json"]}) + end + end context "with a splat" do subject { described_class.new(['foo', :*], resource) } diff --git a/spec/webmachine/dispatcher_spec.rb b/spec/webmachine/dispatcher_spec.rb index faeede65..229f3991 100644 --- a/spec/webmachine/dispatcher_spec.rb +++ b/spec/webmachine/dispatcher_spec.rb @@ -3,6 +3,7 @@ describe Webmachine::Dispatcher do let(:dispatcher) { Webmachine.application.dispatcher } let(:request) { Webmachine::Request.new("GET", URI.parse("http://localhost:8080/"), Webmachine::Headers["accept" => "*/*"], "") } + let(:request2) { Webmachine::Request.new("GET", URI.parse("http://localhost:8080/hello/bob.html"), Webmachine::Headers["accept" => "*/*"], "") } let(:response) { Webmachine::Response.new } let(:resource) do Class.new(Webmachine::Resource) do @@ -14,6 +15,14 @@ def to_html; "hello world!"; end def to_html; "goodbye, cruel world"; end end end + let(:resource3) do + Class.new(Webmachine::Resource) do + def to_html + name, format = request.path_info[:captures] + "Hello #{name} with #{format}" + end + end + end let(:fsm){ double } before { dispatcher.reset } @@ -44,6 +53,12 @@ def to_html; "goodbye, cruel world"; end expect(fsm).to receive(:run) dispatcher.dispatch(request, response) end + it "should handle regex path segments in route definition" do + dispatcher.add_route ["hello", /(.*)\.(.*)/], resource3 + expect(Webmachine::Decision::FSM).to receive(:new).with(instance_of(resource3), request2, response).and_return(fsm) + expect(fsm).to receive(:run) + dispatcher.dispatch(request2, response) + end it "should apply route to request before creating the resource" do route = dispatcher.add_route [:*], resource From d300057ed424e5826383c3fc0524259b544ed30e Mon Sep 17 00:00:00 2001 From: Russell Garner Date: Sat, 23 Apr 2016 21:21:28 +0100 Subject: [PATCH 055/122] Allow Rubinius to fail For reasons we can't currently fathom, Rubinius has a tendency to fail the build. Rather than let this continue to be the case, until such time as someone has time to figure out precisely why, unblock other PRs by letting builds pass with MRI Rubies for now. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 3da2534d..04bcf9db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ matrix: allow_failures: - rvm: ruby-head - rvm: jruby + - rvm: rbx-2 before_install: - gem update --system From 9103bcc5eede6fc94c521e19b8cc98977cab116d Mon Sep 17 00:00:00 2001 From: Ryan Festag Date: Sun, 1 May 2016 00:02:48 -0600 Subject: [PATCH 056/122] Added support for named captures --- lib/webmachine/dispatcher/route.rb | 9 ++++++++- spec/webmachine/dispatcher/route_spec.rb | 8 ++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/webmachine/dispatcher/route.rb b/lib/webmachine/dispatcher/route.rb index 1f6ef59b..9033733e 100644 --- a/lib/webmachine/dispatcher/route.rb +++ b/lib/webmachine/dispatcher/route.rb @@ -122,7 +122,14 @@ def bind(tokens, bindings) when Regexp === spec.first matches = spec.first.match URI.decode(tokens.first) if matches - bindings[:captures] = (bindings[:captures] || []) + matches.captures + if spec.first.named_captures.empty? + bindings[:captures] = (bindings[:captures] || []) + matches.captures + else + spec.first.named_captures.reduce(bindings) do |bindings, (name, idxs)| + bindings[name.to_sym] = matches.captures[idxs.first-1] + bindings + end + end else return false end diff --git a/spec/webmachine/dispatcher/route_spec.rb b/spec/webmachine/dispatcher/route_spec.rb index d22f1b72..0a43d810 100644 --- a/spec/webmachine/dispatcher/route_spec.rb +++ b/spec/webmachine/dispatcher/route_spec.rb @@ -219,6 +219,14 @@ def call(request) expect(request.path_info).to eq({:captures => ["bar", "json"]}) end end + context "with named capture regex" do + subject { described_class.new(['foo', :bar, /(?[^.]+)\.(?.*)/], resource) } + let(:uri) { URI.parse("http://localhost:8080/foo/bar/baz.json") } + + it "should assign the captures path variables" do + expect(request.path_info).to eq({bar: 'bar', baz: 'baz', format: "json"}) + end + end context "with a splat" do subject { described_class.new(['foo', :*], resource) } From f146b2ba4c9d1fdad466a805172b639699579c0f Mon Sep 17 00:00:00 2001 From: Ryan Festag Date: Sun, 1 May 2016 07:29:26 -0600 Subject: [PATCH 057/122] Added documentation on regex route components --- documentation/routes.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/documentation/routes.md b/documentation/routes.md index bdbd27f0..9dcfd307 100644 --- a/documentation/routes.md +++ b/documentation/routes.md @@ -20,6 +20,21 @@ App = Webmachine::Application.new do |app| # but will not provide any path_info add ["orders", :*], OrderResource + # Will map to any path that matches the given components and regular expression + # Any capture groups specified in the regex will be made available in + # request.path_info[:captures. In this case, you would get one or two + # values in :captures depending on whether your request looked like: + # /orders/1/cancel + # or + # /orders/1/cancel.json + add ["orders", :id, /([^.]*)\.?(.*)?/], OrderResource + + # You can even use named captures with regular expressions. This will + # automatically put the captures into path_info. In the below example, + # you would get :id from the symbol, along with :action and :format + # from the regex. :format in this case would be optional. + add ["orders", :id, /(?)[^.]*)\.?(?.*)?/], OrderResource + # will map to any path add [:*], DefaultResource end @@ -94,4 +109,4 @@ end request.path_info[:foo] => "bar" -``` \ No newline at end of file +``` From a0544681e34f8e64e680dc2b584250cc65d7c19b Mon Sep 17 00:00:00 2001 From: Ryan Festag Date: Mon, 30 Jan 2017 08:29:59 -0700 Subject: [PATCH 058/122] Fixing multiple cookie setting code, updating test to verify all three cases in set_cookie --- lib/webmachine/response.rb | 2 +- spec/webmachine/response_spec.rb | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/webmachine/response.rb b/lib/webmachine/response.rb index 8c45a8b8..daa59634 100644 --- a/lib/webmachine/response.rb +++ b/lib/webmachine/response.rb @@ -52,7 +52,7 @@ def set_cookie(name, value, attributes = {}) when String headers['Set-Cookie'] = [headers['Set-Cookie'], cookie] when Array - headers['Set-Cookie'] = headers['Set-Cookie'] + cookie + headers['Set-Cookie'] = headers['Set-Cookie'] << cookie end end diff --git a/spec/webmachine/response_spec.rb b/spec/webmachine/response_spec.rb index f82ddf5b..e67fc9da 100644 --- a/spec/webmachine/response_spec.rb +++ b/spec/webmachine/response_spec.rb @@ -31,14 +31,22 @@ end describe "setting multiple cookies" do + puts "Multiple cookie test" let(:cookie2) { "rodeo" } let(:cookie2_value) { "clown" } - before(:each) { subject.set_cookie(cookie2, cookie2_value) } + let(:cookie3) {"color"} + let(:cookie3_value) {"blue"} + before(:each) do + subject.set_cookie(cookie2, cookie2_value) + subject.set_cookie(cookie3, cookie3_value) + end it "should have a proper Set-Cookie header" do + puts subject.headers["Set-Cookie"] expect(subject.headers["Set-Cookie"]).to be_a Array expect(subject.headers["Set-Cookie"]).to include "rodeo=clown" expect(subject.headers["Set-Cookie"]).to include "monster=mash" + expect(subject.headers["Set-Cookie"]).to include "color=blue" end end end From cecef71a69bcd7fbd32424bb5989c0f5a2bc61c6 Mon Sep 17 00:00:00 2001 From: Ryan Festag Date: Mon, 30 Jan 2017 08:32:03 -0700 Subject: [PATCH 059/122] Updated to simplify set cookie, creating fewer edge cases. Removing puts statements in tests --- lib/webmachine/response.rb | 4 +--- spec/webmachine/response_spec.rb | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/webmachine/response.rb b/lib/webmachine/response.rb index daa59634..c98009d5 100644 --- a/lib/webmachine/response.rb +++ b/lib/webmachine/response.rb @@ -48,9 +48,7 @@ def set_cookie(name, value, attributes = {}) cookie = Webmachine::Cookie.new(name, value, attributes).to_s case headers['Set-Cookie'] when nil - headers['Set-Cookie'] = cookie - when String - headers['Set-Cookie'] = [headers['Set-Cookie'], cookie] + headers['Set-Cookie'] = [cookie] when Array headers['Set-Cookie'] = headers['Set-Cookie'] << cookie end diff --git a/spec/webmachine/response_spec.rb b/spec/webmachine/response_spec.rb index e67fc9da..b6fc1e5e 100644 --- a/spec/webmachine/response_spec.rb +++ b/spec/webmachine/response_spec.rb @@ -31,7 +31,6 @@ end describe "setting multiple cookies" do - puts "Multiple cookie test" let(:cookie2) { "rodeo" } let(:cookie2_value) { "clown" } let(:cookie3) {"color"} @@ -42,7 +41,6 @@ end it "should have a proper Set-Cookie header" do - puts subject.headers["Set-Cookie"] expect(subject.headers["Set-Cookie"]).to be_a Array expect(subject.headers["Set-Cookie"]).to include "rodeo=clown" expect(subject.headers["Set-Cookie"]).to include "monster=mash" From 4081d155633be768b3906c3f41742e2242b49942 Mon Sep 17 00:00:00 2001 From: Ryan Festag Date: Mon, 30 Jan 2017 08:48:53 -0700 Subject: [PATCH 060/122] Updated to remove unnecessary assignment --- lib/webmachine/response.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/webmachine/response.rb b/lib/webmachine/response.rb index c98009d5..1fe12153 100644 --- a/lib/webmachine/response.rb +++ b/lib/webmachine/response.rb @@ -50,7 +50,7 @@ def set_cookie(name, value, attributes = {}) when nil headers['Set-Cookie'] = [cookie] when Array - headers['Set-Cookie'] = headers['Set-Cookie'] << cookie + headers['Set-Cookie'] << cookie end end From f12ee46969fa6998afc85b30bf1544e6d521a011 Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Fri, 7 Apr 2017 11:51:36 +1000 Subject: [PATCH 061/122] Moved heading out of a tag so that it formats correctly. --- documentation/examples.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/documentation/examples.md b/documentation/examples.md index 86cca70d..d61cfaa4 100644 --- a/documentation/examples.md +++ b/documentation/examples.md @@ -212,8 +212,7 @@ Thanks to [oestrich][oestrich] for putting together the original example. You ca [oestrich]: https://github.com/oestrich [source]: https://gist.github.com/oestrich/3638605 - + ## What order are the callbacks invoked in? - This question is actually irrelevant if you write your code in a "stateless" way using lazy initialization as the examples do above. As much as possible, think about exposing "facts" about your resource, not writing procedural code that needs to be called in a certain order. See [How it works](/documentation/how-it-works.md) for more information on how the Webmachine state machine works. From 4f67ff37874e8d1be9979a766fdb82b427a2b81a Mon Sep 17 00:00:00 2001 From: Beth Date: Mon, 14 Aug 2017 14:40:51 +1000 Subject: [PATCH 062/122] chore: lock rspec and rake gems rake spec task needs certain versions of rspec/rake to work correctly. Otherwise it may fail with the error: undefined method last_comment for Rake::Application --- Gemfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index a85835c6..137d2927 100644 --- a/Gemfile +++ b/Gemfile @@ -4,11 +4,11 @@ gemspec group :development do gem "yard" - gem "rake" + gem "rake", "~> 12.0" end group :test do - gem "rspec", '~> 3.0.0' + gem "rspec", '~> 3.0', '>= 3.6.0' gem "rspec-its" gem "rack" gem "rack-test" From e9baf0b6acfd1923aebb74dffc9aa8557fa5f005 Mon Sep 17 00:00:00 2001 From: Beth Date: Mon, 14 Aug 2017 14:46:23 +1000 Subject: [PATCH 063/122] chore: lock all other darwin gems Without locks to stop major version changes being picked up, the build will break when backwards incompatible changes are released by any of the gems --- Gemfile | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Gemfile b/Gemfile index 137d2927..c94d7806 100644 --- a/Gemfile +++ b/Gemfile @@ -3,15 +3,15 @@ source 'https://rubygems.org' gemspec group :development do - gem "yard" + gem "yard", "~> 0.9" gem "rake", "~> 12.0" end group :test do - gem "rspec", '~> 3.0', '>= 3.6.0' - gem "rspec-its" - gem "rack" - gem "rack-test" + gem "rspec", "~> 3.0", ">= 3.6.0" + gem "rspec-its", "~> 1.2" + gem "rack", "~> 2.0" + gem "rack-test", "~> 0.7" end group :webservers do @@ -21,12 +21,12 @@ group :webservers do end group :guard do - gem 'guard-rspec' + gem 'guard-rspec', '~> 4.7' case RbConfig::CONFIG['host_os'] when /darwin/ - gem 'rb-fsevent' + gem 'rb-fsevent', '~> 0.10' # gem 'growl_notify' - gem 'growl' + gem 'growl', '~> 1.0' when /linux/ gem 'rb-inotify' gem 'libnotify' @@ -35,7 +35,7 @@ end group :docs do platform :mri_19, :mri_20 do - gem 'redcarpet' + gem 'redcarpet', '~> 3.4' end end From 97e64ab47e31f3232541c8bd1493ed38004ec521 Mon Sep 17 00:00:00 2001 From: Beth Date: Mon, 14 Aug 2017 15:01:12 +1000 Subject: [PATCH 064/122] chore: update supported rubies Drop 1.9.3, 2.0.0, 2.1.2, 2.2.0 Add 2.2.2 and 2.4.1 Ruby 2.1 is no longer supported, and < 2.2.2 doesn't work with latest rack gem --- .travis.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 04bcf9db..7c9b386f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,7 @@ rvm: - - 1.9.3 - - 2.0.0 - - 2.1.2 - - 2.2.0 + - 2.2.2 - 2.3.0 + - 2.4.1 - ruby-head - jruby - rbx-2 From dbe7289eada5b2ff4979e25ffe83759df56018c2 Mon Sep 17 00:00:00 2001 From: Beth Date: Mon, 14 Aug 2017 15:31:24 +1000 Subject: [PATCH 065/122] fix: use Integer instead of Fixnum This removes 'Warning: constant ::Fixnum is deprecated' in ruby >= 2.4.0 --- lib/webmachine/configuration.rb | 2 +- lib/webmachine/decision/flow.rb | 22 +++++++++++----------- lib/webmachine/decision/fsm.rb | 2 +- lib/webmachine/decision/helpers.rb | 2 +- lib/webmachine/dispatcher/route.rb | 2 +- lib/webmachine/errors.rb | 2 +- lib/webmachine/resource/callbacks.rb | 4 ++-- lib/webmachine/response.rb | 2 +- lib/webmachine/streaming/io_encoder.rb | 2 +- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/lib/webmachine/configuration.rb b/lib/webmachine/configuration.rb index d6b66ef2..d64e6847 100644 --- a/lib/webmachine/configuration.rb +++ b/lib/webmachine/configuration.rb @@ -5,7 +5,7 @@ module Webmachine # defaults will be filled in when {Webmachine::run} is called. # @attr [String] ip the interface to bind to, defaults to "0.0.0.0" # (all interfaces) - # @attr [Fixnum] port the port to bind to, defaults to 8080 + # @attr [Integer] port the port to bind to, defaults to 8080 # @attr [Symbol] adapter the adapter to use, defaults to :WEBrick # @attr [Hash] adapter_options adapter-specific options, defaults to {} Configuration = Struct.new(:ip, :port, :adapter, :adapter_options) diff --git a/lib/webmachine/decision/flow.rb b/lib/webmachine/decision/flow.rb index 103e23e6..c05c68d9 100644 --- a/lib/webmachine/decision/flow.rb +++ b/lib/webmachine/decision/flow.rb @@ -35,7 +35,7 @@ module Flow # Handles standard decisions where halting is allowed def decision_test(test, iftrue, iffalse) case test - when Fixnum # Allows callbacks to "halt" with a given response code + when Integer # Allows callbacks to "halt" with a given response code test when Falsey iffalse @@ -77,7 +77,7 @@ def b9 # Content-MD5 valid? def b9a case valid = resource.validate_content_checksum - when Fixnum + when Integer valid when true :b9b @@ -105,7 +105,7 @@ def b8 case result when true :b7 - when Fixnum + when Integer result when String response.headers['WWW-Authenticate'] = result @@ -280,7 +280,7 @@ def i4 when String, URI response.headers[LOCATION] = uri.to_s 301 - when Fixnum + when Integer uri else :p3 @@ -313,7 +313,7 @@ def k5 when String, URI response.headers[LOCATION] = uri.to_s 301 - when Fixnum + when Integer uri else :l5 @@ -342,7 +342,7 @@ def l5 when String, URI response.headers[LOCATION] = uri.to_s 307 - when Fixnum + when Integer uri else :m5 @@ -422,13 +422,13 @@ def n11 request.disp_path = new_uri.path response.headers[LOCATION] = new_uri.to_s result = accept_helper - return result if Fixnum === result + return result if Integer === result end else case result = resource.process_post when true encode_body_if_set - when Fixnum + when Integer return result else raise InvalidResource, t('process_post_invalid', :result => result.inspect) @@ -456,7 +456,7 @@ def o14 409 else res = accept_helper - (Fixnum === res) ? res : :p11 + (Integer === res) ? res : :p11 end end @@ -473,7 +473,7 @@ def o18 content_type = metadata[CONTENT_TYPE] handler = resource.content_types_provided.find {|ct, _| content_type.type_matches?(MediaType.parse(ct)) }.last result = resource.send(handler) - if Fixnum === result + if Integer === result result else response.body = result @@ -501,7 +501,7 @@ def p3 409 else res = accept_helper - (Fixnum === res) ? res : :p11 + (Integer === res) ? res : :p11 end end diff --git a/lib/webmachine/decision/fsm.rb b/lib/webmachine/decision/fsm.rb index e128e961..d4cc662d 100644 --- a/lib/webmachine/decision/fsm.rb +++ b/lib/webmachine/decision/fsm.rb @@ -29,7 +29,7 @@ def run trace_decision(state) result = handle_exceptions { send(state) } case result - when Fixnum # Response code + when Integer # Response code respond(result) break when Symbol # Next state diff --git a/lib/webmachine/decision/helpers.rb b/lib/webmachine/decision/helpers.rb index 046e1497..f445175a 100644 --- a/lib/webmachine/decision/helpers.rb +++ b/lib/webmachine/decision/helpers.rb @@ -95,7 +95,7 @@ def add_caching_headers # is a String or IO with known size. def body_is_fixed_length? response.body.respond_to?(:bytesize) && - Fixnum === response.body.bytesize + Integer === response.body.bytesize end end # module Helpers end # module Decision diff --git a/lib/webmachine/dispatcher/route.rb b/lib/webmachine/dispatcher/route.rb index 9033733e..8b1ff410 100644 --- a/lib/webmachine/dispatcher/route.rb +++ b/lib/webmachine/dispatcher/route.rb @@ -103,7 +103,7 @@ def apply(request) # accumulating variable bindings. # @param [Array] tokens the list of path segments # @param [Hash] bindings where path bindings will be stored - # @return [Fixnum, Array, false] either the depth + # @return [Integer, Array, false] either the depth # that the path matched at, the depth and tokens matched by # {MATCH_ALL}, or false if it didn't match. def bind(tokens, bindings) diff --git a/lib/webmachine/errors.rb b/lib/webmachine/errors.rb index e25ac53f..c3aba361 100644 --- a/lib/webmachine/errors.rb +++ b/lib/webmachine/errors.rb @@ -9,7 +9,7 @@ module Webmachine # Renders a standard error message body for the response. The # standard messages are defined in localization files. - # @param [Fixnum] code the response status code + # @param [Integer] code the response status code # @param [Request] req the request object # @param [Response] req the response object # @param [Hash] options keys to override the defaults when rendering diff --git a/lib/webmachine/resource/callbacks.rb b/lib/webmachine/resource/callbacks.rb index 596aa215..99dc894d 100644 --- a/lib/webmachine/resource/callbacks.rb +++ b/lib/webmachine/resource/callbacks.rb @@ -103,7 +103,7 @@ def valid_content_headers?(content_headers = nil) # If the entity length on PUT or POST is invalid, this should # return false, which will result in a '413 Request Entity Too # Large' response. Defaults to true. - # @param [Fixnum] length the size of the request body (entity) + # @param [Integer] length the size of the request body (entity) # @return [true,false] Whether the body is a valid length (not too # large) # @api callback @@ -192,7 +192,7 @@ def base_uri # If post_is_create? returns false, then this will be called to # process any POST request. If it succeeds, it should return true. - # @return [true,false,Fixnum] Whether the POST was successfully + # @return [true,false,Integer] Whether the POST was successfully # processed, or an alternate response code # @api callback def process_post diff --git a/lib/webmachine/response.rb b/lib/webmachine/response.rb index 1fe12153..f1812259 100644 --- a/lib/webmachine/response.rb +++ b/lib/webmachine/response.rb @@ -4,7 +4,7 @@ class Response # @return [HeaderHash] Response headers that will be sent to the client attr_reader :headers - # @return [Fixnum] The HTTP status code of the response + # @return [Integer] The HTTP status code of the response attr_accessor :code # @return [String, #each] The response body diff --git a/lib/webmachine/streaming/io_encoder.rb b/lib/webmachine/streaming/io_encoder.rb index 615eb6ba..4c058f97 100644 --- a/lib/webmachine/streaming/io_encoder.rb +++ b/lib/webmachine/streaming/io_encoder.rb @@ -39,7 +39,7 @@ def to_io # Returns the length of the IO stream, if known. Returns nil if # the stream uses an encoder or charsetter that might modify the # length of the stream, or the stream size is unknown. - # @return [Fixnum] the size, in bytes, of the underlying IO, or + # @return [Integer] the size, in bytes, of the underlying IO, or # nil if unsupported def size if is_unencoded? From c336cf4c9d7c9cf2fd22898c808a90dd5ce6de71 Mon Sep 17 00:00:00 2001 From: 0xAB <0xAB@protonmail.com> Date: Tue, 22 Aug 2017 04:33:27 +0100 Subject: [PATCH 066/122] Extend exception handling support. After this commit, the following scenarios are covered in addition to the existing rescueable exceptions: class Resource < Webmachine::Resource def resource_exists? require 'foo' end def handle_exception(e) Airbrake.notify(e) end end class Resource < Webmachine::Resource ThirdPartyLibException = Class.new(Exception) def resource_exists? raise ThirdPartyLibException, "error by some third party lib we dont control" end def handle_exception(e) Airbrake.notify(e) end end The following exceptions are not rescueable, by default: Webmachine::MalformedRequest, SystemExit, SignalException, & NoMemoryError. However, this is now configurable: class Resource < Webmachine::Resource Webmachine::RescueableException.add(Webmachine::MalformedRequest) def handle_exception(e) # Now we can add custom handlers for Webmachine::MalformedRequest. # Formely not possible to customize how this exception is handled. end end --- lib/webmachine/decision/fsm.rb | 7 ++- lib/webmachine/rescueable_exception.rb | 62 ++++++++++++++++++++ spec/spec_helper.rb | 8 +++ spec/webmachine/decision/fsm_spec.rb | 40 +++++++++---- spec/webmachine/rescueable_exception_spec.rb | 15 +++++ 5 files changed, 116 insertions(+), 16 deletions(-) create mode 100644 lib/webmachine/rescueable_exception.rb create mode 100644 spec/webmachine/rescueable_exception_spec.rb diff --git a/lib/webmachine/decision/fsm.rb b/lib/webmachine/decision/fsm.rb index d4cc662d..cc00fcee 100644 --- a/lib/webmachine/decision/fsm.rb +++ b/lib/webmachine/decision/fsm.rb @@ -2,6 +2,7 @@ require 'webmachine/trace' require 'webmachine/translation' require 'webmachine/constants' +require 'webmachine/rescueable_exception' module Webmachine module Decision @@ -48,12 +49,12 @@ def run def handle_exceptions yield + rescue Webmachine::RescueableException => e + resource.handle_exception(e) + 500 rescue MalformedRequest => e Webmachine.render_error(400, request, response, :message => e.message) 400 - rescue => e - resource.handle_exception(e) - 500 end def respond(code, headers={}) diff --git a/lib/webmachine/rescueable_exception.rb b/lib/webmachine/rescueable_exception.rb new file mode 100644 index 00000000..33b78309 --- /dev/null +++ b/lib/webmachine/rescueable_exception.rb @@ -0,0 +1,62 @@ +module Webmachine::RescueableException + require_relative 'errors' + require 'set' + + UNRESCUEABLE_DEFAULTS = [ + Webmachine::MalformedRequest, + NoMemoryError, SystemExit, SignalException + ].freeze + + UNRESCUEABLE = Set.new UNRESCUEABLE_DEFAULTS.dup + private_constant :UNRESCUEABLE + + def self.===(e) + case e + when *UNRESCUEABLE then false + else true + end + end + + # + # Remove modifications to Webmachine::RescueableException. + # Restores default list of unrescue-able exceptions, + # + # @return [nil] + # + def self.default! + UNRESCUEABLE.replace Set.new(UNRESCUEABLE_DEFAULTS.dup) + nil + end + + # + # @return [Array] + # Returns an Array of exceptions that will not be + # rescued by {Webmachine::Resource#handle_exception}. + # + def self.unrescueables + UNRESCUEABLE.to_a + end + + # + # Add a variable number of exceptions that should be rescued by + # {Webmachine::Resource#handle_exception}. See {UNRESCUEABLE_DEFAULTS} + # for a list of exceptions that are not caught by default. + # + # @param (see #remove) + # + def self.add(*exceptions) + exceptions.each{|e| UNRESCUEABLE.delete(e)} + end + + # + # Remove a variable number ofexceptions from being rescued by + # {Webmachine::Resource#handle_exception}. See {UNRESCUEABLE_DEFAULTS} + # for a list of exceptions that are not caught by default. + # + # @param [Exception] *exceptions + # A subclass of Exception. + # + def self.remove(*exceptions) + exceptions.each{|e| UNRESCUEABLE.add(e)} + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index abc5000e..69c09678 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -18,6 +18,14 @@ def add(severity, message=nil, progname=nil, &block) config.order = :random end + config.before :each do + Webmachine::RescueableException.remove(RSpec::Mocks::MockExpectationError) + end + + config.after :each do + Webmachine::RescueableException.default! + end + config.before(:suite) do options = { :Logger => NullLogger.new(STDERR), diff --git a/spec/webmachine/decision/fsm_spec.rb b/spec/webmachine/decision/fsm_spec.rb index 09491f47..3e3ac8ce 100644 --- a/spec/webmachine/decision/fsm_spec.rb +++ b/spec/webmachine/decision/fsm_spec.rb @@ -13,24 +13,38 @@ end describe 'handling of exceptions from decision methods' do - let(:exception) { Exception.new } - - before do - allow(subject).to receive(Webmachine::Decision::Flow::START) { raise exception } + let(:unrescueable_exceptions) do + Webmachine::RescueableException::UNRESCUEABLE end - it 'does not handle the exception' do - expect { subject.run }.to raise_error exception - end + describe "rescueable exceptions" do + it 'does rescue Exception' do + allow(subject).to receive(Webmachine::Decision::Flow::START) { raise(Exception) } + expect(resource).to receive(:handle_exception).with instance_of(Exception) + expect { subject.run }.to_not raise_error + end - it 'does not call resource.handle_exception' do - expect(resource).to_not receive(:handle_exception) - run_with_exception + it 'does rescue a failed require' do + allow(subject).to receive(Webmachine::Decision::Flow::START) { require 'laterequire' } + expect(resource).to receive(:handle_exception).with instance_of(LoadError) + expect { subject.run }.to_not raise_error + end end - it 'does not call resource.finish_request' do - expect(resource).to_not receive(:finish_request) - run_with_exception + describe "unrescueable exceptions" do + shared_examples "unrescueable" do |e| + specify "#{e} is not rescued" do + allow(subject).to receive(Webmachine::Decision::Flow::START) {raise(e)} + expect(resource).to_not receive(:handle_exception).with instance_of(e) + expect { subject.run }.to raise_error(e) + end + end + eary = Webmachine::RescueableException::UNRESCUEABLE_DEFAULTS - [ + Webmachine::MalformedRequest, # Webmachine rescues by default, so it won't re-raise. + SignalException # Requires raise in form 'raise SignalException, "SIGSOMESIGNAL"'. + # Haven't found a good no-op signal to use here. + ] + eary.each{|e| include_examples "unrescueable", e} end end diff --git a/spec/webmachine/rescueable_exception_spec.rb b/spec/webmachine/rescueable_exception_spec.rb new file mode 100644 index 00000000..00ca5179 --- /dev/null +++ b/spec/webmachine/rescueable_exception_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' +RSpec.describe Webmachine::RescueableException do + before { described_class.default! } + + describe ".unrescueables" do + specify "returns an array of unrescueable exceptions" do + expect(described_class.unrescueables).to eq(described_class::UNRESCUEABLE_DEFAULTS) + end + + specify "returns an array of unrescueable exceptions, with custom exceptions added" do + described_class.remove(Exception) + expect(described_class.unrescueables).to eq(described_class::UNRESCUEABLE_DEFAULTS.dup.concat([Exception])) + end + end +end From 219f737aacc01238fdde40350267a9927655b03b Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Fri, 8 Sep 2017 07:57:10 +1000 Subject: [PATCH 067/122] test: fixed failing exception handling test As described in https://github.com/webmachine/webmachine-ruby/pull/247#issuecomment-327691038 --- spec/webmachine/decision/fsm_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/webmachine/decision/fsm_spec.rb b/spec/webmachine/decision/fsm_spec.rb index 3e3ac8ce..f3de2ff8 100644 --- a/spec/webmachine/decision/fsm_spec.rb +++ b/spec/webmachine/decision/fsm_spec.rb @@ -93,9 +93,10 @@ end describe 'handling of exceptions from resource.finish_request' do - let(:exception) { Exception.new } + let(:exception) { Class.new(Exception).new } before do + Webmachine::RescueableException.remove(exception) allow(resource).to receive(:finish_request) { raise exception } end From 72db4a8e0c9d79aa150b2178271b52b525ad9e15 Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Fri, 8 Sep 2017 08:02:28 +1000 Subject: [PATCH 068/122] chore: correct spelling of 'rescuable' As pointed out by @r-obert in https://github.com/webmachine/webmachine-ruby/pull/247#issuecomment-327765831 --- lib/webmachine/decision/fsm.rb | 2 +- lib/webmachine/rescueable_exception.rb | 30 ++++++++++---------- spec/spec_helper.rb | 4 +-- spec/webmachine/decision/fsm_spec.rb | 14 ++++----- spec/webmachine/rescueable_exception_spec.rb | 12 ++++---- 5 files changed, 31 insertions(+), 31 deletions(-) diff --git a/lib/webmachine/decision/fsm.rb b/lib/webmachine/decision/fsm.rb index cc00fcee..f3252551 100644 --- a/lib/webmachine/decision/fsm.rb +++ b/lib/webmachine/decision/fsm.rb @@ -49,7 +49,7 @@ def run def handle_exceptions yield - rescue Webmachine::RescueableException => e + rescue Webmachine::RescuableException => e resource.handle_exception(e) 500 rescue MalformedRequest => e diff --git a/lib/webmachine/rescueable_exception.rb b/lib/webmachine/rescueable_exception.rb index 33b78309..297ac7d6 100644 --- a/lib/webmachine/rescueable_exception.rb +++ b/lib/webmachine/rescueable_exception.rb @@ -1,30 +1,30 @@ -module Webmachine::RescueableException +module Webmachine::RescuableException require_relative 'errors' require 'set' - UNRESCUEABLE_DEFAULTS = [ + UNRESCUABLE_DEFAULTS = [ Webmachine::MalformedRequest, NoMemoryError, SystemExit, SignalException ].freeze - UNRESCUEABLE = Set.new UNRESCUEABLE_DEFAULTS.dup - private_constant :UNRESCUEABLE + UNRESCUABLE = Set.new UNRESCUABLE_DEFAULTS.dup + private_constant :UNRESCUABLE def self.===(e) case e - when *UNRESCUEABLE then false + when *UNRESCUABLE then false else true end end # - # Remove modifications to Webmachine::RescueableException. - # Restores default list of unrescue-able exceptions, + # Remove modifications to Webmachine::RescuableException. + # Restores default list of unrescue-able exceptions. # # @return [nil] # def self.default! - UNRESCUEABLE.replace Set.new(UNRESCUEABLE_DEFAULTS.dup) + UNRESCUABLE.replace Set.new(UNRESCUABLE_DEFAULTS.dup) nil end @@ -33,30 +33,30 @@ def self.default! # Returns an Array of exceptions that will not be # rescued by {Webmachine::Resource#handle_exception}. # - def self.unrescueables - UNRESCUEABLE.to_a + def self.UNRESCUABLEs + UNRESCUABLE.to_a end # # Add a variable number of exceptions that should be rescued by - # {Webmachine::Resource#handle_exception}. See {UNRESCUEABLE_DEFAULTS} + # {Webmachine::Resource#handle_exception}. See {UNRESCUABLE_DEFAULTS} # for a list of exceptions that are not caught by default. # # @param (see #remove) # def self.add(*exceptions) - exceptions.each{|e| UNRESCUEABLE.delete(e)} + exceptions.each{|e| UNRESCUABLE.delete(e)} end # - # Remove a variable number ofexceptions from being rescued by - # {Webmachine::Resource#handle_exception}. See {UNRESCUEABLE_DEFAULTS} + # Remove a variable number of exceptions from being rescued by + # {Webmachine::Resource#handle_exception}. See {UNRESCUABLE_DEFAULTS} # for a list of exceptions that are not caught by default. # # @param [Exception] *exceptions # A subclass of Exception. # def self.remove(*exceptions) - exceptions.each{|e| UNRESCUEABLE.add(e)} + exceptions.each{|e| UNRESCUABLE.add(e)} end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 69c09678..20a161a6 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -19,11 +19,11 @@ def add(severity, message=nil, progname=nil, &block) end config.before :each do - Webmachine::RescueableException.remove(RSpec::Mocks::MockExpectationError) + Webmachine::RescuableException.remove(RSpec::Mocks::MockExpectationError) end config.after :each do - Webmachine::RescueableException.default! + Webmachine::RescuableException.default! end config.before(:suite) do diff --git a/spec/webmachine/decision/fsm_spec.rb b/spec/webmachine/decision/fsm_spec.rb index f3de2ff8..900f3398 100644 --- a/spec/webmachine/decision/fsm_spec.rb +++ b/spec/webmachine/decision/fsm_spec.rb @@ -13,8 +13,8 @@ end describe 'handling of exceptions from decision methods' do - let(:unrescueable_exceptions) do - Webmachine::RescueableException::UNRESCUEABLE + let(:UNRESCUABLE_exceptions) do + Webmachine::RescuableException::UNRESCUABLE end describe "rescueable exceptions" do @@ -31,20 +31,20 @@ end end - describe "unrescueable exceptions" do - shared_examples "unrescueable" do |e| + describe "UNRESCUABLE exceptions" do + shared_examples "UNRESCUABLE" do |e| specify "#{e} is not rescued" do allow(subject).to receive(Webmachine::Decision::Flow::START) {raise(e)} expect(resource).to_not receive(:handle_exception).with instance_of(e) expect { subject.run }.to raise_error(e) end end - eary = Webmachine::RescueableException::UNRESCUEABLE_DEFAULTS - [ + eary = Webmachine::RescuableException::UNRESCUABLE_DEFAULTS - [ Webmachine::MalformedRequest, # Webmachine rescues by default, so it won't re-raise. SignalException # Requires raise in form 'raise SignalException, "SIGSOMESIGNAL"'. # Haven't found a good no-op signal to use here. ] - eary.each{|e| include_examples "unrescueable", e} + eary.each{|e| include_examples "UNRESCUABLE", e} end end @@ -96,7 +96,7 @@ let(:exception) { Class.new(Exception).new } before do - Webmachine::RescueableException.remove(exception) + Webmachine::RescuableException.remove(exception) allow(resource).to receive(:finish_request) { raise exception } end diff --git a/spec/webmachine/rescueable_exception_spec.rb b/spec/webmachine/rescueable_exception_spec.rb index 00ca5179..819c3bad 100644 --- a/spec/webmachine/rescueable_exception_spec.rb +++ b/spec/webmachine/rescueable_exception_spec.rb @@ -1,15 +1,15 @@ require 'spec_helper' -RSpec.describe Webmachine::RescueableException do +RSpec.describe Webmachine::RescuableException do before { described_class.default! } - describe ".unrescueables" do - specify "returns an array of unrescueable exceptions" do - expect(described_class.unrescueables).to eq(described_class::UNRESCUEABLE_DEFAULTS) + describe ".UNRESCUABLEs" do + specify "returns an array of UNRESCUABLE exceptions" do + expect(described_class.UNRESCUABLEs).to eq(described_class::UNRESCUABLE_DEFAULTS) end - specify "returns an array of unrescueable exceptions, with custom exceptions added" do + specify "returns an array of UNRESCUABLE exceptions, with custom exceptions added" do described_class.remove(Exception) - expect(described_class.unrescueables).to eq(described_class::UNRESCUEABLE_DEFAULTS.dup.concat([Exception])) + expect(described_class.UNRESCUABLEs).to eq(described_class::UNRESCUABLE_DEFAULTS.dup.concat([Exception])) end end end From 50d8b74aed86d31668c08110c5e58c0bf3bd5150 Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Fri, 8 Sep 2017 09:21:18 +1000 Subject: [PATCH 069/122] docs: add RELEASING.md --- RELEASING.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 RELEASING.md diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 00000000..a5a60c0a --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,21 @@ +1. Open `CHANGELOG.md` and summarize the changes made since the last release (hopefully better than the individual commit messages). The history can be grabbed with a simple git command (assuming the last version was 1.3.0: + + $ git log --pretty=format:' * %s' v1.3.0..HEAD + +2. Edit the version in `lib/webmachine/version.rb` according to semantic versioning rules. +3. Commit both files. + + $ git add CHANGELOG.md lib/webmachine/version.rb + $ git commit -m "chore(release): version 1.3.1" + +4. Release the gem. + + $ bundle exec rake release + +5. If this is a new major or minor release, push a new stable branch, otherwise merge the commit into the stable branch (or master, depending on where you made the commit). + + $ git push origin HEAD:1.3-stable + # or + $ git checkout 1.3-stable; git merge master; git push origin; git checkout master + +6. YOU'RE DONE! From c3b0a57e81d07ea395949299ec434ddd564f1398 Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Fri, 8 Sep 2017 09:22:38 +1000 Subject: [PATCH 070/122] chore(release): version 1.5.0 --- CHANGELOG.md | 7 +++++++ lib/webmachine/version.rb | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1358cc73..664377e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ ### HEAD +### 1.5.0 September 8, 2017 +* Removed Fixnum/Integer deprecation warnings in Ruby 2.4 +* Fixed multiple cookie setting code +* Added support for named captures +* Improved logic for determining which errors are 'rescuable' by Webmachine, + and which are 'unhandlable'. + ### 1.4.0 March 20, 2015 * Added RackMapped adapter which allows Webmachine apps to be mounted diff --git a/lib/webmachine/version.rb b/lib/webmachine/version.rb index 5c475f85..58a9142b 100644 --- a/lib/webmachine/version.rb +++ b/lib/webmachine/version.rb @@ -1,6 +1,6 @@ module Webmachine # Library version - VERSION = "1.4.0".freeze + VERSION = "1.5.0".freeze # String for use in "Server" HTTP response header, which includes # the {VERSION}. From 0b5c0d04e497e52dc2f4e778abca4805f9c78c66 Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Fri, 8 Sep 2017 09:23:07 +1000 Subject: [PATCH 071/122] docs: updated RELEASING.md --- RELEASING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASING.md b/RELEASING.md index a5a60c0a..4642cb2d 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -6,7 +6,7 @@ 3. Commit both files. $ git add CHANGELOG.md lib/webmachine/version.rb - $ git commit -m "chore(release): version 1.3.1" + $ git commit -m "chore(release): version $(ruby -r ./lib/webmachine/version.rb -e "puts Webmachine::VERSION")" && git push 4. Release the gem. From c5a556c1628ed384b2b96bee79aeb0a954fbd016 Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Fri, 8 Sep 2017 09:48:50 +1000 Subject: [PATCH 072/122] docs(README): add gem version badge --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 935b215a..147df857 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -# webmachine for Ruby [![Build Status](https://travis-ci.org/webmachine/webmachine-ruby.svg)](https://travis-ci.org/webmachine/webmachine-ruby) +# webmachine for Ruby + [![Gem Version](https://badge.fury.io/rb/webmachine.svg)](https://badge.fury.io/rb/webmachine) + [![Build Status](https://travis-ci.org/webmachine/webmachine-ruby.svg)](https://travis-ci.org/webmachine/webmachine-ruby) webmachine-ruby is a port of [Webmachine](https://github.com/basho/webmachine), which is written in From 686f4b40adfcc98d13999edbe058989744cdbad2 Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Mon, 17 Dec 2018 11:31:05 +1100 Subject: [PATCH 073/122] test: correct usage of rspec expectation --- spec/webmachine/decision/fsm_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/webmachine/decision/fsm_spec.rb b/spec/webmachine/decision/fsm_spec.rb index 900f3398..957b841b 100644 --- a/spec/webmachine/decision/fsm_spec.rb +++ b/spec/webmachine/decision/fsm_spec.rb @@ -106,7 +106,7 @@ end it 'does not call resource.finish_request again' do - expect(resource).to_not receive(:finish_request).once { raise } + expect(resource).to receive(:finish_request).once run_with_exception end end From 8671f23e50192e0c55e5a136614c64bf88d51796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Pacana?= Date: Sun, 16 Dec 2018 22:47:50 +0100 Subject: [PATCH 074/122] Up-to-date stable Rubies. * dropped EOL Ruby 2.2.2 * added (still) current 2.5.3 release * bumped to latest patch releases --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7c9b386f..e8b74734 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ rvm: - - 2.2.2 - - 2.3.0 - - 2.4.1 + - 2.3.8 + - 2.4.5 + - 2.5.3 - ruby-head - jruby - rbx-2 From cbaa9b8700666925e86c744f4bca41b69f2021ae Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Wed, 24 Apr 2019 19:29:35 +1000 Subject: [PATCH 075/122] feat: make rack env available on the webmachine request when using a rack adapter --- lib/webmachine/adapters/rack.rb | 14 ++++++++++++-- lib/webmachine/spec/test_resource.rb | 7 ++++++- spec/webmachine/adapters/rack_spec.rb | 5 +++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/webmachine/adapters/rack.rb b/lib/webmachine/adapters/rack.rb index 54265865..50c7a0c8 100644 --- a/lib/webmachine/adapters/rack.rb +++ b/lib/webmachine/adapters/rack.rb @@ -106,15 +106,25 @@ def base_uri(rack_req) private def build_webmachine_request(rack_req, headers) - Webmachine::Request.new(rack_req.request_method, + RackRequest.new(rack_req.request_method, rack_req.url, headers, RequestBody.new(rack_req), routing_tokens(rack_req), - base_uri(rack_req) + base_uri(rack_req), + rack_req.env ) end + class RackRequest < Webmachine::Request + attr_reader :env + + def initialize(method, uri, headers, body, routing_tokens, base_uri, env) + super(method, uri, headers, body, routing_tokens, base_uri) + @env = env + end + end + class RackResponse ONE_FIVE = '1.5'.freeze diff --git a/lib/webmachine/spec/test_resource.rb b/lib/webmachine/spec/test_resource.rb index e8d2d00e..92895d83 100644 --- a/lib/webmachine/spec/test_resource.rb +++ b/lib/webmachine/spec/test_resource.rb @@ -19,7 +19,8 @@ def content_types_provided ["test/response.fiberbody", :to_fiber], ["test/response.iobody", :to_io_body], ["test/response.cookies", :to_cookies], - ["test/response.request_uri", :to_request_uri] + ["test/response.request_uri", :to_request_uri], + ["test/response.rack_env", :to_rack_env] ] end @@ -75,5 +76,9 @@ def to_cookies def to_request_uri request.uri.to_s end + + def to_rack_env + request.env.to_json + end end end diff --git a/spec/webmachine/adapters/rack_spec.rb b/spec/webmachine/adapters/rack_spec.rb index f0e32449..c7771910 100644 --- a/spec/webmachine/adapters/rack_spec.rb +++ b/spec/webmachine/adapters/rack_spec.rb @@ -53,5 +53,10 @@ rack_response = get "test", nil, {"HTTP_ACCEPT" => "test/response.request_uri"} expect(rack_response.body).to eq "http://example.org/test" end + + it "provides the rack env on the request" do + rack_response = get "test", nil, {"HTTP_ACCEPT" => "test/response.rack_env"} + expect(JSON.parse(rack_response.body).keys).to include "rack.input" + end end end From 37bbd9be0fce6cb6871e7b2cc1223843a615a993 Mon Sep 17 00:00:00 2001 From: rg-3 <1xab@protonmail.com> Date: Wed, 15 May 2019 15:46:48 +0100 Subject: [PATCH 076/122] Run tests with Ruby 2.6.3 on travis-ci. Add ruby 2.6.3 to the list of rubies that run the test suite. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index e8b74734..f1c4fabb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ rvm: - 2.3.8 - 2.4.5 - 2.5.3 + - 2.6.3 - ruby-head - jruby - rbx-2 From fdb694b0d3981397792f511b3fd3a104b79e2408 Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Wed, 12 Feb 2020 07:59:14 +1100 Subject: [PATCH 077/122] docs: update documentation for using post to perform a task (#254) --- documentation/examples.md | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/documentation/examples.md b/documentation/examples.md index d61cfaa4..c7c4d81d 100644 --- a/documentation/examples.md +++ b/documentation/examples.md @@ -92,13 +92,20 @@ end ``` # POST to perform a task -* Override `allowed_methods` and `process_post`. Put all the code to be executed in `process_post`. -* `process_post` must return true, or the HTTP response code -* Response headers like Content-Type will need to be set manually. +* Override `allowed_methods`, `process_post`, `content_types_accepted` (if the request must have a certain content type) and `content_types_provided` (if the response has a content type). +* Rather than providing a method handler in the `content_type_provided` mappings, put all the code to be executed in `process_post`. +* `process_post` must return true, or the HTTP response code. ```ruby class DispatchOrderResource < Webmachine::Resource + def content_types_accepted + [["application/json"]] + end + def content_types_provided + [["application/json"]] + end + def allowed_methods ["POST"] end @@ -108,9 +115,8 @@ class DispatchOrderResource < Webmachine::Resource end def process_post - @order.dispatch - response.headers['Content-Type'] = 'text/plain' - response.body = "Successfully dispatched order #{id}" + @order.dispatch(params['some_param']) + response.body = { message: "Successfully dispatched order #{id}" }.to_json true end @@ -119,6 +125,10 @@ class DispatchOrderResource < Webmachine::Resource def id request.path_info[:id] end + + def params + JSON.parse(request.body.to_s) + end end ``` From 400b5ef68b9a54d0e7901b98c84a6c0fb9aac674 Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Tue, 18 Feb 2020 20:27:05 +1100 Subject: [PATCH 078/122] docs: correct docs for post to perform a task (#255) --- documentation/examples.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/documentation/examples.md b/documentation/examples.md index c7c4d81d..3891cc7d 100644 --- a/documentation/examples.md +++ b/documentation/examples.md @@ -92,20 +92,16 @@ end ``` # POST to perform a task -* Override `allowed_methods`, `process_post`, `content_types_accepted` (if the request must have a certain content type) and `content_types_provided` (if the response has a content type). +* Override `allowed_methods`, `process_post`, and `content_types_provided` (if the response has a content type). * Rather than providing a method handler in the `content_type_provided` mappings, put all the code to be executed in `process_post`. * `process_post` must return true, or the HTTP response code. ```ruby class DispatchOrderResource < Webmachine::Resource - def content_types_accepted - [["application/json"]] - end - def content_types_provided [["application/json"]] end - + def allowed_methods ["POST"] end @@ -125,7 +121,7 @@ class DispatchOrderResource < Webmachine::Resource def id request.path_info[:id] end - + def params JSON.parse(request.body.to_s) end From 818f9e4e46a90df48afab3095f4f84841083eb26 Mon Sep 17 00:00:00 2001 From: Sean Cribbs Date: Wed, 18 Mar 2020 10:31:30 -0500 Subject: [PATCH 079/122] Rename SPLIT_SEMI constant to SPLIT_COMMA I was reviewing the conneg code to refresh my memory on how subtype params matching worked and found this misnamed constant. The Accept header is never split on semi-colons (which are parts of the media type) but on commas. --- lib/webmachine/constants.rb | 4 ++-- lib/webmachine/decision/conneg.rb | 6 +++--- lib/webmachine/decision/flow.rb | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/webmachine/constants.rb b/lib/webmachine/constants.rb index 9f387939..8541cc65 100644 --- a/lib/webmachine/constants.rb +++ b/lib/webmachine/constants.rb @@ -59,8 +59,8 @@ # Charset string CHARSET = 'Charset'.freeze - # Semicolon split match - SPLIT_SEMI = /\s*,\s*/.freeze + # Comma split match + SPLIT_COMMA = /\s*,\s*/.freeze # Star Character STAR = '*'.freeze diff --git a/lib/webmachine/decision/conneg.rb b/lib/webmachine/decision/conneg.rb index e4507a6b..30e85b05 100644 --- a/lib/webmachine/decision/conneg.rb +++ b/lib/webmachine/decision/conneg.rb @@ -14,7 +14,7 @@ module Conneg # appropriate media type. # @api private def choose_media_type(provided, header) - types = Array(header).map{|h| h.split(SPLIT_SEMI) }.flatten + types = Array(header).map{|h| h.split(SPLIT_COMMA) }.flatten requested = MediaTypeList.build(types) provided = provided.map do |p| # normalize_provided MediaType.parse(p) @@ -57,7 +57,7 @@ def choose_charset(provided, header) # @api private def choose_language(provided, header) if provided && !provided.empty? - requested = PriorityList.build(header.split(SPLIT_SEMI)) + requested = PriorityList.build(header.split(SPLIT_COMMA)) star_priority = requested.priority_of(STAR) any_ok = star_priority && star_priority > 0.0 accepted = requested.find do |priority, range| @@ -99,7 +99,7 @@ def language_match(range, tag) # @api private def do_choose(choices, header, default) choices = choices.dup.map {|s| s.downcase } - accepted = PriorityList.build(header.split(SPLIT_SEMI)) + accepted = PriorityList.build(header.split(SPLIT_COMMA)) default_priority = accepted.priority_of(default) star_priority = accepted.priority_of(STAR) default_ok = (default_priority.nil? && star_priority != 0.0) || default_priority diff --git a/lib/webmachine/decision/flow.rb b/lib/webmachine/decision/flow.rb index c05c68d9..87d264dd 100644 --- a/lib/webmachine/decision/flow.rb +++ b/lib/webmachine/decision/flow.rb @@ -245,7 +245,7 @@ def g9 # ETag in If-Match def g11 - request_etags = request.if_match.split(SPLIT_SEMI).map {|etag| ETag.new(etag) } + request_etags = request.if_match.split(SPLIT_COMMA).map {|etag| ETag.new(etag) } request_etags.include?(ETag.new(resource.generate_etag)) ? :h10 : 412 end @@ -327,7 +327,7 @@ def k7 # Etag in if-none-match? def k13 - request_etags = request.if_none_match.split(SPLIT_SEMI).map {|etag| ETag.new(etag) } + request_etags = request.if_none_match.split(SPLIT_COMMA).map {|etag| ETag.new(etag) } resource_etag = resource.generate_etag if resource_etag && request_etags.include?(ETag.new(resource_etag)) :j18 From 1fb6daab05050970390421a95eb5f3b0d9b5d114 Mon Sep 17 00:00:00 2001 From: Ronald Holshausen Date: Wed, 23 Dec 2020 13:50:24 +1100 Subject: [PATCH 080/122] fix: implement rfc3986 Percent-Encoding decoder --- lib/webmachine/dispatcher/route.rb | 16 +++++++++++++- .../dispatcher/rfc3986_percent_decode_spec.rb | 22 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 spec/webmachine/dispatcher/rfc3986_percent_decode_spec.rb diff --git a/lib/webmachine/dispatcher/route.rb b/lib/webmachine/dispatcher/route.rb index 8b1ff410..cd15e4a8 100644 --- a/lib/webmachine/dispatcher/route.rb +++ b/lib/webmachine/dispatcher/route.rb @@ -134,7 +134,7 @@ def bind(tokens, bindings) return false end when Symbol === spec.first - bindings[spec.first] = URI.decode(tokens.first) + bindings[spec.first] = Route.rfc3986_percent_decode(tokens.first) when spec.first == tokens.first else return false @@ -145,6 +145,20 @@ def bind(tokens, bindings) end end + # Decode a string using the scheme described in RFC 3986 2.1. Percent-Encoding (https://www.ietf.org/rfc/rfc3986.txt) + def self.rfc3986_percent_decode(value) + s = StringScanner.new(value) + result = '' + until s.eos? + encoded_val = s.scan(/%([0-9a-fA-F]){2}/) + result << if encoded_val.nil? + s.getch + else + [encoded_val[1..-1]].pack('H*') + end + end + result + end end # class Route end # module Dispatcher end # module Webmachine diff --git a/spec/webmachine/dispatcher/rfc3986_percent_decode_spec.rb b/spec/webmachine/dispatcher/rfc3986_percent_decode_spec.rb new file mode 100644 index 00000000..b2a0236e --- /dev/null +++ b/spec/webmachine/dispatcher/rfc3986_percent_decode_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe Webmachine::Dispatcher::Route do + describe '#rfc3986_percent_decode' do + def call_subject(value) + Webmachine::Dispatcher::Route.rfc3986_percent_decode(value) + end + + it 'does not change un-encoded strings' do + expect(call_subject('this is a normal string, I think')).to eq 'this is a normal string, I think' + expect(call_subject('')).to eq '' + end + + it 'decodes percent encoded sequences' do + expect(call_subject('/tenants/esckimo+test%20%65')).to eq '/tenants/esckimo+test e' + end + + it 'leaves incorrectly encoded sequences as is' do + expect(call_subject('/tenants/esckimo+test%2%65')).to eq '/tenants/esckimo+test%2e' + end + end +end From c5ae5b1a755404d56aae15a5cbe849df44d2bba0 Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Thu, 11 Mar 2021 15:10:33 +1100 Subject: [PATCH 081/122] fix: replace missed URI.decode with new Route.rfc3986_percent_decode (#261) --- lib/webmachine/dispatcher/route.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/webmachine/dispatcher/route.rb b/lib/webmachine/dispatcher/route.rb index cd15e4a8..4a5bdfcb 100644 --- a/lib/webmachine/dispatcher/route.rb +++ b/lib/webmachine/dispatcher/route.rb @@ -120,7 +120,7 @@ def bind(tokens, bindings) when tokens.empty? return false when Regexp === spec.first - matches = spec.first.match URI.decode(tokens.first) + matches = spec.first.match Route.rfc3986_percent_decode(tokens.first) if matches if spec.first.named_captures.empty? bindings[:captures] = (bindings[:captures] || []) + matches.captures From 5de009d4b3236a771f86e551220d1ca93c8a3cbe Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Thu, 11 Mar 2021 15:12:57 +1100 Subject: [PATCH 082/122] chore: fix build (#260) * chore: lock down celluloid version to make the tests pass * chore: add test workflow for github actions * chore: remove .travis.yml --- .github/workflows/test.yml | 28 ++++++++++++++++++++++++++++ .travis.yml | 22 ---------------------- Gemfile | 2 ++ 3 files changed, 30 insertions(+), 22 deletions(-) create mode 100644 .github/workflows/test.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..64af68db --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,28 @@ +name: Test + +on: [push, pull_request] + +jobs: + test: + runs-on: "ubuntu-latest" + continue-on-error: ${{ matrix.experimental }} + strategy: + fail-fast: false + matrix: + ruby_version: ["2.3.8", "2.4.5", "2.5.3", "2.6.3", "2.7.2"] + experimental: [false] + include: + - ruby_version: "3.0" + experimental: true + - ruby_version: "ruby-head" + experimental: true + - ruby_version: "jruby-head" + experimental: true + + steps: + - uses: actions/checkout@v2 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby_version }} + - run: "bundle install" + - run: "bundle exec rspec spec/ -b" diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f1c4fabb..00000000 --- a/.travis.yml +++ /dev/null @@ -1,22 +0,0 @@ -rvm: - - 2.3.8 - - 2.4.5 - - 2.5.3 - - 2.6.3 - - ruby-head - - jruby - - rbx-2 - -matrix: - allow_failures: - - rvm: ruby-head - - rvm: jruby - - rvm: rbx-2 - -before_install: - - gem update --system - - gem update bundler - -bundler_args: --without guard docs - -script: bundle exec rspec spec/ -b diff --git a/Gemfile b/Gemfile index c94d7806..356617ee 100644 --- a/Gemfile +++ b/Gemfile @@ -12,11 +12,13 @@ group :test do gem "rspec-its", "~> 1.2" gem "rack", "~> 2.0" gem "rack-test", "~> 0.7" + gem "websocket_parser", "~>1.0" end group :webservers do gem 'reel', '~> 0.5.0' gem 'http', '~> 0.6.0' + gem 'celluloid', '0.17.4' # Refactors in 0.18.0 break the tests gem 'httpkit', :platform => [:mri, :rbx] end From 9a6ced4b10d3ee7ba403aa7ad7d6e32c6f1742ee Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Tue, 22 Jun 2021 10:16:24 +1000 Subject: [PATCH 083/122] chore(release): version 1.6.0 --- CHANGELOG.md | 7 +++++++ lib/webmachine/version.rb | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 664377e9..eec13fca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ ### HEAD +### 1.6.0 June 22, 2021 + +* fix: replace missed URI.decode with new Route.rfc3986_percent_decode (#261) +* fix: implement rfc3986 Percent-Encoding decoder +* feat: make rack env available on the webmachine request when using a rack adapter + ### 1.5.0 September 8, 2017 + * Removed Fixnum/Integer deprecation warnings in Ruby 2.4 * Fixed multiple cookie setting code * Added support for named captures diff --git a/lib/webmachine/version.rb b/lib/webmachine/version.rb index 58a9142b..02210c54 100644 --- a/lib/webmachine/version.rb +++ b/lib/webmachine/version.rb @@ -1,6 +1,6 @@ module Webmachine # Library version - VERSION = "1.5.0".freeze + VERSION = "1.6.0".freeze # String for use in "Server" HTTP response header, which includes # the {VERSION}. From a17691cd5c62a79ddf4a19ea5a741255077ff502 Mon Sep 17 00:00:00 2001 From: Russell Garner Date: Sun, 27 Jun 2021 00:34:10 +0100 Subject: [PATCH 084/122] chore: fix the build for ruby 3.0.x * Add webrick as a dev dependency webrick is no longer a bundled dependency for Ruby 3 and up. * Fix translation errors in Ruby 3.x Ruby 3 is stricter about hashes being used interchangeably with keyword arguments, and will give errors like: ArgumentError: wrong number of arguments (given 2, expected 0..1) Explicitly map options hash to positional argument with ** to fix * Replace Proc.new usage for Ruby 3 Ruby 3 no longer supports Proc.new without a block to mean "the block that was passed to this method". Use an explicit &block instead This commit does not fix as-notifications, on this line: https://github.com/bernd/as-notifications/blob/v1.0.0/lib/as/notifications/fanout.rb#L18 * Update as-notifications to 1.0.2 Since 1.0.2 is now compatible with Ruby 3.0, we have one spec we no longer have to use the Proc.new { } form with. Thanks Bernd! --- lib/webmachine/dispatcher/route.rb | 4 ++-- lib/webmachine/translation.rb | 2 +- webmachine.gemspec | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/webmachine/dispatcher/route.rb b/lib/webmachine/dispatcher/route.rb index 4a5bdfcb..0f4b82ee 100644 --- a/lib/webmachine/dispatcher/route.rb +++ b/lib/webmachine/dispatcher/route.rb @@ -58,7 +58,7 @@ class Route # @yield [req] an optional guard block # @yieldparam [Request] req the request object # @see Dispatcher#add_route - def initialize(path_spec, *args) + def initialize(path_spec, *args, &block) if args.last.is_a? Hash bindings = args.pop else @@ -67,7 +67,7 @@ def initialize(path_spec, *args) resource = args.pop guards = args - guards << Proc.new if block_given? + guards << block if block_given? warn t('match_all_symbol') if path_spec.include? MATCH_ALL_STR diff --git a/lib/webmachine/translation.rb b/lib/webmachine/translation.rb index eb0a932a..9d72c459 100644 --- a/lib/webmachine/translation.rb +++ b/lib/webmachine/translation.rb @@ -13,7 +13,7 @@ module Translation # variables to interpolate. # @return [String] the interpolated string def t(key, options={}) - ::I18n.t(key, options.merge(:scope => :webmachine)) + ::I18n.t(key, **options.merge(:scope => :webmachine)) end end end diff --git a/webmachine.gemspec b/webmachine.gemspec index 7a269f9c..d1c3d079 100644 --- a/webmachine.gemspec +++ b/webmachine.gemspec @@ -17,7 +17,9 @@ Gem::Specification.new do |gem| gem.add_runtime_dependency(%q, [">= 0.4.0"]) gem.add_runtime_dependency(%q) - gem.add_runtime_dependency(%q, ["~> 1.0"]) + gem.add_runtime_dependency(%q, [">= 1.0.2", "< 2.0"]) + + gem.add_development_dependency(%q, ["~> 1.7.0"]) ignores = File.read(".gitignore").split(/\r?\n/).reject{ |f| f =~ /^(#.+|\s*)$/ }.map {|f| Dir[f] }.flatten gem.files = (Dir['**/*','.gitignore'] - ignores).reject {|f| !File.file?(f) } From e87e2f9c9522ace88bcd42c40f0818618bcd6e37 Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Wed, 11 Jan 2023 22:44:57 +1100 Subject: [PATCH 085/122] CI: test against Ruby 3.1 --- .github/workflows/test.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 64af68db..406828d9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,20 +9,18 @@ jobs: strategy: fail-fast: false matrix: - ruby_version: ["2.3.8", "2.4.5", "2.5.3", "2.6.3", "2.7.2"] + ruby_version: ["2.3", "2.4", "2.5", "2.6", "2.7", "3.0", "3.1"] experimental: [false] include: - - ruby_version: "3.0" + - ruby_version: "3.2" experimental: true - ruby_version: "ruby-head" experimental: true - - ruby_version: "jruby-head" - experimental: true steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby_version }} - - run: "bundle install" + bundler-cache: true - run: "bundle exec rspec spec/ -b" From 10851c5ccaee05bbccef66fa11ec4f1567816d9b Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Wed, 11 Jan 2023 22:45:13 +1100 Subject: [PATCH 086/122] Format cookie 'Expires' timestamps as per RFC 2616 For reference: - https://www.rfc-editor.org/rfc/rfc2616#section-3.3.1 - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expires --- lib/webmachine/cookie.rb | 8 +++++--- spec/webmachine/cookie_spec.rb | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/webmachine/cookie.rb b/lib/webmachine/cookie.rb index 9d80e26e..b30535de 100644 --- a/lib/webmachine/cookie.rb +++ b/lib/webmachine/cookie.rb @@ -102,10 +102,12 @@ def to_s private + # Format timestamps for the 'Expires' portion of the cookie string, as per RFC 2822 and 2616. + # + # @see https://www.rfc-editor.org/rfc/rfc2616#section-3.3.1 + # @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expires def rfc2822(time) - wday = Time::RFC2822_DAY_NAME[time.wday] - mon = Time::RFC2822_MONTH_NAME[time.mon - 1] - time.strftime("#{wday}, %d-#{mon}-%Y %H:%M:%S GMT") + time.strftime('%a, %d %b %Y %T GMT') end if URI.respond_to?(:decode_www_form_component) and defined?(::Encoding) diff --git a/spec/webmachine/cookie_spec.rb b/spec/webmachine/cookie_spec.rb index ca2d66fc..217ff4bb 100644 --- a/spec/webmachine/cookie_spec.rb +++ b/spec/webmachine/cookie_spec.rb @@ -60,7 +60,7 @@ expect(str).to include "Path=/" expect(str).to include "Version=1" expect(str).to include "Max-Age=60" - expect(str).to include "Expires=Sun, 14-Mar-2010 03:14:00 GMT" + expect(str).to include "Expires=Sun, 14 Mar 2010 03:14:00 GMT" end end end From 5feb251888cb4323b66de783afc17a74fa145359 Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Sat, 14 Jan 2023 00:14:39 +1100 Subject: [PATCH 087/122] Remove Reel adapter The Reel project is no-longer actively maintained and the GitHub repository has been archived. --- Gemfile | 2 - documentation/adapters.md | 7 +- lib/webmachine/adapters.rb | 1 - lib/webmachine/adapters/reel.rb | 113 -------------------------- spec/webmachine/adapters/reel_spec.rb | 76 ----------------- 5 files changed, 3 insertions(+), 196 deletions(-) delete mode 100644 lib/webmachine/adapters/reel.rb delete mode 100644 spec/webmachine/adapters/reel_spec.rb diff --git a/Gemfile b/Gemfile index 356617ee..8a7ce4e0 100644 --- a/Gemfile +++ b/Gemfile @@ -16,9 +16,7 @@ group :test do end group :webservers do - gem 'reel', '~> 0.5.0' gem 'http', '~> 0.6.0' - gem 'celluloid', '0.17.4' # Refactors in 0.18.0 break the tests gem 'httpkit', :platform => [:mri, :rbx] end diff --git a/documentation/adapters.md b/documentation/adapters.md index 69b3565a..b64a4126 100644 --- a/documentation/adapters.md +++ b/documentation/adapters.md @@ -1,6 +1,6 @@ ### Adapters -Webmachine includes adapters for [WEBrick][webrick], [Reel][reel], and +Webmachine includes adapters for [WEBrick][webrick], and [HTTPkit][httpkit]. Additionally, the [Rack][rack] adapter lets it run on any webserver that provides a Rack interface. It also lets it run on [Shotgun][shotgun] ([example][shotgun_example]). @@ -26,13 +26,12 @@ See the [Rack Adapter API docs][rack-adapter-api-docs] for more information. #### A Note about MRI 1.9 -The [Reel][reel] and [HTTPkit][httpkit] -adapters might crash with a `SystemStackError` on MRI 1.9 due to its +The [HTTPkit][httpkit] +adapter might crash with a `SystemStackError` on MRI 1.9 due to its limited fiber stack size. If your application is affected by this, the only known solution is to switch to JRuby, Rubinius or MRI 2.0. [webrick]: http://rubydoc.info/stdlib/webrick -[reel]: https://github.com/celluloid/reel [httpkit]: https://github.com/lgierth/httpkit [rack]: https://github.com/rack/rack [shotgun]: https://github.com/rtomayko/shotgun diff --git a/lib/webmachine/adapters.rb b/lib/webmachine/adapters.rb index 37c8e9d3..6db2c8df 100644 --- a/lib/webmachine/adapters.rb +++ b/lib/webmachine/adapters.rb @@ -5,7 +5,6 @@ module Webmachine # Contains classes and modules that connect Webmachine to Ruby # application servers. module Adapters - autoload :Reel, 'webmachine/adapters/reel' autoload :HTTPkit, 'webmachine/adapters/httpkit' end end diff --git a/lib/webmachine/adapters/reel.rb b/lib/webmachine/adapters/reel.rb deleted file mode 100644 index 5a084227..00000000 --- a/lib/webmachine/adapters/reel.rb +++ /dev/null @@ -1,113 +0,0 @@ -require 'webmachine/adapter' -require 'webmachine/constants' -require 'set' -require 'celluloid/current' -require 'reel' -require 'webmachine/headers' -require 'webmachine/request' -require 'webmachine/response' - -module Webmachine - module Adapters - class Reel < Adapter - # Used to override default Reel server options (useful in testing) - DEFAULT_OPTIONS = {} - - def run - @options = DEFAULT_OPTIONS.merge({ - :port => application.configuration.port, - :host => application.configuration.ip - }).merge(application.configuration.adapter_options) - - if extra_verbs = application.configuration.adapter_options[:extra_verbs] - @extra_verbs = Set.new(extra_verbs.map(&:to_s).map(&:upcase)) - else - @extra_verbs = Set.new - end - - if @options[:ssl] - unless @options[:ssl][:cert] && @options[:ssl][:key] - raise ArgumentError, 'Certificate or Private key missing for HTTPS Server' - end - @server = ::Reel::Server::HTTPS.supervise(@options[:host], @options[:port], @options[:ssl], &method(:process)) - else - @server = ::Reel::Server::HTTP.supervise(@options[:host], @options[:port], &method(:process)) - end - - Celluloid::Actor.join(@server) - end - - def process(connection) - connection.each_request do |request| - # Users of the adapter can configure a custom WebSocket handler - if request.websocket? - if handler = @options[:websocket_handler] - handler.call(request.websocket) - else - # Pretend we don't know anything about the WebSocket protocol - # FIXME: This isn't strictly what RFC 6455 would have us do - request.respond :bad_request, "WebSockets not supported" - end - - next - end - - # Optional support for e.g. WebDAV verbs not included in Webmachine's - # state machine. Do the "Railsy" thing and handle them like POSTs - # with a magical parameter - if @extra_verbs.include?(request.method) - method = POST_METHOD - param = "_method=#{request.method}" - uri = request_uri(request.url, request.headers, param) - else - method = request.method - uri = request_uri(request.url, request.headers) - end - - wm_headers = Webmachine::Headers[request.headers.dup] - wm_request = Webmachine::Request.new(method, uri, wm_headers, request.body) - - wm_response = Webmachine::Response.new - application.dispatcher.dispatch(wm_request, wm_response) - - fixup_headers(wm_response) - fixup_callable_encoder(wm_response) - - request.respond ::Reel::Response.new(wm_response.code, - wm_response.headers, - wm_response.body) - end - end - - def request_uri(path, headers, extra_query_params = nil) - path_parts = path.split('?') - uri_hash = {path: path_parts.first} - uri_hash[:query] = path_parts.last if path_parts.length == 2 - - if extra_query_params - if uri_hash[:query] - uri_hash[:query] << "&#{extra_query_params}" - else - uri_hash[:query] = extra_query_params - end - end - - URI::HTTP.build(uri_hash) - end - - def fixup_headers(response) - response.headers.each do |key, value| - if value.is_a?(Array) - response.headers[key] = value.join(", ") - end - end - end - - def fixup_callable_encoder(response) - if response.body.is_a?(Streaming::CallableEncoder) - response.body = [response.body.call] - end - end - end - end -end diff --git a/spec/webmachine/adapters/reel_spec.rb b/spec/webmachine/adapters/reel_spec.rb deleted file mode 100644 index 24e62560..00000000 --- a/spec/webmachine/adapters/reel_spec.rb +++ /dev/null @@ -1,76 +0,0 @@ -require 'spec_helper' -require 'webmachine/spec/adapter_lint' -describe Webmachine::Adapters::Reel do - context 'lint' do - it_should_behave_like :adapter_lint - end - - context 'websockets' do - let(:application) { Webmachine::Application.new } - let(:adapter) do - server = TCPServer.new('0.0.0.0', 0) - application.configuration.port = server.addr[1] - server.close - described_class.new(application) - end - - let(:example_host) { "www.example.com" } - let(:example_path) { "/example"} - let(:example_url) { "ws://#{example_host}#{example_path}" } - let :handshake_headers do - { - "Host" => example_host, - "Upgrade" => "websocket", - "Connection" => "Upgrade", - "Sec-WebSocket-Key" => "dGhlIHNhbXBsZSBub25jZQ==", - "Origin" => "http://example.com", - "Sec-WebSocket-Protocol" => "chat, superchat", - "Sec-WebSocket-Version" => "13" - } - end - let(:client_message) { "Hi server!" } - let(:server_message) { "Hi client!" } - - it 'supports websockets' do - application.configuration.adapter_options[:websocket_handler] = proc do |socket| - expect(socket.read).to eq client_message - socket << server_message - end - - reel_server(adapter) do |client| - client << WebSocket::ClientHandshake.new(:get, example_url, handshake_headers).to_data - - # Discard handshake response - # FIXME: hax - client.readpartial(4096) - - client << WebSocket::Message.new(client_message).to_data - parser = WebSocket::Parser.new - parser.append client.readpartial(4096) until message = parser.next_message - - expect(message).to eq server_message - end - end - end - - def reel_server(adptr = adapter) - thread = Thread.new { adptr.run } - begin - Timeout.timeout(5) do - begin - sock = TCPSocket.new(adptr.application.configuration.ip, adptr.application.configuration.port) - begin - yield(sock) - ensure - sock.close - end - rescue Errno::ECONNREFUSED - Thread.pass - retry - end - end - ensure - thread.kill if thread - end - end -end From 67cc822e12fe7fc06682958f86aeed8b9ad2e799 Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Sat, 14 Jan 2023 00:14:42 +1100 Subject: [PATCH 088/122] CI: promote the Ruby 3.2 build step to non-experimental --- .github/workflows/test.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 406828d9..d7d31f00 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,11 +9,9 @@ jobs: strategy: fail-fast: false matrix: - ruby_version: ["2.3", "2.4", "2.5", "2.6", "2.7", "3.0", "3.1"] + ruby_version: ["2.3", "2.4", "2.5", "2.6", "2.7", "3.0", "3.1", "3.2"] experimental: [false] include: - - ruby_version: "3.2" - experimental: true - ruby_version: "ruby-head" experimental: true From f0d6db268b3b91ab281d0488a392f9bc7561bd0d Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Sat, 14 Jan 2023 00:42:31 +1100 Subject: [PATCH 089/122] Set gem homepage to current git repository --- webmachine.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webmachine.gemspec b/webmachine.gemspec index d1c3d079..c5ab77ff 100644 --- a/webmachine.gemspec +++ b/webmachine.gemspec @@ -10,7 +10,7 @@ Gem::Specification.new do |gem| the confusion of going through a CGI-style interface like Rack. It is strongly influenced by the original Erlang project of the same name and shares its opinionated nature about HTTP. DESC - gem.homepage = "http://github.com/seancribbs/webmachine-ruby" + gem.homepage = "https://github.com/webmachine/webmachine-ruby" gem.authors = ["Sean Cribbs"] gem.email = ["sean@basho.com"] gem.license = "Apache-2.0" From 08a1b86e2291d542767d548e9e5fd4f5f8d8626b Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Sat, 14 Jan 2023 00:42:41 +1100 Subject: [PATCH 090/122] Add project metadata to the gemspec As per https://guides.rubygems.org/specification-reference/#metadata, add metadata to the gemspec file. This'll allow people to more easily access the source code, raise issues and read the changelog. These bug_tracker_uri, changelog_uri, documentation_uri, homepage_uri, source_code_uri, and wiki_uri links will appear on the rubygems page at https://rubygems.org/gems/webmachine and be available via the Rubygems API after the next release. --- webmachine.gemspec | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/webmachine.gemspec b/webmachine.gemspec index c5ab77ff..0c048872 100644 --- a/webmachine.gemspec +++ b/webmachine.gemspec @@ -15,6 +15,13 @@ Gem::Specification.new do |gem| gem.email = ["sean@basho.com"] gem.license = "Apache-2.0" + gem.metadata["bug_tracker_uri"] = "#{gem.homepage}/issues" + gem.metadata["changelog_uri"] = "#{gem.homepage}/blob/HEAD/CHANGELOG.md" + gem.metadata["documentation_uri"] = "https://www.rubydoc.info/gems/webmachine/#{gem.version}" + gem.metadata["homepage_uri"] = gem.homepage + gem.metadata["source_code_uri"] = gem.homepage + gem.metadata["wiki_uri"] = "#{gem.homepage}/wiki" + gem.add_runtime_dependency(%q, [">= 0.4.0"]) gem.add_runtime_dependency(%q) gem.add_runtime_dependency(%q, [">= 1.0.2", "< 2.0"]) From 2b02726b5da5b49c1385d8d78699796762ee4a9a Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Sat, 14 Jan 2023 07:33:23 +1100 Subject: [PATCH 091/122] Remove the HTTPkit adapter The HTTPkit project seems not to be maintained: - the git repository has been removed from GitHub - there has been no release since 2014 --- Gemfile | 5 -- README.md | 3 +- documentation/adapters.md | 12 +--- lib/webmachine/adapters.rb | 1 - lib/webmachine/adapters/httpkit.rb | 74 ------------------------ spec/spec_helper.rb | 2 +- spec/webmachine/adapters/httpkit_spec.rb | 10 ---- 7 files changed, 4 insertions(+), 103 deletions(-) delete mode 100644 lib/webmachine/adapters/httpkit.rb delete mode 100644 spec/webmachine/adapters/httpkit_spec.rb diff --git a/Gemfile b/Gemfile index 8a7ce4e0..b0bcff49 100644 --- a/Gemfile +++ b/Gemfile @@ -15,11 +15,6 @@ group :test do gem "websocket_parser", "~>1.0" end -group :webservers do - gem 'http', '~> 0.6.0' - gem 'httpkit', :platform => [:mri, :rbx] -end - group :guard do gem 'guard-rspec', '~> 4.7' case RbConfig::CONFIG['host_os'] diff --git a/README.md b/README.md index 147df857..c4185336 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,7 @@ are up to you. requests, and response codes for you. * Provides a base resource with points of extension to let you describe what is relevant about your particular resource. -* Supports WEBrick, Reel, HTTPkit, and a Rack shim. Other host - servers are being investigated. +* Supports WEBrick and a Rack shim. Other host servers are being investigated. * Streaming/chunked response bodies are permitted as Enumerables, Procs, or Fibers! * Unlike the Erlang original, it does real Language negotiation. diff --git a/documentation/adapters.md b/documentation/adapters.md index b64a4126..3bba6911 100644 --- a/documentation/adapters.md +++ b/documentation/adapters.md @@ -1,7 +1,7 @@ ### Adapters -Webmachine includes adapters for [WEBrick][webrick], and -[HTTPkit][httpkit]. Additionally, the [Rack][rack] adapter lets it +Webmachine includes an adapter for [WEBrick][webrick]. +Additionally, the [Rack][rack] adapter lets it run on any webserver that provides a Rack interface. It also lets it run on [Shotgun][shotgun] ([example][shotgun_example]). @@ -24,15 +24,7 @@ For an example of using Webmachine with Rack middleware, see the [Pact Broker][m See the [Rack Adapter API docs][rack-adapter-api-docs] for more information. -#### A Note about MRI 1.9 - -The [HTTPkit][httpkit] -adapter might crash with a `SystemStackError` on MRI 1.9 due to its -limited fiber stack size. If your application is affected by this, the -only known solution is to switch to JRuby, Rubinius or MRI 2.0. - [webrick]: http://rubydoc.info/stdlib/webrick -[httpkit]: https://github.com/lgierth/httpkit [rack]: https://github.com/rack/rack [shotgun]: https://github.com/rtomayko/shotgun [shotgun_example]: https://gist.github.com/4389220 diff --git a/lib/webmachine/adapters.rb b/lib/webmachine/adapters.rb index 6db2c8df..ab6dc231 100644 --- a/lib/webmachine/adapters.rb +++ b/lib/webmachine/adapters.rb @@ -5,6 +5,5 @@ module Webmachine # Contains classes and modules that connect Webmachine to Ruby # application servers. module Adapters - autoload :HTTPkit, 'webmachine/adapters/httpkit' end end diff --git a/lib/webmachine/adapters/httpkit.rb b/lib/webmachine/adapters/httpkit.rb deleted file mode 100644 index 2198e8f8..00000000 --- a/lib/webmachine/adapters/httpkit.rb +++ /dev/null @@ -1,74 +0,0 @@ -require 'webmachine/adapter' -require 'webmachine/constants' -require 'webmachine/version' -require 'httpkit' -require 'webmachine/version' -require 'webmachine/response' -require 'webmachine/request' -require 'webmachine/headers' - -module Webmachine - module Adapters - class HTTPkit < Adapter - VERSION_STRING = "#{Webmachine::SERVER_STRING} HTTPkit/#{::HTTPkit::VERSION}".freeze - - def options - @options ||= { - :address => application.configuration.ip, - :port => application.configuration.port, - :handlers => [ - ::HTTPkit::Server::TimeoutsHandler.new, - ::HTTPkit::Server::KeepAliveHandler.new, - self - ] - } - end - - def run - ::HTTPkit.start do - ::HTTPkit::Server.start(options) - end - end - - # Called by HTTPkit::Server for every request - def serve(request, served) - response = Webmachine::Response.new - application.dispatcher.dispatch(convert_request(request), response) - - served.fulfill(convert_response(response)) - end - - private - - # Converts HTTPkit::Request to Webmachine::Request - def convert_request(request) - Webmachine::Request.new( - request.http_method.to_s.upcase, - request.uri, - Webmachine::Headers[request.headers.dup], - request.body) - end - - # Converts Webmachine::Response to HTTPkit::Response - def convert_response(response) - response.headers[SERVER] = VERSION_STRING - - - ::HTTPkit::Response.new( - response.code.to_i, - response.headers, - convert_body(response.body)) - end - - # HTTPkit::Body accepts strings and enumerables, i.e. Webmachine's - # Callable, Enumerable, IO, and Fiber encoders are supported. - def convert_body(body) - if body.respond_to?(:call) - [body.call] - else - body || '' - end - end - end - end -end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 20a161a6..00eaf7c6 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,5 +1,5 @@ require "bundler/setup" -Bundler.require :default, :test, :webservers +Bundler.require :default, :test require 'logger' class NullLogger < Logger diff --git a/spec/webmachine/adapters/httpkit_spec.rb b/spec/webmachine/adapters/httpkit_spec.rb deleted file mode 100644 index f2ee7dde..00000000 --- a/spec/webmachine/adapters/httpkit_spec.rb +++ /dev/null @@ -1,10 +0,0 @@ -require "spec_helper" -require "webmachine/spec/adapter_lint" - -begin - describe Webmachine::Adapters::HTTPkit do - it_should_behave_like :adapter_lint - end -rescue LoadError - warn "Platform is #{RUBY_PLATFORM}: skipping httpkit adapter spec." -end From efa097451909a0576665bf8dc4ae6ca6e9497cbd Mon Sep 17 00:00:00 2001 From: 0x1eef <0x1eef@protonmail.com> Date: Fri, 13 Jan 2023 22:04:08 -0300 Subject: [PATCH 092/122] Remove dead links from the README Both irwebmachine, and webmachine-sprockets have been abandoned. --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index c4185336..8de7d35c 100644 --- a/README.md +++ b/README.md @@ -164,10 +164,8 @@ the "visual debugger". Learn how to configure it [here][visual-debugger]. ## Related libraries -* [irwebmachine](https://github.com/generalassembly/irwebmachine) - IRB/Pry debugging of Webmachine applications * [webmachine-test](https://github.com/bernd/webmachine-test) - Helpers for testing Webmachine applications * [webmachine-linking](https://github.com/petejohanson/webmachine-linking) - Helpers for linking between Resources, and Web Linking -* [webmachine-sprockets](https://github.com/lgierth/webmachine-sprockets) - Integration with Sprockets assets packaging system * [webmachine-actionview](https://github.com/rgarner/webmachine-actionview) - Integration of some Rails-style view conventions into Webmachine * [jruby-http-kit](https://github.com/nLight/jruby-http-kit) - Includes an adapter for the Clojure-based Ring library/server * [newrelic-webmachine](https://github.com/mdub/newrelic-webmachine) - NewRelic instrumentation From 49754d3b91cde1852f9654b636554c8fbc96c2f1 Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Sat, 14 Jan 2023 17:53:43 +1100 Subject: [PATCH 093/122] Use a GitHub Actions build status badge in the readme document --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c4185336..202e9abb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # webmachine for Ruby [![Gem Version](https://badge.fury.io/rb/webmachine.svg)](https://badge.fury.io/rb/webmachine) - [![Build Status](https://travis-ci.org/webmachine/webmachine-ruby.svg)](https://travis-ci.org/webmachine/webmachine-ruby) + [![Build Status](https://github.com/webmachine/webmachine-ruby/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/webmachine/webmachine-ruby/actions/workflows/test.yml) webmachine-ruby is a port of [Webmachine](https://github.com/basho/webmachine), which is written in From 083e7575d998c544a04ea063f535c2551d8a58d7 Mon Sep 17 00:00:00 2001 From: 0x1eef <0x1eef@protonmail.com> Date: Sat, 14 Jan 2023 09:06:38 -0300 Subject: [PATCH 094/122] Add the standardrb linter standardrb provides a relaxed set of linting rules that provide the benefits of a linter without the headaches that can come from the slightly excessive rubocop defaults. New rules we'd like to adopt can be enabled in `.rubocop.yml`, and similarly rules we don't want to adopt can be disabled in `.rubocop.yml`. --- .rubocop.yml | 54 + Gemfile | 14 +- Guardfile | 10 +- Rakefile | 24 +- examples/debugger.rb | 8 +- examples/logging.rb | 4 +- examples/webrick.rb | 4 +- lib/webmachine/adapters/rack.rb | 72 +- lib/webmachine/adapters/rack_mapped.rb | 2 +- lib/webmachine/adapters/webrick.rb | 23 +- lib/webmachine/configuration.rb | 2 +- lib/webmachine/constants.rb | 24 +- lib/webmachine/cookie.rb | 30 +- lib/webmachine/decision/conneg.rb | 48 +- lib/webmachine/decision/flow.rb | 39 +- lib/webmachine/decision/fsm.rb | 8 +- lib/webmachine/decision/helpers.rb | 42 +- lib/webmachine/dispatcher/route.rb | 54 +- lib/webmachine/errors.rb | 15 +- lib/webmachine/media_type.rb | 10 +- lib/webmachine/quoted_string.rb | 6 +- lib/webmachine/request.rb | 17 +- lib/webmachine/resource/authentication.rb | 7 +- lib/webmachine/resource/encodings.rb | 12 +- lib/webmachine/response.rb | 16 +- lib/webmachine/spec/adapter_lint.rb | 122 +-- lib/webmachine/spec/test_resource.rb | 44 +- lib/webmachine/streaming/encoder.rb | 4 +- lib/webmachine/streaming/io_encoder.rb | 7 +- lib/webmachine/trace/fsm.rb | 43 +- lib/webmachine/trace/resource_proxy.rb | 2 +- lib/webmachine/trace/trace_resource.rb | 46 +- lib/webmachine/translation.rb | 2 +- lib/webmachine/version.rb | 2 +- memory_test.rb | 5 +- spec/spec_helper.rb | 18 +- spec/webmachine/adapter_spec.rb | 14 +- spec/webmachine/adapters/rack_mapped_spec.rb | 38 +- spec/webmachine/adapters/rack_spec.rb | 46 +- spec/webmachine/adapters/webrick_spec.rb | 12 +- spec/webmachine/application_spec.rb | 22 +- spec/webmachine/chunked_body_spec.rb | 12 +- spec/webmachine/configuration_spec.rb | 10 +- spec/webmachine/cookie_spec.rb | 88 +- spec/webmachine/decision/conneg_spec.rb | 151 ++- spec/webmachine/decision/flow_spec.rb | 921 +++++++++++------- spec/webmachine/decision/fsm_spec.rb | 28 +- spec/webmachine/decision/helpers_spec.rb | 101 +- spec/webmachine/dispatcher/route_spec.rb | 172 ++-- spec/webmachine/dispatcher_spec.rb | 56 +- spec/webmachine/errors_spec.rb | 8 +- spec/webmachine/etags_spec.rb | 14 +- spec/webmachine/events_spec.rb | 34 +- spec/webmachine/headers_spec.rb | 46 +- spec/webmachine/media_type_spec.rb | 92 +- spec/webmachine/request_spec.rb | 177 ++-- spec/webmachine/rescueable_exception_spec.rb | 6 +- .../resource/authentication_spec.rb | 34 +- spec/webmachine/response_spec.rb | 43 +- spec/webmachine/trace/fsm_spec.rb | 14 +- spec/webmachine/trace/resource_proxy_spec.rb | 23 +- spec/webmachine/trace/trace_store_spec.rb | 26 +- spec/webmachine/trace_spec.rb | 8 +- webmachine.gemspec | 41 +- 64 files changed, 1688 insertions(+), 1389 deletions(-) create mode 100644 .rubocop.yml diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 00000000..70b0b6bc --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,54 @@ +## +# Plugins +require: + - standard + +## +# Defaults: standardrb +inherit_gem: + standard: config/base.yml + +## +# Rules that break from standardrb defaults +Style/StringLiterals: + EnforcedStyle: single_quotes + +## +# Disabled rules +Lint/AssignmentInCondition: + Enabled: false +Lint/FloatComparison: + Enabled: false +Lint/ConstantDefinitionInBlock: + Enabled: false +Lint/EmptyWhen: + Exclude: + - "lib/webmachine/dispatcher/route.rb" +Lint/DuplicateMethods: + Exclude: + - "lib/webmachine/application.rb" +Lint/UnderscorePrefixedVariableName: + Exclude: + - "lib/webmachine/trace/resource_proxy.rb" + - "spec/webmachine/dispatcher_spec.rb" +Lint/NestedMethodDefinition: + Exclude: + - "spec/webmachine/decision/flow_spec.rb" +Lint/RescueException: + Exclude: + - "spec/webmachine/decision/fsm_spec.rb" +Lint/RaiseException: + Exclude: + - "spec/webmachine/decision/fsm_spec.rb" +Style/MissingRespondToMissing: + Exclude: + - "lib/webmachine/request.rb" +Style/NilComparison: + Exclude: + - "spec/webmachine/decision/falsey_spec.rb" +Style/GlobalVars: + Exclude: + - "lib/webmachine/decision/conneg.rb" + +AllCops: + SuggestExtensions: false diff --git a/Gemfile b/Gemfile index b0bcff49..013e857b 100644 --- a/Gemfile +++ b/Gemfile @@ -3,16 +3,16 @@ source 'https://rubygems.org' gemspec group :development do - gem "yard", "~> 0.9" - gem "rake", "~> 12.0" + gem 'yard', '~> 0.9' + gem 'rake', '~> 12.0' end group :test do - gem "rspec", "~> 3.0", ">= 3.6.0" - gem "rspec-its", "~> 1.2" - gem "rack", "~> 2.0" - gem "rack-test", "~> 0.7" - gem "websocket_parser", "~>1.0" + gem 'rspec', '~> 3.0', '>= 3.6.0' + gem 'rspec-its', '~> 1.2' + gem 'rack', '~> 2.0' + gem 'rack-test', '~> 0.7' + gem 'websocket_parser', '~>1.0' end group :guard do diff --git a/Guardfile b/Guardfile index 357f38e2..1d7af7b7 100644 --- a/Guardfile +++ b/Guardfile @@ -1,11 +1,11 @@ gemset = ENV['RVM_GEMSET'] || 'webmachine' gemset = "@#{gemset}" unless gemset.to_s == '' -rvms = %W[ 1.8.7 1.9.2 1.9.3 jruby rbx ].map {|v| "#{v}#{gemset}" } +rvms = %W[1.8.7 1.9.2 1.9.3 jruby rbx].map { |v| "#{v}#{gemset}" } -guard 'rspec', :cli => "--color --profile", :growl => true, :rvm => rvms do - watch(%r{^lib/webmachine/locale/.+$}) { "spec" } +guard 'rspec', cli: '--color --profile', growl: true, rvm: rvms do + watch(%r{^lib/webmachine/locale/.+$}) { 'spec' } watch(%r{^spec/.+_spec\.rb$}) - watch(%r{^lib/(.+)\.rb$}){ |m| "spec/#{m[1]}_spec.rb" } - watch('spec/spec_helper.rb') { "spec" } + watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } + watch('spec/spec_helper.rb') { 'spec' } end diff --git a/Rakefile b/Rakefile index 9c5f3a5e..c9f54e96 100644 --- a/Rakefile +++ b/Rakefile @@ -1,44 +1,44 @@ -require "bundler/gem_tasks" +require 'bundler/gem_tasks' begin require 'yard' require 'yard/rake/yardoc_task' YARD::Rake::YardocTask.new do |doc| - doc.files = Dir["lib/**/*.rb"] + ['README.md'] - doc.options = ["-m", "markdown"] + doc.files = Dir['lib/**/*.rb'] + ['README.md'] + doc.options = ['-m', 'markdown'] end rescue LoadError end -desc "Validate the gemspec file." +desc 'Validate the gemspec file.' task :validate_gemspec do - Gem::Specification.load("webmachine.gemspec").validate + Gem::Specification.load('webmachine.gemspec').validate end -task :build => :validate_gemspec +task build: :validate_gemspec -desc "Cleans up white space in source files" +desc 'Cleans up white space in source files' task :clean_whitespace do no_file_cleaned = true - Dir["**/*.rb"].each do |file| + Dir['**/*.rb'].each do |file| contents = File.read(file) cleaned_contents = contents.gsub(/([ \t]+)$/, '') unless cleaned_contents == contents no_file_cleaned = false puts " - Cleaned #{file}" - File.open(file, 'w') { |f| f.write(cleaned_contents) } + File.write(file, cleaned_contents) end end if no_file_cleaned - puts "No files with trailing whitespace found" + puts 'No files with trailing whitespace found' end end require 'rspec/core/rake_task' -desc "Run specs" +desc 'Run specs' RSpec::Core::RakeTask.new(:spec) -task :default => :spec +task default: :spec diff --git a/examples/debugger.rb b/examples/debugger.rb index cff11c90..ec4bffa5 100644 --- a/examples/debugger.rb +++ b/examples/debugger.rb @@ -2,21 +2,23 @@ require 'webmachine/trace' class MyTracedResource < Webmachine::Resource - def trace?; true; end + def trace? + true + end def resource_exists? case request.query['e'] when 'true' true when 'fail' - raise "BOOM" + raise 'BOOM' else false end end def to_html - "You found me." + 'You found me.' end end diff --git a/examples/logging.rb b/examples/logging.rb index 24ceac7f..82e27c3a 100644 --- a/examples/logging.rb +++ b/examples/logging.rb @@ -18,7 +18,7 @@ def handle_event(event) resource = event.payload[:resource] code = event.payload[:code] - puts "[%s] method=%s uri=%s code=%d resource=%s time=%.4f" % [ + puts '[%s] method=%s uri=%s code=%d resource=%s time=%.4f' % [ Time.now.iso8601, request.method, request.uri.to_s, code, resource, event.duration ] @@ -34,7 +34,7 @@ def handle_event(event) app.configure do |config| config.adapter = :WEBrick - config.adapter_options = {:AccessLog => [], :Logger => Logger.new('/dev/null')} + config.adapter_options = {AccessLog: [], Logger: Logger.new('/dev/null')} end end diff --git a/examples/webrick.rb b/examples/webrick.rb index 3c899ca8..a6a81268 100644 --- a/examples/webrick.rb +++ b/examples/webrick.rb @@ -6,11 +6,11 @@ def last_modified end def encodings_provided - { "gzip" => :encode_gzip, "identity" => :encode_identity } + {'gzip' => :encode_gzip, 'identity' => :encode_identity} end def to_html - "Hello from WebmachineHello, world!" + 'Hello from WebmachineHello, world!' end end diff --git a/lib/webmachine/adapters/rack.rb b/lib/webmachine/adapters/rack.rb index 50c7a0c8..6148b4b3 100644 --- a/lib/webmachine/adapters/rack.rb +++ b/lib/webmachine/adapters/rack.rb @@ -47,9 +47,9 @@ class Rack < Adapter # Start the Rack adapter def run options = DEFAULT_OPTIONS.merge({ - :app => self, - :Port => application.configuration.port, - :Host => application.configuration.ip + app: self, + Port: application.configuration.port, + Host: application.configuration.ip }).merge(application.configuration.adapter_options) @server = ::Rack::Server.new(options) @@ -69,33 +69,34 @@ def call(env) response.headers[SERVER] = VERSION_STRING - rack_status = response.code + rack_status = response.code rack_headers = response.headers.flattened(NEWLINE) rack_body = case response.body - when String # Strings are enumerable in ruby 1.8 - [response.body] - else - if (io_body = IO.try_convert(response.body)) - io_body - elsif response.body.respond_to?(:call) - Webmachine::ChunkedBody.new(Array(response.body.call)) - elsif response.body.respond_to?(:each) - # This might be an IOEncoder with a Content-Length, which shouldn't be chunked. - if response.headers[TRANSFER_ENCODING] == "chunked" - Webmachine::ChunkedBody.new(response.body) - else - response.body - end - else - [response.body.to_s] - end - end + when String # Strings are enumerable in ruby 1.8 + [response.body] + else + if (io_body = IO.try_convert(response.body)) + io_body + elsif response.body.respond_to?(:call) + Webmachine::ChunkedBody.new(Array(response.body.call)) + elsif response.body.respond_to?(:each) + # This might be an IOEncoder with a Content-Length, which shouldn't be chunked. + if response.headers[TRANSFER_ENCODING] == 'chunked' + Webmachine::ChunkedBody.new(response.body) + else + response.body + end + else + [response.body.to_s] + end + end rack_res = RackResponse.new(rack_body, rack_status, rack_headers) rack_res.finish end protected + def routing_tokens(rack_req) nil # no-op for default, un-mapped rack adapter end @@ -105,15 +106,15 @@ def base_uri(rack_req) end private + def build_webmachine_request(rack_req, headers) RackRequest.new(rack_req.request_method, - rack_req.url, - headers, - RequestBody.new(rack_req), - routing_tokens(rack_req), - base_uri(rack_req), - rack_req.env - ) + rack_req.url, + headers, + RequestBody.new(rack_req), + routing_tokens(rack_req), + base_uri(rack_req), + rack_req.env) end class RackRequest < Webmachine::Request @@ -129,14 +130,14 @@ class RackResponse ONE_FIVE = '1.5'.freeze def initialize(body, status, headers) - @body = body - @status = status + @body = body + @status = status @headers = headers end def finish @headers[CONTENT_TYPE] ||= TEXT_HTML if rack_release_enforcing_content_type - @headers.delete(CONTENT_TYPE) if response_without_body + @headers.delete(CONTENT_TYPE) if response_without_body [@status, @headers, @body] end @@ -188,10 +189,13 @@ def to_s # @yieldparam [String] chunk a chunk of the request body def each if @value - @value.each {|chunk| yield chunk } + @value.each { |chunk| yield chunk } else @value = [] - @request.body.each {|chunk| @value << chunk; yield chunk } + @request.body.each { |chunk| + @value << chunk + yield chunk + } end end end # class RequestBody diff --git a/lib/webmachine/adapters/rack_mapped.rb b/lib/webmachine/adapters/rack_mapped.rb index 01b1bd8b..c924c867 100644 --- a/lib/webmachine/adapters/rack_mapped.rb +++ b/lib/webmachine/adapters/rack_mapped.rb @@ -26,7 +26,7 @@ class RackMapped < Rack def routing_tokens(rack_req) routing_match = rack_req.path_info.match(Webmachine::Request::ROUTING_PATH_MATCH) - routing_path = routing_match ? routing_match[1] : "" + routing_path = routing_match ? routing_match[1] : '' routing_path.split(SLASH) end diff --git a/lib/webmachine/adapters/webrick.rb b/lib/webmachine/adapters/webrick.rb index 5967787b..d6a3e90e 100644 --- a/lib/webmachine/adapters/webrick.rb +++ b/lib/webmachine/adapters/webrick.rb @@ -17,9 +17,9 @@ class WEBrick < Adapter # Starts the WEBrick adapter def run options = DEFAULT_OPTIONS.merge({ - :Port => application.configuration.port, - :BindAddress => application.configuration.ip, - :application => application + Port: application.configuration.port, + BindAddress: application.configuration.ip, + application: application }).merge(application.configuration.adapter_options) @server = Server.new(options) @server.start @@ -27,7 +27,6 @@ def run # WEBRick::HTTPServer that is run by the WEBrick adapter. class Server < ::WEBrick::HTTPServer - def initialize(options) @application = options[:application] super(options) @@ -36,29 +35,29 @@ def initialize(options) # Handles a request def service(wreq, wres) header = Webmachine::Headers.new - wreq.each {|k,v| header[k] = v } + wreq.each { |k, v| header[k] = v } request = Webmachine::Request.new(wreq.request_method, - wreq.request_uri, - header, - LazyRequestBody.new(wreq)) + wreq.request_uri, + header, + LazyRequestBody.new(wreq)) response = Webmachine::Response.new @application.dispatcher.dispatch(request, response) wres.status = response.code.to_i - headers = response.headers.flattened.reject { |k,v| k == 'Set-Cookie' } - headers.each { |k,v| wres[k] = v } + headers = response.headers.flattened.reject { |k, v| k == 'Set-Cookie' } + headers.each { |k, v| wres[k] = v } cookies = [response.headers['Set-Cookie'] || []].flatten cookies.each { |c| wres.cookies << c } - wres[SERVER] = [Webmachine::SERVER_STRING, wres.config[:ServerSoftware]].join(" ") + wres[SERVER] = [Webmachine::SERVER_STRING, wres.config[:ServerSoftware]].join(' ') case response.body when String wres.body << response.body when Enumerable wres.chunked = response.headers[TRANSFER_ENCODING] == 'chunked' - response.body.each {|part| wres.body << part } + response.body.each { |part| wres.body << part } else if response.body.respond_to?(:call) wres.chunked = true diff --git a/lib/webmachine/configuration.rb b/lib/webmachine/configuration.rb index d64e6847..5555a92c 100644 --- a/lib/webmachine/configuration.rb +++ b/lib/webmachine/configuration.rb @@ -12,7 +12,7 @@ module Webmachine # @return [Configuration] the default configuration def Configuration.default - new("0.0.0.0", 8080, :WEBrick, {}) + new('0.0.0.0', 8080, :WEBrick, {}) end # Yields the current configuration to the passed block. diff --git a/lib/webmachine/constants.rb b/lib/webmachine/constants.rb index 8541cc65..444f4eb8 100644 --- a/lib/webmachine/constants.rb +++ b/lib/webmachine/constants.rb @@ -28,20 +28,20 @@ MATCHES_ALL = '*/*'.freeze - GET_METHOD = "GET" - HEAD_METHOD = "HEAD" - POST_METHOD = "POST" - PUT_METHOD = "PUT" - DELETE_METHOD = "DELETE" - OPTIONS_METHOD = "OPTIONS" - TRACE_METHOD = "TRACE" - CONNECT_METHOD = "CONNECT" + GET_METHOD = 'GET' + HEAD_METHOD = 'HEAD' + POST_METHOD = 'POST' + PUT_METHOD = 'PUT' + DELETE_METHOD = 'DELETE' + OPTIONS_METHOD = 'OPTIONS' + TRACE_METHOD = 'TRACE' + CONNECT_METHOD = 'CONNECT' STANDARD_HTTP_METHODS = [ - GET_METHOD, HEAD_METHOD, POST_METHOD, - PUT_METHOD, DELETE_METHOD, TRACE_METHOD, - CONNECT_METHOD, OPTIONS_METHOD - ].map!(&:freeze) + GET_METHOD, HEAD_METHOD, POST_METHOD, + PUT_METHOD, DELETE_METHOD, TRACE_METHOD, + CONNECT_METHOD, OPTIONS_METHOD + ].map!(&:freeze) STANDARD_HTTP_METHODS.freeze # A colon diff --git a/lib/webmachine/cookie.rb b/lib/webmachine/cookie.rb index b30535de..dfb07990 100644 --- a/lib/webmachine/cookie.rb +++ b/lib/webmachine/cookie.rb @@ -11,7 +11,7 @@ class Cookie def self.parse(cstr, include_dups = false) cookies = {} (cstr || '').split(/\s*[;,]\s*/n).each { |c| - k,v = c.split(/\s*=\s*/, 2).map { |s| unescape(s) } + k, v = c.split(/\s*=\s*/, 2).map { |s| unescape(s) } case cookies[k] when nil @@ -31,7 +31,7 @@ def self.parse(cstr, include_dups = false) # Allowed keys for the attributes parameter of # {Webmachine::Cookie#initialize} ALLOWED_ATTRIBUTES = [:secure, :httponly, :path, :domain, - :comment, :maxage, :expires, :version] + :comment, :maxage, :expires, :version] # If the cookie is HTTP only def http_only? @@ -83,21 +83,21 @@ def to_s attributes = ALLOWED_ATTRIBUTES.select { |a| @attributes[a] }.map do |a| case a when :httponly - "HttpOnly" if @attributes[a] + 'HttpOnly' if @attributes[a] when :secure - "Secure" if @attributes[a] + 'Secure' if @attributes[a] when :maxage - "Max-Age=" + @attributes[a].to_s + 'Max-Age=' + @attributes[a].to_s when :expires - "Expires=" + rfc2822(@attributes[a]) + 'Expires=' + rfc2822(@attributes[a]) when :comment - "Comment=" + escape(@attributes[a].to_s) + 'Comment=' + escape(@attributes[a].to_s) else - a.to_s.sub(/^\w/) { $&.capitalize } + "=" + @attributes[a].to_s + a.to_s.sub(/^\w/) { $&.capitalize } + '=' + @attributes[a].to_s end end - ([escape(name) + "=" + escape(value)] + attributes).join("; ") + ([escape(name) + '=' + escape(value)] + attributes).join('; ') end private @@ -110,7 +110,7 @@ def rfc2822(time) time.strftime('%a, %d %b %Y %T GMT') end - if URI.respond_to?(:decode_www_form_component) and defined?(::Encoding) + if URI.respond_to?(:decode_www_form_component) && defined?(::Encoding) # Escape a cookie def escape(s) URI.encode_www_form_component(s) @@ -134,7 +134,7 @@ def self.unescape(s, encoding = Encoding::UTF_8) # @private TBLDECWWWCOMP_ = {} 256.times do |i| - h, l = i>>4, i&15 + h, l = i >> 4, i & 15 TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr @@ -148,9 +148,9 @@ def self.unescape(s, encoding = Encoding::UTF_8) # This decodes + to SP. # # @private - def self.unescape(str, enc=nil) - raise ArgumentError, "invalid %-encoding (#{str})" unless /\A(?:%\h\h|[^%]+)*\z/ =~ str - str.gsub(/\+|%\h\h/){|c| TBLDECWWWCOMP_[c] } + def self.unescape(str, enc = nil) + raise ArgumentError, "invalid %-encoding (#{str})" unless /\A(?:%\h\h|[^%]+)*\z/.match?(str) + str.gsub(/\+|%\h\h/) { |c| TBLDECWWWCOMP_[c] } end # Encode given +str+ to URL-encoded form data. @@ -163,7 +163,7 @@ def self.unescape(str, enc=nil) # # @private def escape(str) - str.to_s.gsub(/[^*\-.0-9A-Z_a-z]/){|c| TBLENCWWWCOMP_[c] } + str.to_s.gsub(/[^*\-.0-9A-Z_a-z]/) { |c| TBLENCWWWCOMP_[c] } end end end diff --git a/lib/webmachine/decision/conneg.rb b/lib/webmachine/decision/conneg.rb index 30e85b05..204634de 100644 --- a/lib/webmachine/decision/conneg.rb +++ b/lib/webmachine/decision/conneg.rb @@ -14,7 +14,7 @@ module Conneg # appropriate media type. # @api private def choose_media_type(provided, header) - types = Array(header).map{|h| h.split(SPLIT_COMMA) }.flatten + types = Array(header).map { |h| h.split(SPLIT_COMMA) }.flatten requested = MediaTypeList.build(types) provided = provided.map do |p| # normalize_provided MediaType.parse(p) @@ -43,7 +43,7 @@ def choose_encoding(provided, header) # @api private def choose_charset(provided, header) if provided && !provided.empty? - charsets = provided.map {|c| c.first } + charsets = provided.map { |c| c.first } if charset = do_choose(charsets, header, HAS_ENCODING ? Encoding.default_external.name : kcode_charset) metadata[CHARSET] = charset end @@ -62,17 +62,17 @@ def choose_language(provided, header) any_ok = star_priority && star_priority > 0.0 accepted = requested.find do |priority, range| if priority == 0.0 - provided.delete_if {|tag| language_match(range, tag) } + provided.delete_if { |tag| language_match(range, tag) } false else - provided.any? {|tag| language_match(range, tag) } + provided.any? { |tag| language_match(range, tag) } end end chosen = if accepted - provided.find {|tag| language_match(accepted.last, tag) } - elsif any_ok - provided.first - end + provided.find { |tag| language_match(accepted.last, tag) } + elsif any_ok + provided.first + end if chosen metadata['Language'] = chosen response.headers['Content-Language'] = chosen @@ -91,14 +91,14 @@ def choose_language(provided, header) # is "-". # @api private def language_match(range, tag) - range.downcase == tag.downcase || tag =~ /^#{Regexp.escape(range)}\-/i + range.downcase == tag.downcase || tag =~ /^#{Regexp.escape(range)}-/i end # Makes an conneg choice based what is accepted and what is # provided. # @api private def do_choose(choices, header, default) - choices = choices.dup.map {|s| s.downcase } + choices = choices.dup.map { |s| s.downcase } accepted = PriorityList.build(header.split(SPLIT_COMMA)) default_priority = accepted.priority_of(default) star_priority = accepted.priority_of(STAR) @@ -112,12 +112,13 @@ def do_choose(choices, header, default) choices.include?(acceptable.downcase) end end - (chosen && chosen.last) || # Use the matching one + chosen&.last || # Use the matching one (any_ok && choices.first) || # Or first if "*" (default_ok && choices.include?(default) && default) # Or default end private + # Matches acceptable items that include 'q' values CONNEG_REGEX = /^\s*(\S+);\s*q=(\S*)\s*$/.freeze @@ -138,13 +139,13 @@ def media_match(requested, provided) def kcode_charset case $KCODE when /^U/i - "UTF-8" + 'UTF-8' when /^S/i - "Shift-JIS" + 'Shift-JIS' when /^B/i - "Big5" - else #when /^A/i, nil - "ASCII" + 'Big5' + else # when /^A/i, nil + 'ASCII' end end @@ -157,7 +158,7 @@ class PriorityList # Given an acceptance list, create a PriorityList from them. def self.build(list) new.tap do |plist| - list.each {|item| plist.add_header_val(item) } + list.each { |item| plist.add_header_val(item) } end end @@ -166,7 +167,7 @@ def self.build(list) # Creates a {PriorityList}. # @see PriorityList::build def initialize - @hash = Hash.new {|h,k| h[k] = [] } + @hash = Hash.new { |h, k| h[k] = [] } @index = {} end @@ -185,8 +186,8 @@ def add(q, choice) def add_header_val(c) if c =~ CONNEG_REGEX choice, q = $1, $2 - q = "0" << q if q =~ /^\./ # handle strange FeedBurner Accept - add(q.to_f,choice) + q = '0' << q if /^\./.match?(q) # handle strange FeedBurner Accept + add(q.to_f, choice) else add(1.0, c) end @@ -212,8 +213,8 @@ def priority_of(choice) # @yieldparam [Float] q the acceptable item's priority # @yieldparam [String] v the acceptable item def each - @hash.to_a.sort.reverse_each do |q,l| - l.each {|v| yield q, v } + @hash.to_a.sort.reverse_each do |q, l| + l.each { |v| yield q, v } end end end @@ -232,10 +233,9 @@ def add_header_val(c) q = mt.params.delete('q') || 1.0 add(q.to_f, mt) rescue ArgumentError - raise MalformedRequest, t('invalid_media_type', :type => c) + raise MalformedRequest, t('invalid_media_type', type: c) end end - end # module Conneg end # module Decision end # module Webmachine diff --git a/lib/webmachine/decision/flow.rb b/lib/webmachine/decision/flow.rb index 87d264dd..5ecc8f54 100644 --- a/lib/webmachine/decision/flow.rb +++ b/lib/webmachine/decision/flow.rb @@ -64,7 +64,7 @@ def b10 if resource.allowed_methods.include?(request.method) :b9 else - response.headers["Allow"] = resource.allowed_methods.join(", ") + response.headers['Allow'] = resource.allowed_methods.join(', ') 405 end end @@ -82,13 +82,13 @@ def b9a when true :b9b when false - response.body = "Content-MD5 header does not match request body." + response.body = 'Content-MD5 header does not match request body.' 400 else # not_validated if decode64(request.content_md5) == Digest::MD5.hexdigest(request.body) :b9b else - response.body = "Content-MD5 header does not match request body." + response.body = 'Content-MD5 header does not match request body.' 400 end end @@ -123,7 +123,7 @@ def b7 CONTENT = /content-/.freeze # Okay Content-* Headers? def b6 - decision_test(resource.valid_content_headers?(request.headers.grep(CONTENT)), :b5, 501) + decision_test(resource.valid_content_headers?(request.headers.grep(CONTENT)), :b5, 501) end # Known Content-Type? @@ -158,7 +158,7 @@ def c3 # Acceptable media type available? def c4 - types = resource.content_types_provided.map {|pair| pair.first } + types = resource.content_types_provided.map { |pair| pair.first } chosen_type = choose_media_type(types, request.accept) if !chosen_type 406 @@ -215,7 +215,7 @@ def f6 end response.headers[CONTENT_TYPE] = chosen_type.to_s if !request.accept_encoding - choose_encoding(resource.encodings_provided, "identity;q=1.0,*;q=0.5") ? :g7 : 406 + choose_encoding(resource.encodings_provided, 'identity;q=1.0,*;q=0.5') ? :g7 : 406 else :f7 end @@ -229,7 +229,7 @@ def f7 # Resource exists? def g7 # This is the first place after all conneg, so set Vary here - response.headers['Vary'] = variances.join(", ") if variances.any? + response.headers['Vary'] = variances.join(', ') if variances.any? decision_test(resource.resource_exists?, :g8, :h7) end @@ -240,12 +240,12 @@ def g8 # If-Match: * exists? def g9 - quote(request.if_match) == '"*"' ? :h10 : :g11 + (quote(request.if_match) == '"*"') ? :h10 : :g11 end # ETag in If-Match def g11 - request_etags = request.if_match.split(SPLIT_COMMA).map {|etag| ETag.new(etag) } + request_etags = request.if_match.split(SPLIT_COMMA).map { |etag| ETag.new(etag) } request_etags.include?(ETag.new(resource.generate_etag)) ? :h10 : 412 end @@ -271,7 +271,7 @@ def h11 # Last-Modified > I-UM-S? def h12 - resource.last_modified > metadata['If-Unmodified-Since'] ? 412 : :i12 + (resource.last_modified > metadata['If-Unmodified-Since']) ? 412 : :i12 end # Moved permanently? (apply PUT to different URI) @@ -299,7 +299,7 @@ def i12 # If-none-match: * exists? def i13 - quote(request.if_none_match) == '"*"' ? :j18 : :k13 + (quote(request.if_none_match) == '"*"') ? :j18 : :k13 end # GET or HEAD? @@ -327,10 +327,10 @@ def k7 # Etag in if-none-match? def k13 - request_etags = request.if_none_match.split(SPLIT_COMMA).map {|etag| ETag.new(etag) } + request_etags = request.if_none_match.split(SPLIT_COMMA).map { |etag| ETag.new(etag) } resource_etag = resource.generate_etag if resource_etag && request_etags.include?(ETag.new(resource_etag)) - :j18 + :j18 else :l13 end @@ -371,12 +371,12 @@ def l14 # IMS > Now? def l15 - metadata['If-Modified-Since'] > Time.now ? :m16 : :l17 + (metadata['If-Modified-Since'] > Time.now) ? :m16 : :l17 end # Last-Modified > IMS? def l17 - resource.last_modified.nil? || resource.last_modified > metadata['If-Modified-Since'] ? :m16 : 304 + (resource.last_modified.nil? || resource.last_modified > metadata['If-Modified-Since']) ? :m16 : 304 end # POST? @@ -415,7 +415,7 @@ def n11 if resource.post_is_create? case uri = resource.create_path when nil - raise InvalidResource, t('create_path_nil', :class => resource.class) + raise InvalidResource, t('create_path_nil', class: resource.class) when URI, String base_uri = resource.base_uri || request.base_uri new_uri = URI.join(base_uri.to_s, uri) @@ -431,7 +431,7 @@ def n11 when Integer return result else - raise InvalidResource, t('process_post_invalid', :result => result.inspect) + raise InvalidResource, t('process_post_invalid', result: result.inspect) end end if response.is_redirect? @@ -471,7 +471,7 @@ def o18 if request.get? || request.head? add_caching_headers content_type = metadata[CONTENT_TYPE] - handler = resource.content_types_provided.find {|ct, _| content_type.type_matches?(MediaType.parse(ct)) }.last + handler = resource.content_types_provided.find { |ct, _| content_type.type_matches?(MediaType.parse(ct)) }.last result = resource.send(handler) if Integer === result result @@ -507,9 +507,8 @@ def p3 # New resource? def p11 - !response.headers[LOCATION] ? :o20 : 201 + (!response.headers[LOCATION]) ? :o20 : 201 end - end # module Flow end # module Decision end # module Webmachine diff --git a/lib/webmachine/decision/fsm.rb b/lib/webmachine/decision/fsm.rb index f3252551..44ec2484 100644 --- a/lib/webmachine/decision/fsm.rb +++ b/lib/webmachine/decision/fsm.rb @@ -36,11 +36,11 @@ def run when Symbol # Next state state = result else # You bwoke it - raise InvalidResource, t('fsm_broke', :state => state, :result => result.inspect) + raise InvalidResource, t('fsm_broke', state: state, result: result.inspect) end end rescue => e - Webmachine.render_error(500, request, response, :message => e.message) + Webmachine.render_error(500, request, response, message: e.message) ensure trace_response(response) end @@ -53,11 +53,11 @@ def handle_exceptions resource.handle_exception(e) 500 rescue MalformedRequest => e - Webmachine.render_error(400, request, response, :message => e.message) + Webmachine.render_error(400, request, response, message: e.message) 400 end - def respond(code, headers={}) + def respond(code, headers = {}) response.code = code response.headers.merge!(headers) case code diff --git a/lib/webmachine/decision/helpers.rb b/lib/webmachine/decision/helpers.rb index f445175a..892ad063 100644 --- a/lib/webmachine/decision/helpers.rb +++ b/lib/webmachine/decision/helpers.rb @@ -31,24 +31,24 @@ def encode_body body = response.body chosen_charset = metadata[CHARSET] chosen_encoding = metadata[CONTENT_ENCODING] - charsetter = resource.charsets_provided && resource.charsets_provided.find {|c,_| c == chosen_charset }.last || :charset_nop + charsetter = resource.charsets_provided&.find { |c, _| c == chosen_charset }&.last || :charset_nop encoder = resource.encodings_provided[chosen_encoding] response.body = case body - when String # 1.8 treats Strings as Enumerable - resource.send(encoder, resource.send(charsetter, body)) - when IO, StringIO - IOEncoder.new(resource, encoder, charsetter, body) - when Fiber - FiberEncoder.new(resource, encoder, charsetter, body) - when Enumerable - EnumerableEncoder.new(resource, encoder, charsetter, body) - else - if body.respond_to?(:call) - CallableEncoder.new(resource, encoder, charsetter, body) - else - resource.send(encoder, resource.send(charsetter, body)) - end - end + when String # 1.8 treats Strings as Enumerable + resource.send(encoder, resource.send(charsetter, body)) + when IO, StringIO + IOEncoder.new(resource, encoder, charsetter, body) + when Fiber + FiberEncoder.new(resource, encoder, charsetter, body) + when Enumerable + EnumerableEncoder.new(resource, encoder, charsetter, body) + else + if body.respond_to?(:call) + CallableEncoder.new(resource, encoder, charsetter, body) + else + resource.send(encoder, resource.send(charsetter, body)) + end + end if body_is_fixed_length? ensure_content_length(response) else @@ -60,7 +60,7 @@ def encode_body # Assists in receiving request bodies def accept_helper content_type = MediaType.parse(request.content_type || 'application/octet-stream') - acceptable = resource.content_types_accepted.find {|ct, _| content_type.match?(ct) } + acceptable = resource.content_types_accepted.find { |ct, _| content_type.match?(ct) } if acceptable resource.send(acceptable.last) else @@ -71,10 +71,10 @@ def accept_helper # Computes the entries for the 'Vary' response header def variances resource.variances.tap do |v| - v.unshift "Accept-Language" if resource.languages_provided.size > 1 - v.unshift "Accept-Charset" if resource.charsets_provided && resource.charsets_provided.size > 1 - v.unshift "Accept-Encoding" if resource.encodings_provided.size > 1 - v.unshift "Accept" if resource.content_types_provided.size > 1 + v.unshift 'Accept-Language' if resource.languages_provided.size > 1 + v.unshift 'Accept-Charset' if resource.charsets_provided && resource.charsets_provided.size > 1 + v.unshift 'Accept-Encoding' if resource.encodings_provided.size > 1 + v.unshift 'Accept' if resource.content_types_provided.size > 1 end end diff --git a/lib/webmachine/dispatcher/route.rb b/lib/webmachine/dispatcher/route.rb index 0f4b82ee..b7a27ce3 100644 --- a/lib/webmachine/dispatcher/route.rb +++ b/lib/webmachine/dispatcher/route.rb @@ -28,6 +28,21 @@ class Route # String version of MATCH_ALL, deprecated. Use the symbol instead. MATCH_ALL_STR = '*'.freeze + # Decode a string using the scheme described in RFC 3986 2.1. Percent-Encoding (https://www.ietf.org/rfc/rfc3986.txt) + def self.rfc3986_percent_decode(value) + s = StringScanner.new(value) + result = '' + until s.eos? + encoded_val = s.scan(/%([0-9a-fA-F]){2}/) + result << if encoded_val.nil? + s.getch + else + [encoded_val[1..-1]].pack('H*') + end + end + result + end + # Creates a new Route that will associate a pattern to a # {Resource}. # @@ -59,24 +74,24 @@ class Route # @yieldparam [Request] req the request object # @see Dispatcher#add_route def initialize(path_spec, *args, &block) - if args.last.is_a? Hash - bindings = args.pop + bindings = if args.last.is_a? Hash + args.pop else - bindings = {} + {} end resource = args.pop guards = args - guards << block if block_given? + guards << block if block warn t('match_all_symbol') if path_spec.include? MATCH_ALL_STR @path_spec = path_spec - @guards = guards - @resource = resource - @bindings = bindings + @guards = guards + @resource = resource + @bindings = bindings - raise ArgumentError, t('not_resource_class', :class => resource.name) unless resource < Resource + raise ArgumentError, t('not_resource_class', class: resource.name) unless resource < Resource end # Determines whether the given request matches this route and @@ -94,11 +109,12 @@ def apply(request) request.disp_path = request.routing_tokens.join(SLASH) request.path_info = @bindings.dup tokens = request.routing_tokens - depth, trailing = bind(tokens, request.path_info) + _depth, trailing = bind(tokens, request.path_info) request.path_tokens = trailing || [] end private + # Attempts to match the path spec against the path tokens, while # accumulating variable bindings. # @param [Array] tokens the list of path segments @@ -125,9 +141,8 @@ def bind(tokens, bindings) if spec.first.named_captures.empty? bindings[:captures] = (bindings[:captures] || []) + matches.captures else - spec.first.named_captures.reduce(bindings) do |bindings, (name, idxs)| - bindings[name.to_sym] = matches.captures[idxs.first-1] - bindings + spec.first.named_captures.each_with_object(bindings) do |(name, idxs), bindings| + bindings[name.to_sym] = matches.captures[idxs.first - 1] end end else @@ -144,21 +159,6 @@ def bind(tokens, bindings) depth += 1 end end - - # Decode a string using the scheme described in RFC 3986 2.1. Percent-Encoding (https://www.ietf.org/rfc/rfc3986.txt) - def self.rfc3986_percent_decode(value) - s = StringScanner.new(value) - result = '' - until s.eos? - encoded_val = s.scan(/%([0-9a-fA-F]){2}/) - result << if encoded_val.nil? - s.getch - else - [encoded_val[1..-1]].pack('H*') - end - end - result - end end # class Route end # module Dispatcher end # module Webmachine diff --git a/lib/webmachine/errors.rb b/lib/webmachine/errors.rb index 72477c73..8ebb1c9f 100644 --- a/lib/webmachine/errors.rb +++ b/lib/webmachine/errors.rb @@ -14,23 +14,22 @@ module Webmachine # @param [Response] req the response object # @param [Hash] options keys to override the defaults when rendering # the response body - def self.render_error(code, req, res, options={}) + def self.render_error(code, req, res, options = {}) res.code = code unless res.body title, message = t(["errors.#{code}.title", "errors.#{code}.message"], - { :method => req.method, - :error => res.error}.merge(options)) - res.body = t("errors.standard_body", - {:title => title, - :message => message, - :version => Webmachine::SERVER_STRING}.merge(options)) + {method: req.method, + error: res.error}.merge(options)) + res.body = t('errors.standard_body', + {title: title, + message: message, + version: Webmachine::SERVER_STRING}.merge(options)) res.headers[CONTENT_TYPE] = TEXT_HTML end ensure_content_length(res) ensure_date_header(res) end - # Superclass of all errors generated by Webmachine. class Error < ::StandardError; end diff --git a/lib/webmachine/media_type.rb b/lib/webmachine/media_type.rb index d6bdf988..da0c12d0 100644 --- a/lib/webmachine/media_type.rb +++ b/lib/webmachine/media_type.rb @@ -23,11 +23,11 @@ def self.parse(obj) obj when MEDIA_TYPE_REGEX type, raw_params = $1, $2 - params = Hash[raw_params.scan(PARAMS_REGEX).map { |m| [m[0], m[2].to_s] }] + params = raw_params.scan(PARAMS_REGEX).map { |m| [m[0], m[2].to_s] }.to_h new(type, params) else unless Array === obj && String === obj[0] && Hash === obj[1] - raise ArgumentError, t('invalid_media_type', :type => obj.inspect) + raise ArgumentError, t('invalid_media_type', type: obj.inspect) end type = parse(obj[0]) type.params.merge!(obj[1]) @@ -43,7 +43,7 @@ def self.parse(obj) # @param [String] type the main media type, e.g. application/json # @param [Hash] params the media type parameters - def initialize(type, params={}) + def initialize(type, params = {}) @type, @params = type, params end @@ -88,13 +88,13 @@ def match?(other) # @param [Hash] params the requested params # @return [true,false] whether it is an acceptable match def params_match?(other) - other.all? {|k,v| params[k] == v } + other.all? { |k, v| params[k] == v } end # Reconstitutes the type into a String # @return [String] the type as a String def to_s - [type, *params.map {|k,v| "#{k}=#{v}" }].join(";") + [type, *params.map { |k, v| "#{k}=#{v}" }].join(';') end # @return [String] The major type, e.g. "application", "text", "image" diff --git a/lib/webmachine/quoted_string.rb b/lib/webmachine/quoted_string.rb index 7c09a91c..dd5039e0 100644 --- a/lib/webmachine/quoted_string.rb +++ b/lib/webmachine/quoted_string.rb @@ -19,10 +19,10 @@ def unquote(str) # Ensures that quotes exist around a quoted-string def quote(str) - if str =~ QS_ANCHORED + if QS_ANCHORED.match?(str) str else - %Q{"#{escape_quotes str}"} + %("#{escape_quotes str}") end end @@ -33,7 +33,7 @@ def escape_quotes(str) # Unescapes quotes within a quoted string def unescape_quotes(str) - str.gsub(%r{\\}, '') + str.delete('\\') end end end diff --git a/lib/webmachine/request.rb b/lib/webmachine/request.rb index bad4f1f3..f8f3b771 100644 --- a/lib/webmachine/request.rb +++ b/lib/webmachine/request.rb @@ -21,7 +21,7 @@ class Request # @param [Headers] headers the HTTP request headers # @param [String,#to_s,#each,nil] body the entity included in the # request, if present - def initialize(method, uri, headers, body, routing_tokens=nil, base_uri=nil) + def initialize(method, uri, headers, body, routing_tokens = nil, base_uri = nil) @method, @headers, @body = method, headers, body @uri = build_uri(uri, headers) @routing_tokens = routing_tokens || @uri.path.match(ROUTING_PATH_MATCH)[1].split(SLASH) @@ -37,12 +37,12 @@ def initialize(method, uri, headers, body, routing_tokens=nil, base_uri=nil) # lowercased-underscored version of the header name, e.g. # `if_unmodified_since`. def method_missing(m, *args, &block) - if m =~ HTTP_HEADERS_MATCH + if HTTP_HEADERS_MATCH.match?(m) # Access headers more easily as underscored methods. header_name = m.to_s.tr(UNDERSCORE, DASH) if (header_value = @headers[header_name]) # Make future lookups faster. - self.class.class_eval <<-RUBY, __FILE__, __LINE__ + self.class.class_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{m} @headers["#{header_name}"] end @@ -66,8 +66,8 @@ def has_body? def query unless @query @query = {} - (uri.query || '').split(/&/).each do |kv| - key, value = kv.split(/=/) + (uri.query || '').split('&').each do |kv| + key, value = kv.split('=') if key && value key, value = CGI.unescape(key), CGI.unescape(value) @query[key] = value @@ -82,9 +82,7 @@ def query # @return [Hash] # {} if no Cookies header set def cookies - unless @cookies - @cookies = Webmachine::Cookie.parse(headers['Cookie']) - end + @cookies ||= Webmachine::Cookie.parse(headers['Cookie']) @cookies end @@ -93,7 +91,7 @@ def cookies # @return [Boolean] # true if this request was made via HTTPS def https? - uri.scheme == "https" + uri.scheme == 'https' end # Is this a GET request? @@ -191,6 +189,5 @@ def build_uri(uri, headers) parse_host(uri, headers.fetch(HOST)) end - end # class Request end # module Webmachine diff --git a/lib/webmachine/resource/authentication.rb b/lib/webmachine/resource/authentication.rb index d3a3e976..427c9a36 100644 --- a/lib/webmachine/resource/authentication.rb +++ b/lib/webmachine/resource/authentication.rb @@ -23,14 +23,13 @@ module Authentication # @yieldparam [String] user the passed username # @yieldparam [String] password the passed password # @yieldreturn [true,false] whether the username/password is correct - def basic_auth(header, realm="Webmachine") - if header =~ BASIC_HEADER && (yield *$1.unpack('m*').first.split(/:/,2)) + def basic_auth(header, realm = 'Webmachine') + if header =~ BASIC_HEADER && yield(*$1.unpack1('m*').split(/:/, 2)) true else - %Q[Basic realm="#{realm}"] + %(Basic realm="#{realm}") end end - end # module Authentication end # class Resource end # module Webmachine diff --git a/lib/webmachine/resource/encodings.rb b/lib/webmachine/resource/encodings.rb index 40987f1e..3e6c0cad 100644 --- a/lib/webmachine/resource/encodings.rb +++ b/lib/webmachine/resource/encodings.rb @@ -15,23 +15,17 @@ def encode_identity(data) # The 'deflate' encoding, which uses libz's DEFLATE compression. def encode_deflate(data) # The deflate options were borrowed from Rack and Mongrel1. - Zlib::Deflate.deflate(data, *[Zlib::DEFAULT_COMPRESSION, - # drop the zlib header which causes both Safari and IE to choke - -Zlib::MAX_WBITS, - Zlib::DEF_MEM_LEVEL, - Zlib::DEFAULT_STRATEGY - ]) + Zlib::Deflate.deflate(data, Zlib::DEFAULT_COMPRESSION, -Zlib::MAX_WBITS, Zlib::DEF_MEM_LEVEL, Zlib::DEFAULT_STRATEGY) end # The 'gzip' encoding, which uses GNU Zip (via libz). # @note Because of the header/checksum requirements, gzip cannot # be used on streamed responses. def encode_gzip(data) - "".tap do |out| - Zlib::GzipWriter.wrap(StringIO.new(out)){|gz| gz << data } + ''.tap do |out| + Zlib::GzipWriter.wrap(StringIO.new(out)) { |gz| gz << data } end end - end # module Encodings end # class Resource end # module Webmachine diff --git a/lib/webmachine/response.rb b/lib/webmachine/response.rb index f1812259..73fee48e 100644 --- a/lib/webmachine/response.rb +++ b/lib/webmachine/response.rb @@ -35,7 +35,7 @@ def initialize # of the target resource, or manually set the Location header # using {#headers}. # @param [String, URI] location the target of the redirection - def do_redirect(location=nil) + def do_redirect(location = nil) headers['Location'] = location.to_s if location self.redirect = true end @@ -54,8 +54,8 @@ def set_cookie(name, value, attributes = {}) end end - alias :is_redirect? :redirect - alias :redirect_to :do_redirect + alias_method :is_redirect?, :redirect + alias_method :redirect_to, :do_redirect # A {Hash} that can flatten array values into single values with a separator class HeaderHash < ::Hash @@ -63,17 +63,15 @@ class HeaderHash < ::Hash # @param [String] The separator used to join Array values # @return [HeaderHash] A new {HeaderHash} with Array values flattened def flattened(separator = ',') - Hash[self.collect { |k,v| + collect { |k, v| case v when Array - [k,v.join(separator)] + [k, v.join(separator)] else - [k,v] + [k, v] end - }] - + }.to_h end end - end # class Response end # module Webmachine diff --git a/lib/webmachine/spec/adapter_lint.rb b/lib/webmachine/spec/adapter_lint.rb index 3bb08359..8a32b809 100644 --- a/lib/webmachine/spec/adapter_lint.rb +++ b/lib/webmachine/spec/adapter_lint.rb @@ -1,7 +1,7 @@ -require "webmachine/spec/test_resource" -require "net/http" +require 'webmachine/spec/test_resource' +require 'net/http' -ADDRESS = "127.0.0.1" +ADDRESS = '127.0.0.1' shared_examples_for :adapter_lint do attr_reader :client @@ -20,7 +20,7 @@ def find_free_port def create_test_application(port) Webmachine::Application.new.tap do |application| - application.dispatcher.add_route ["test"], Test::Resource + application.dispatcher.add_route ['test'], Test::Resource application.configure do |c| c.ip = ADDRESS @@ -62,9 +62,9 @@ def wait_until_server_responds_to(client) @server_thread.kill end - it "provides the request URI" do - request = Net::HTTP::Get.new("/test") - request["Accept"] = "test/response.request_uri" + it 'provides the request URI' do + request = Net::HTTP::Get.new('/test') + request['Accept'] = 'test/response.request_uri' response = client.request(request) expect(response.body).to eq("http://#{ADDRESS}:#{@port}/test") end @@ -80,92 +80,92 @@ def wait_until_server_responds_to(client) # end # end - it "provides a string-like request body" do - request = Net::HTTP::Put.new("/test") - request.body = "Hello, World!" - request["Content-Type"] = "test/request.stringbody" + it 'provides a string-like request body' do + request = Net::HTTP::Put.new('/test') + request.body = 'Hello, World!' + request['Content-Type'] = 'test/request.stringbody' response = client.request(request) - expect(response["Content-Length"]).to eq("21") - expect(response.body).to eq("String: Hello, World!") + expect(response['Content-Length']).to eq('21') + expect(response.body).to eq('String: Hello, World!') end - it "provides an enumerable request body" do - request = Net::HTTP::Put.new("/test") - request.body = "Hello, World!" - request["Content-Type"] = "test/request.enumbody" + it 'provides an enumerable request body' do + request = Net::HTTP::Put.new('/test') + request.body = 'Hello, World!' + request['Content-Type'] = 'test/request.enumbody' response = client.request(request) - expect(response["Content-Length"]).to eq("19") - expect(response.body).to eq("Enum: Hello, World!") + expect(response['Content-Length']).to eq('19') + expect(response.body).to eq('Enum: Hello, World!') end - it "handles missing pages" do - request = Net::HTTP::Get.new("/missing") + it 'handles missing pages' do + request = Net::HTTP::Get.new('/missing') response = client.request(request) - expect(response.code).to eq("404") - expect(response["Content-Type"]).to eq("text/html") + expect(response.code).to eq('404') + expect(response['Content-Type']).to eq('text/html') end - it "handles empty response bodies" do - request = Net::HTTP::Post.new("/test") - request.body = "" + it 'handles empty response bodies' do + request = Net::HTTP::Post.new('/test') + request.body = '' response = client.request(request) - expect(response.code).to eq("204") - expect(["0", nil]).to include(response["Content-Length"]) + expect(response.code).to eq('204') + expect(['0', nil]).to include(response['Content-Length']) expect(response.body).to be_nil end - it "handles string response bodies" do - request = Net::HTTP::Get.new("/test") - request["Accept"] = "test/response.stringbody" + it 'handles string response bodies' do + request = Net::HTTP::Get.new('/test') + request['Accept'] = 'test/response.stringbody' response = client.request(request) - expect(response["Content-Length"]).to eq("20") - expect(response.body).to eq("String response body") + expect(response['Content-Length']).to eq('20') + expect(response.body).to eq('String response body') end - it "handles enumerable response bodies" do - request = Net::HTTP::Get.new("/test") - request["Accept"] = "test/response.enumbody" + it 'handles enumerable response bodies' do + request = Net::HTTP::Get.new('/test') + request['Accept'] = 'test/response.enumbody' response = client.request(request) - expect(response["Transfer-Encoding"]).to eq("chunked") - expect(response.body).to eq("Enumerable response body") + expect(response['Transfer-Encoding']).to eq('chunked') + expect(response.body).to eq('Enumerable response body') end - it "handles proc response bodies" do - request = Net::HTTP::Get.new("/test") - request["Accept"] = "test/response.procbody" + it 'handles proc response bodies' do + request = Net::HTTP::Get.new('/test') + request['Accept'] = 'test/response.procbody' response = client.request(request) - expect(response["Transfer-Encoding"]).to eq("chunked") - expect(response.body).to eq("Proc response body") + expect(response['Transfer-Encoding']).to eq('chunked') + expect(response.body).to eq('Proc response body') end - it "handles fiber response bodies" do - request = Net::HTTP::Get.new("/test") - request["Accept"] = "test/response.fiberbody" + it 'handles fiber response bodies' do + request = Net::HTTP::Get.new('/test') + request['Accept'] = 'test/response.fiberbody' response = client.request(request) - expect(response["Transfer-Encoding"]).to eq("chunked") - expect(response.body).to eq("Fiber response body") + expect(response['Transfer-Encoding']).to eq('chunked') + expect(response.body).to eq('Fiber response body') end - it "handles io response bodies" do - request = Net::HTTP::Get.new("/test") - request["Accept"] = "test/response.iobody" + it 'handles io response bodies' do + request = Net::HTTP::Get.new('/test') + request['Accept'] = 'test/response.iobody' response = client.request(request) - expect(response["Content-Length"]).to eq("17") + expect(response['Content-Length']).to eq('17') expect(response.body).to eq("IO response body\n") end - it "handles request cookies" do - request = Net::HTTP::Get.new("/test") - request["Accept"] = "test/response.cookies" - request["Cookie"] = "echo=echocookie" + it 'handles request cookies' do + request = Net::HTTP::Get.new('/test') + request['Accept'] = 'test/response.cookies' + request['Cookie'] = 'echo=echocookie' response = client.request(request) - expect(response.body).to eq("echocookie") + expect(response.body).to eq('echocookie') end - it "handles response cookies" do - request = Net::HTTP::Get.new("/test") - request["Accept"] = "test/response.cookies" + it 'handles response cookies' do + request = Net::HTTP::Get.new('/test') + request['Accept'] = 'test/response.cookies' response = client.request(request) - expect(response["Set-Cookie"]).to eq("cookie=monster, rodeo=clown") + expect(response['Set-Cookie']).to eq('cookie=monster, rodeo=clown') end end diff --git a/lib/webmachine/spec/test_resource.rb b/lib/webmachine/spec/test_resource.rb index 92895d83..cc949216 100644 --- a/lib/webmachine/spec/test_resource.rb +++ b/lib/webmachine/spec/test_resource.rb @@ -1,35 +1,35 @@ module Test class Resource < Webmachine::Resource def allowed_methods - ["GET", "PUT", "POST"] + ['GET', 'PUT', 'POST'] end def content_types_accepted [ - ["test/request.stringbody", :from_string], - ["test/request.enumbody", :from_enum] + ['test/request.stringbody', :from_string], + ['test/request.enumbody', :from_enum] ] end def content_types_provided [ - ["test/response.stringbody", :to_string], - ["test/response.enumbody", :to_enum], - ["test/response.procbody", :to_proc], - ["test/response.fiberbody", :to_fiber], - ["test/response.iobody", :to_io_body], - ["test/response.cookies", :to_cookies], - ["test/response.request_uri", :to_request_uri], - ["test/response.rack_env", :to_rack_env] + ['test/response.stringbody', :to_string], + ['test/response.enumbody', :to_enum], + ['test/response.procbody', :to_proc], + ['test/response.fiberbody', :to_fiber], + ['test/response.iobody', :to_io_body], + ['test/response.cookies', :to_cookies], + ['test/response.request_uri', :to_request_uri], + ['test/response.rack_env', :to_rack_env] ] end def from_string - response.body = "String: #{request.body.to_s}" + response.body = "String: #{request.body}" end def from_enum - response.body = "Enum: " + response.body = 'Enum: ' request.body.each do |part| response.body += part end @@ -41,22 +41,22 @@ def process_post end def to_string - "String response body" + 'String response body' end def to_enum - ["Enumerable ", "response " "body"] + ['Enumerable ', 'response ', 'body'] end def to_proc - Proc.new { "Proc response body" } + proc { 'Proc response body' } end def to_fiber Fiber.new do - Fiber.yield "Fiber " - Fiber.yield "response " - "body" + Fiber.yield 'Fiber ' + Fiber.yield 'response ' + 'body' end end @@ -65,12 +65,12 @@ def to_io_body end def to_cookies - response.set_cookie("cookie", "monster") - response.set_cookie("rodeo", "clown") + response.set_cookie('cookie', 'monster') + response.set_cookie('rodeo', 'clown') # FIXME: Mongrel/WEBrick fail if this method returns nil # Might be a net/http issue. Is this a bug? # @see Flow#o18, Helpers#encode_body_if_set - request.cookies["echo"] || "" + request.cookies['echo'] || '' end def to_request_uri diff --git a/lib/webmachine/streaming/encoder.rb b/lib/webmachine/streaming/encoder.rb index 0ad9f9e3..da7f139f 100644 --- a/lib/webmachine/streaming/encoder.rb +++ b/lib/webmachine/streaming/encoder.rb @@ -16,8 +16,8 @@ def initialize(resource, encoder, charsetter, body) # the encoder and/or charsetter. Only returns true if using the # built-in "encode_identity" and "charset_nop" methods. def is_unencoded? - encoder.to_s == "encode_identity" && - charsetter.to_s == "charset_nop" + encoder.to_s == 'encode_identity' && + charsetter.to_s == 'charset_nop' end end # class Encoder end # module Streaming diff --git a/lib/webmachine/streaming/io_encoder.rb b/lib/webmachine/streaming/io_encoder.rb index 4c058f97..d3d94456 100644 --- a/lib/webmachine/streaming/io_encoder.rb +++ b/lib/webmachine/streaming/io_encoder.rb @@ -13,7 +13,7 @@ class IOEncoder < Encoder # @yield [chunk] # @yieldparam [String] chunk a chunk of the response, encoded def each - while chunk = body.read(CHUNK_SIZE) and chunk != "" + while (chunk = body.read(CHUNK_SIZE)) && (chunk != '') yield resource.send(encoder, resource.send(charsetter, chunk)) end end @@ -26,7 +26,7 @@ def copy_stream(outstream) if can_copy_stream? IO.copy_stream(body, outstream) else - each {|chunk| outstream << chunk } + each { |chunk| outstream << chunk } end end @@ -60,9 +60,10 @@ def empty? size == 0 end - alias bytesize size + alias_method :bytesize, :size private + def can_copy_stream? IO.respond_to?(:copy_stream) && is_unencoded? && !is_string_io? end diff --git a/lib/webmachine/trace/fsm.rb b/lib/webmachine/trace/fsm.rb index 49b24ae1..d01b86ca 100644 --- a/lib/webmachine/trace/fsm.rb +++ b/lib/webmachine/trace/fsm.rb @@ -23,39 +23,46 @@ def trace? # Adds the request to the trace. # @param [Webmachine::Request] request the request to be traced def trace_request(request) - response.trace << { - :type => :request, - :method => request.method, - :path => request.uri.request_uri.to_s, - :headers => request.headers, - :body => request.body.to_s - } if trace? + if trace? + response.trace << { + type: :request, + method: request.method, + path: request.uri.request_uri.to_s, + headers: request.headers, + body: request.body.to_s + } + end end # Adds the response to the trace and then commits the trace to # separate storage which can be discovered by the debugger. # @param [Webmachine::Response] response the response to be traced def trace_response(response) - response.trace << { - :type => :response, - :code => response.code.to_s, - :headers => response.headers, - :body => trace_response_body(response.body) - } if trace? + if trace? + response.trace << { + type: :response, + code: response.code.to_s, + headers: response.headers, + body: trace_response_body(response.body) + } + end ensure - Webmachine::Events.publish('wm.trace.record', { - :trace_id => resource.object_id.to_s, - :trace => response.trace - }) if trace? + if trace? + Webmachine::Events.publish('wm.trace.record', { + trace_id: resource.object_id.to_s, + trace: response.trace + }) + end end # Adds a decision to the trace. # @param [Symbol] decision the decision being processed def trace_decision(decision) - response.trace << {:type => :decision, :decision => decision} if trace? + response.trace << {type: :decision, decision: decision} if trace? end private + # Works around streaming encoders where possible def trace_response_body(body) case body diff --git a/lib/webmachine/trace/resource_proxy.rb b/lib/webmachine/trace/resource_proxy.rb index 71cca9b1..bc9b02bf 100644 --- a/lib/webmachine/trace/resource_proxy.rb +++ b/lib/webmachine/trace/resource_proxy.rb @@ -69,7 +69,7 @@ def attempt(callback, args) log[:name] = "(default)##{method.name}" else log[:name] = "#{method.owner.name}##{method.name}" - log[:source] = method.source_location.join(":") if method.respond_to?(:source_location) + log[:source] = method.source_location.join(':') if method.respond_to?(:source_location) end unless args.empty? log[:args] = args diff --git a/lib/webmachine/trace/trace_resource.rb b/lib/webmachine/trace/trace_resource.rb index e8d60d6b..be9855c2 100644 --- a/lib/webmachine/trace/trace_resource.rb +++ b/lib/webmachine/trace/trace_resource.rb @@ -7,15 +7,14 @@ module Trace # includes serving the static files (the PNG flow diagram, CSS and # JS for the UI) and the HTML for the individual traces. class TraceResource < Resource - - MAP_EXTERNAL = %w{static map.png} - MAP_FILE = File.expand_path("../static/http-headers-status-v3.png", __FILE__) - SCRIPT_EXTERNAL = %w{static wmtrace.js} - SCRIPT_FILE = File.expand_path("../#{SCRIPT_EXTERNAL.join '/'}", __FILE__) - STYLE_EXTERNAL = %w{static wmtrace.css} - STYLE_FILE = File.expand_path("../#{STYLE_EXTERNAL.join '/'}", __FILE__) - TRACELIST_ERB = File.expand_path("../static/tracelist.erb", __FILE__) - TRACE_ERB = File.expand_path("../static/trace.erb", __FILE__) + MAP_EXTERNAL = %w[static map.png] + MAP_FILE = File.expand_path('../static/http-headers-status-v3.png', __FILE__) + SCRIPT_EXTERNAL = %w[static wmtrace.js] + SCRIPT_FILE = File.expand_path("../#{SCRIPT_EXTERNAL.join "/"}", __FILE__) + STYLE_EXTERNAL = %w[static wmtrace.css] + STYLE_FILE = File.expand_path("../#{STYLE_EXTERNAL.join "/"}", __FILE__) + TRACELIST_ERB = File.expand_path('../static/tracelist.erb', __FILE__) + TRACE_ERB = File.expand_path('../static/trace.erb', __FILE__) # The ERB template for the trace list def self.tracelist @@ -30,15 +29,15 @@ def self.trace def content_types_provided case request.path_tokens when [] - [["text/html", :produce_list]] + [['text/html', :produce_list]] when MAP_EXTERNAL - [["image/png", :produce_file]] + [['image/png', :produce_file]] when SCRIPT_EXTERNAL - [["text/javascript", :produce_file]] + [['text/javascript', :produce_file]] when STYLE_EXTERNAL - [["text/css", :produce_file]] + [['text/css', :produce_file]] else - [["text/html", :produce_trace]] + [['text/html', :produce_trace]] end end @@ -73,12 +72,12 @@ def produce_file # TODO: Add support for IO objects as response bodies, # allowing server optimizations like sendfile or chunked # downloads - open(@file, "rb") {|io| io.read } + File.binread(@file) end def produce_list - base = request.uri.path.chomp("/") - traces = Trace.traces.map {|t| [ t, "#{base}/#{t}" ] } + base = request.uri.path.chomp('/') + traces = Trace.traces.map { |t| [t, "#{base}/#{t}"] } self.class.tracelist.result(binding) end @@ -96,22 +95,22 @@ def encode_trace(data) tres = data.pop.dup treq.delete :type tres.delete :type - [ MultiJson.dump(treq), MultiJson.dump(tres), MultiJson.dump(encode_decisions(data)) ] + [MultiJson.dump(treq), MultiJson.dump(tres), MultiJson.dump(encode_decisions(data))] end def encode_decisions(decisions) - decisions.inject([]) do |list, event| + decisions.each_with_object([]) do |event, list| case event[:type] when :decision # Don't produce new decisions for sub-steps in the graph - unless event[:decision].to_s =~ /[a-z]$/ + unless /[a-z]$/.match?(event[:decision].to_s) list << {'d' => event[:decision], 'calls' => []} end when :attempt list.last['calls'] << { - "call" => event[:name], - "source" => event[:source], - "input" => event[:args] && event[:args].inspect + 'call' => event[:name], + 'source' => event[:source], + 'input' => event[:args] && event[:args].inspect } when :result list.last['calls'].last['output'] = event[:value].inspect @@ -122,7 +121,6 @@ def encode_decisions(decisions) 'message' => event[:message] } end - list end end end diff --git a/lib/webmachine/translation.rb b/lib/webmachine/translation.rb index 9d72c459..2c437ba7 100644 --- a/lib/webmachine/translation.rb +++ b/lib/webmachine/translation.rb @@ -1,7 +1,7 @@ require 'set' require 'i18n' I18n.enforce_available_locales = true if I18n.respond_to?(:enforce_available_locales) -I18n.config.load_path << File.expand_path("../locale/en.yml", __FILE__) +I18n.config.load_path << File.expand_path('../locale/en.yml', __FILE__) module Webmachine # Provides an interface to the I18n library specifically for diff --git a/lib/webmachine/version.rb b/lib/webmachine/version.rb index 02210c54..d38fd901 100644 --- a/lib/webmachine/version.rb +++ b/lib/webmachine/version.rb @@ -1,6 +1,6 @@ module Webmachine # Library version - VERSION = "1.6.0".freeze + VERSION = '1.6.0'.freeze # String for use in "Server" HTTP response header, which includes # the {VERSION}. diff --git a/memory_test.rb b/memory_test.rb index 1bf0246e..29abc5ff 100644 --- a/memory_test.rb +++ b/memory_test.rb @@ -1,8 +1,8 @@ -$:.push File.expand_path("../lib", __FILE__) +$:.push File.expand_path('../lib', __FILE__) require 'webmachine' class Constantized < Webmachine::Resource - HELLO_WORLD = "Hello World".freeze + HELLO_WORLD = 'Hello World'.freeze ALLOWED_METHODS = ['GET'.freeze].freeze CONTENT_TYPES_PROVIDED = [['text/html'.freeze, :to_html].freeze].freeze @@ -34,4 +34,3 @@ def to_html end report.pretty_print - diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 00eaf7c6..a63215df 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,15 +1,15 @@ -require "bundler/setup" +require 'bundler/setup' Bundler.require :default, :test require 'logger' class NullLogger < Logger - def add(severity, message=nil, progname=nil, &block) + def add(severity, message = nil, progname = nil, &block) end end RSpec.configure do |config| config.mock_with :rspec - config.filter_run :focus => true + config.filter_run focus: true config.run_all_when_everything_filtered = true config.formatter = :documentation if ENV['CI'] if defined?(::Java) @@ -28,8 +28,8 @@ def add(severity, message=nil, progname=nil, &block) config.before(:suite) do options = { - :Logger => NullLogger.new(STDERR), - :AccessLog => [] + Logger: NullLogger.new($stderr), + AccessLog: [] } Webmachine::Adapters::WEBrick::DEFAULT_OPTIONS.merge! options Webmachine::Adapters::Rack::DEFAULT_OPTIONS.merge! options if defined?(Webmachine::Adapters::Rack) @@ -37,18 +37,18 @@ def add(severity, message=nil, progname=nil, &block) end # For use in specs that need a fully initialized resource -shared_context "default resource" do +shared_context 'default resource' do let(:method) { 'GET' } - let(:uri) { URI.parse("http://localhost/") } + let(:uri) { URI.parse('http://localhost/') } let(:headers) { Webmachine::Headers.new } - let(:body) { "" } + let(:body) { '' } let(:request) { Webmachine::Request.new(method, uri, headers, body) } let(:response) { Webmachine::Response.new } let(:resource_class) do Class.new(Webmachine::Resource) do def to_html - "Hello, world!" + 'Hello, world!' end end end diff --git a/spec/webmachine/adapter_spec.rb b/spec/webmachine/adapter_spec.rb index 28b5d7c3..b366d3cc 100644 --- a/spec/webmachine/adapter_spec.rb +++ b/spec/webmachine/adapter_spec.rb @@ -1,4 +1,4 @@ -require "spec_helper" +require 'spec_helper' describe Webmachine::Adapter do let(:application) { Webmachine::Application.new } @@ -10,14 +10,14 @@ described_class.new(application) end - describe "#initialize" do - it "stores the provided application" do + describe '#initialize' do + it 'stores the provided application' do expect(adapter.application).to eq(application) end end - describe ".run" do - it "creates a new adapter and runs it" do + describe '.run' do + it 'creates a new adapter and runs it' do adapter = double(described_class) expect(described_class).to receive(:new). @@ -30,8 +30,8 @@ end end - describe "#run" do - it "raises a NotImplementedError" do + describe '#run' do + it 'raises a NotImplementedError' do expect { adapter.run }.to raise_exception(NotImplementedError) end end diff --git a/spec/webmachine/adapters/rack_mapped_spec.rb b/spec/webmachine/adapters/rack_mapped_spec.rb index 6e82848f..ca944639 100644 --- a/spec/webmachine/adapters/rack_mapped_spec.rb +++ b/spec/webmachine/adapters/rack_mapped_spec.rb @@ -6,10 +6,10 @@ describe Webmachine::Adapters::RackMapped do it_should_behave_like :adapter_lint do - it "should set Server header" do - response = client.request(Net::HTTP::Get.new("/test")) - expect(response["Server"]).to match(/Webmachine/) - expect(response["Server"]).to match(/Rack/) + it 'should set Server header' do + response = client.request(Net::HTTP::Get.new('/test')) + expect(response['Server']).to match(/Webmachine/) + expect(response['Server']).to match(/Rack/) end end end @@ -17,15 +17,15 @@ describe Webmachine::Adapters::RackMapped do class CreateResource < Webmachine::Resource def allowed_methods - ["POST"] + ['POST'] end def content_types_accepted - [["application/json", :from_json]] + [['application/json', :from_json]] end def content_types_provided - [["application/json", :to_json]] + [['application/json', :to_json]] end def post_is_create? @@ -33,11 +33,11 @@ def post_is_create? end def create_path - "created_path_here/123" + 'created_path_here/123' end def from_json - response.body = %{ {"foo": "bar"} } + response.body = %( {"foo": "bar"} ) end end @@ -45,9 +45,9 @@ def from_json Rack::Builder.new do map '/some/route' do run(Webmachine::Application.new do |app| - app.add_route(["test"], Test::Resource) - app.add_route(["create_test"], CreateResource) - app.configure do | config | + app.add_route(['test'], Test::Resource) + app.add_route(['create_test'], CreateResource) + app.configure do |config| config.adapter = :RackMapped end end.adapter) @@ -55,17 +55,17 @@ def from_json end end - context "using Rack::Test" do + context 'using Rack::Test' do include Rack::Test::Methods - it "provides the full request URI" do - rack_response = get "some/route/test", nil, {"HTTP_ACCEPT" => "test/response.request_uri"} - expect(rack_response.body).to eq "http://example.org/some/route/test" + it 'provides the full request URI' do + rack_response = get 'some/route/test', nil, {'HTTP_ACCEPT' => 'test/response.request_uri'} + expect(rack_response.body).to eq 'http://example.org/some/route/test' end - it "provides LOCATION header using custom base_uri when creating from POST request" do - rack_response = post "/some/route/create_test", %{{"foo": "bar"}}, {"HTTP_ACCEPT" => "application/json", "CONTENT_TYPE" => "application/json"} - expect(rack_response.headers["Location"]).to eq("http://example.org/some/route/created_path_here/123") + it 'provides LOCATION header using custom base_uri when creating from POST request' do + rack_response = post '/some/route/create_test', %({"foo": "bar"}), {'HTTP_ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json'} + expect(rack_response.headers['Location']).to eq('http://example.org/some/route/created_path_here/123') end end end diff --git a/spec/webmachine/adapters/rack_spec.rb b/spec/webmachine/adapters/rack_spec.rb index c7771910..837a1e03 100644 --- a/spec/webmachine/adapters/rack_spec.rb +++ b/spec/webmachine/adapters/rack_spec.rb @@ -6,32 +6,32 @@ describe Webmachine::Adapters::Rack do it_should_behave_like :adapter_lint do - it "should set Server header" do - response = client.request(Net::HTTP::Get.new("/test")) - expect(response["Server"]).to match(/Webmachine/) - expect(response["Server"]).to match(/Rack/) + it 'should set Server header' do + response = client.request(Net::HTTP::Get.new('/test')) + expect(response['Server']).to match(/Webmachine/) + expect(response['Server']).to match(/Rack/) end end end describe Webmachine::Adapters::Rack::RackResponse do - context "on Rack < 1.5 release" do - before { allow(Rack).to receive_messages(:release => "1.4") } + context 'on Rack < 1.5 release' do + before { allow(Rack).to receive_messages(release: '1.4') } - it "should add Content-Type header on not acceptable response" do + it 'should add Content-Type header on not acceptable response' do rack_response = described_class.new(double(:body), 406, {}) - rack_status, rack_headers, rack_body = rack_response.finish - expect(rack_headers).to have_key("Content-Type") + _rack_status, rack_headers, _rack_body = rack_response.finish + expect(rack_headers).to have_key('Content-Type') end end - context "on Rack >= 1.5 release" do - before { allow(Rack).to receive_messages(:release => "1.5") } + context 'on Rack >= 1.5 release' do + before { allow(Rack).to receive_messages(release: '1.5') } - it "should not add Content-Type header on not acceptable response" do + it 'should not add Content-Type header on not acceptable response' do rack_response = described_class.new(double(:body), 406, {}) - rack_status, rack_headers, rack_body = rack_response.finish - expect(rack_headers).not_to have_key("Content-Type") + _rack_status, rack_headers, _rack_body = rack_response.finish + expect(rack_headers).not_to have_key('Content-Type') end end end @@ -39,24 +39,24 @@ describe Webmachine::Adapters::Rack do let(:app) do Webmachine::Application.new do |app| - app.add_route(["test"], Test::Resource) - app.configure do | config | + app.add_route(['test'], Test::Resource) + app.configure do |config| config.adapter = :Rack end end.adapter end - context "using Rack::Test" do + context 'using Rack::Test' do include Rack::Test::Methods - it "provides the full request URI" do - rack_response = get "test", nil, {"HTTP_ACCEPT" => "test/response.request_uri"} - expect(rack_response.body).to eq "http://example.org/test" + it 'provides the full request URI' do + rack_response = get 'test', nil, {'HTTP_ACCEPT' => 'test/response.request_uri'} + expect(rack_response.body).to eq 'http://example.org/test' end - it "provides the rack env on the request" do - rack_response = get "test", nil, {"HTTP_ACCEPT" => "test/response.rack_env"} - expect(JSON.parse(rack_response.body).keys).to include "rack.input" + it 'provides the rack env on the request' do + rack_response = get 'test', nil, {'HTTP_ACCEPT' => 'test/response.rack_env'} + expect(JSON.parse(rack_response.body).keys).to include 'rack.input' end end end diff --git a/spec/webmachine/adapters/webrick_spec.rb b/spec/webmachine/adapters/webrick_spec.rb index 2beb0c32..dfdc8489 100644 --- a/spec/webmachine/adapters/webrick_spec.rb +++ b/spec/webmachine/adapters/webrick_spec.rb @@ -1,12 +1,12 @@ -require "spec_helper" -require "webmachine/spec/adapter_lint" +require 'spec_helper' +require 'webmachine/spec/adapter_lint' describe Webmachine::Adapters::WEBrick do it_should_behave_like :adapter_lint do - it "should set Server header" do - response = client.request(Net::HTTP::Get.new("/test")) - expect(response["Server"]).to match(/Webmachine/) - expect(response["Server"]).to match(/WEBrick/) + it 'should set Server header' do + response = client.request(Net::HTTP::Get.new('/test')) + expect(response['Server']).to match(/Webmachine/) + expect(response['Server']).to match(/WEBrick/) end end end diff --git a/spec/webmachine/application_spec.rb b/spec/webmachine/application_spec.rb index e7894bb8..2469b2bb 100644 --- a/spec/webmachine/application_spec.rb +++ b/spec/webmachine/application_spec.rb @@ -4,12 +4,12 @@ let(:application) { described_class.new } let(:test_resource) { Class.new(Webmachine::Resource) } - it "accepts a Configuration when initialized" do + it 'accepts a Configuration when initialized' do config = Webmachine::Configuration.new('1.1.1.1', 9999, :Reel, {}) expect(described_class.new(config).configuration).to be(config) end - it "is yielded into a block provided during initialization" do + it 'is yielded into a block provided during initialization' do yielded_app = nil returned_app = described_class.new do |app| expect(app).to be_kind_of(Webmachine::Application) @@ -18,25 +18,25 @@ expect(returned_app).to be(yielded_app) end - it "is initialized with the default Configration if none is given" do + it 'is initialized with the default Configration if none is given' do expect(application.configuration).to eq(Webmachine::Configuration.default) end - it "returns the receiver from the configure call so you can chain it" do + it 'returns the receiver from the configure call so you can chain it' do expect(application.configure { |c| }).to equal(application) end - it "is configurable" do + it 'is configurable' do application.configure do |config| expect(config).to be_kind_of(Webmachine::Configuration) end end - it "is initialized with an empty Dispatcher" do + it 'is initialized with an empty Dispatcher' do expect(application.dispatcher.routes).to be_empty end - it "can have routes added" do + it 'can have routes added' do route = nil resource = test_resource # overcome instance_eval :/ @@ -50,24 +50,24 @@ expect(application.routes).to eq([route]) end - describe "#adapter" do + describe '#adapter' do let(:adapter_class) { application.adapter_class } it "returns an instance of it's adapter class" do expect(application.adapter).to be_an_instance_of(adapter_class) end - it "is memoized" do + it 'is memoized' do expect(application.adapter).to eql application.adapter end end - it "can be run" do + it 'can be run' do expect(application.adapter).to receive(:run) application.run end - it "can be queried about its configured adapter" do + it 'can be queried about its configured adapter' do expected = Webmachine::Adapters.const_get(application.configuration.adapter) expect(application.adapter_class).to equal(expected) end diff --git a/spec/webmachine/chunked_body_spec.rb b/spec/webmachine/chunked_body_spec.rb index 96bbf163..0a0620f7 100644 --- a/spec/webmachine/chunked_body_spec.rb +++ b/spec/webmachine/chunked_body_spec.rb @@ -2,7 +2,7 @@ require 'webmachine/chunked_body' describe Webmachine::ChunkedBody do - it "builds a proper body" do + it 'builds a proper body' do body = '' Webmachine::ChunkedBody.new(['foo', 'bar', '', 'j', 'webmachine']).each do |chunk| body << chunk @@ -10,8 +10,8 @@ expect(body).to eq("3\r\nfoo\r\n3\r\nbar\r\n1\r\nj\r\na\r\nwebmachine\r\n0\r\n\r\n") end - context "with an empty body" do - it "builds a proper body" do + context 'with an empty body' do + it 'builds a proper body' do body = '' Webmachine::ChunkedBody.new([]).each do |chunk| body << chunk @@ -20,9 +20,9 @@ end end - describe "#each" do - context "without a block given" do - it "returns an Enumerator" do + describe '#each' do + context 'without a block given' do + it 'returns an Enumerator' do expect(Webmachine::ChunkedBody.new([]).each).to respond_to(:next) end end diff --git a/spec/webmachine/configuration_spec.rb b/spec/webmachine/configuration_spec.rb index b97e65c6..4148e2ea 100644 --- a/spec/webmachine/configuration_spec.rb +++ b/spec/webmachine/configuration_spec.rb @@ -3,25 +3,25 @@ describe Webmachine::Configuration do before { Webmachine.configuration = nil } - %w{ip port adapter adapter_options}.each do |field| + %w[ip port adapter adapter_options].each do |field| it { is_expected.to respond_to(field) } it { is_expected.to respond_to("#{field}=") } end - it "should yield configuration to the block" do + it 'should yield configuration to the block' do Webmachine.configure do |config| expect(config).to be_kind_of(described_class) end end - it "should set the global configuration from the yielded instance" do + it 'should set the global configuration from the yielded instance' do Webmachine.configure do |config| @config = config end expect(@config).to eq Webmachine.configuration end - it "should return the module from the configure call so you can chain it" do - expect(Webmachine.configure {|c|}).to eq Webmachine + it 'should return the module from the configure call so you can chain it' do + expect(Webmachine.configure { |c| }).to eq Webmachine end end diff --git a/spec/webmachine/cookie_spec.rb b/spec/webmachine/cookie_spec.rb index 217ff4bb..de815c1f 100644 --- a/spec/webmachine/cookie_spec.rb +++ b/spec/webmachine/cookie_spec.rb @@ -1,9 +1,9 @@ require 'spec_helper' describe Webmachine::Cookie do - describe "creating a cookie" do - let(:name) { "monster" } - let(:value) { "mash" } + describe 'creating a cookie' do + let(:name) { 'monster' } + let(:value) { 'mash' } let(:attributes) { {} } let(:cookie) { Webmachine::Cookie.new(name, value, attributes) } @@ -13,32 +13,32 @@ its(:name) { should == name } its(:value) { should == value } - its(:to_s) { should == "monster=mash" } + its(:to_s) { should == 'monster=mash' } - describe "a cookie with whitespace in name and value" do - let(:name) { "cookie name" } - let(:value) { "cookie value" } + describe 'a cookie with whitespace in name and value' do + let(:name) { 'cookie name' } + let(:value) { 'cookie value' } - its(:to_s) { should == "cookie+name=cookie+value" } + its(:to_s) { should == 'cookie+name=cookie+value' } end - describe "a cookie with attributes set" do - let(:domain) { "www.server.com" } - let(:path) { "/" } - let(:comment) { "comment with spaces" } + describe 'a cookie with attributes set' do + let(:domain) { 'www.server.com' } + let(:path) { '/' } + let(:comment) { 'comment with spaces' } let(:version) { 1 } let(:maxage) { 60 } - let(:expires) { Time.gm(2010,3,14, 3, 14, 0) } + let(:expires) { Time.gm(2010, 3, 14, 3, 14, 0) } let(:attributes) { { - :comment => comment, - :domain => domain, - :path => path, - :secure => true, - :httponly => true, - :version => version, - :maxage => maxage, - :expires => expires + comment: comment, + domain: domain, + path: path, + secure: true, + httponly: true, + version: version, + maxage: maxage, + expires: expires } } @@ -51,49 +51,49 @@ its(:maxage) { should == maxage } its(:expires) { should == expires } - it "should include the attributes in its string version" do + it 'should include the attributes in its string version' do str = subject.to_s - expect(str).to include "Secure" - expect(str).to include "HttpOnly" - expect(str).to include "Comment=comment+with+spaces" - expect(str).to include "Domain=www.server.com" - expect(str).to include "Path=/" - expect(str).to include "Version=1" - expect(str).to include "Max-Age=60" - expect(str).to include "Expires=Sun, 14 Mar 2010 03:14:00 GMT" + expect(str).to include 'Secure' + expect(str).to include 'HttpOnly' + expect(str).to include 'Comment=comment+with+spaces' + expect(str).to include 'Domain=www.server.com' + expect(str).to include 'Path=/' + expect(str).to include 'Version=1' + expect(str).to include 'Max-Age=60' + expect(str).to include 'Expires=Sun, 14 Mar 2010 03:14:00 GMT' end end end - describe "parsing a cookie parameter" do - let(:str) { "cookie = monster" } + describe 'parsing a cookie parameter' do + let(:str) { 'cookie = monster' } subject { Webmachine::Cookie.parse(str) } - it("should have the cookie") { expect(subject).to eq({ "cookie" => "monster" }) } + it('should have the cookie') { expect(subject).to eq({'cookie' => 'monster'}) } - describe "parsing multiple cookie parameters" do - let(:str) { "cookie=monster; monster=mash" } + describe 'parsing multiple cookie parameters' do + let(:str) { 'cookie=monster; monster=mash' } - it("should have both cookies") { expect(subject).to eq({ "cookie" => "monster", "monster" => "mash" }) } + it('should have both cookies') { expect(subject).to eq({'cookie' => 'monster', 'monster' => 'mash'}) } end - describe "parsing an encoded cookie" do - let(:str) { "cookie=yum+yum" } + describe 'parsing an encoded cookie' do + let(:str) { 'cookie=yum+yum' } - it("should decode the cookie") { expect(subject).to eq({ "cookie" => "yum yum" }) } + it('should decode the cookie') { expect(subject).to eq({'cookie' => 'yum yum'}) } end - describe "parsing nil" do + describe 'parsing nil' do let(:str) { nil } - it("should return empty hash") { expect(subject).to eq({}) } + it('should return empty hash') { expect(subject).to eq({}) } end - describe "parsing duplicate cookies" do - let(:str) { "cookie=monster; cookie=yum+yum" } + describe 'parsing duplicate cookies' do + let(:str) { 'cookie=monster; cookie=yum+yum' } - it("should return the first instance of the cookie") { expect(subject).to eq({ "cookie" => "monster" }) } + it('should return the first instance of the cookie') { expect(subject).to eq({'cookie' => 'monster'}) } end end end diff --git a/spec/webmachine/decision/conneg_spec.rb b/spec/webmachine/decision/conneg_spec.rb index af2d5255..58b9f846 100644 --- a/spec/webmachine/decision/conneg_spec.rb +++ b/spec/webmachine/decision/conneg_spec.rb @@ -1,163 +1,160 @@ require 'spec_helper' describe Webmachine::Decision::Conneg do - include_context "default resource" + include_context 'default resource' subject do Webmachine::Decision::FSM.new(resource, request, response) end - context "choosing a media type" do - it "should not choose a type when none are provided" do - expect(subject.choose_media_type([], "*/*")).to be_nil + context 'choosing a media type' do + it 'should not choose a type when none are provided' do + expect(subject.choose_media_type([], '*/*')).to be_nil end - it "should not choose a type when none are acceptable" do - expect(subject.choose_media_type(["text/html"], "application/json")).to be_nil + it 'should not choose a type when none are acceptable' do + expect(subject.choose_media_type(['text/html'], 'application/json')).to be_nil end - it "should choose the first acceptable type" do - expect(subject.choose_media_type(["text/html", "application/xml"], - "application/xml, text/html, */*")).to eq("application/xml") + it 'should choose the first acceptable type' do + expect(subject.choose_media_type(['text/html', 'application/xml'], + 'application/xml, text/html, */*')).to eq('application/xml') end - it "should choose the type that matches closest when matching subparams" do - expect(subject.choose_media_type(["text/html", - ["text/html", {"charset" => "iso8859-1"}]], - "text/html;charset=iso8859-1, application/xml")). - to eq("text/html;charset=iso8859-1") + it 'should choose the type that matches closest when matching subparams' do + expect(subject.choose_media_type(['text/html', + ['text/html', {'charset' => 'iso8859-1'}]], + 'text/html;charset=iso8859-1, application/xml')) + .to eq('text/html;charset=iso8859-1') end - it "should choose a type more specific than requested when an exact match is not present" do - expect(subject.choose_media_type(["application/json;v=3;foo=bar", "application/json;v=2"], - "text/html, application/json")). - to eq("application/json;v=3;foo=bar") + it 'should choose a type more specific than requested when an exact match is not present' do + expect(subject.choose_media_type(['application/json;v=3;foo=bar', 'application/json;v=2'], + 'text/html, application/json')) + .to eq('application/json;v=3;foo=bar') end - - it "should choose the preferred type over less-preferred types" do - expect(subject.choose_media_type(["text/html", "application/xml"], - "application/xml;q=0.7, text/html, */*")).to eq("text/html") - + it 'should choose the preferred type over less-preferred types' do + expect(subject.choose_media_type(['text/html', 'application/xml'], + 'application/xml;q=0.7, text/html, */*')).to eq('text/html') end - it "should raise an error when a media-type is improperly formatted" do + it 'should raise an error when a media-type is improperly formatted' do expect { - subject.choose_media_type(["text/html", "application/xml"], - "bah;") + subject.choose_media_type(['text/html', 'application/xml'], + 'bah;') }.to raise_error(Webmachine::MalformedRequest) end - it "should choose a type when more than one accept header is present" do - expect(subject.choose_media_type(["text/html"], - ["text/html", "text/plain"])).to eq("text/html") - + it 'should choose a type when more than one accept header is present' do + expect(subject.choose_media_type(['text/html'], + ['text/html', 'text/plain'])).to eq('text/html') end end - context "choosing an encoding" do - it "should not set the encoding when none are provided" do - subject.choose_encoding({}, "identity, gzip") + context 'choosing an encoding' do + it 'should not set the encoding when none are provided' do + subject.choose_encoding({}, 'identity, gzip') expect(subject.metadata['Content-Encoding']).to be_nil expect(subject.response.headers['Content-Encoding']).to be_nil end - it "should not set the Content-Encoding header when it is identity" do - subject.choose_encoding({"gzip"=> :encode_gzip, "identity" => :encode_identity}, "identity") + it 'should not set the Content-Encoding header when it is identity' do + subject.choose_encoding({'gzip' => :encode_gzip, 'identity' => :encode_identity}, 'identity') expect(subject.metadata['Content-Encoding']).to eq('identity') expect(response.headers['Content-Encoding']).to be_nil end - it "should choose the first acceptable encoding" do - subject.choose_encoding({"gzip" => :encode_gzip}, "identity, gzip") + it 'should choose the first acceptable encoding' do + subject.choose_encoding({'gzip' => :encode_gzip}, 'identity, gzip') expect(subject.metadata['Content-Encoding']).to eq('gzip') expect(response.headers['Content-Encoding']).to eq('gzip') end - it "should choose the first acceptable encoding" \ - ", even when no white space after comma" do - subject.choose_encoding({"gzip" => :encode_gzip}, "identity,gzip") + it 'should choose the first acceptable encoding' \ + ', even when no white space after comma' do + subject.choose_encoding({'gzip' => :encode_gzip}, 'identity,gzip') expect(subject.metadata['Content-Encoding']).to eq('gzip') expect(response.headers['Content-Encoding']).to eq('gzip') end - it "should choose the preferred encoding over less-preferred encodings" do - subject.choose_encoding({"gzip" => :encode_gzip, "identity" => :encode_identity}, "gzip, identity;q=0.7") + it 'should choose the preferred encoding over less-preferred encodings' do + subject.choose_encoding({'gzip' => :encode_gzip, 'identity' => :encode_identity}, 'gzip, identity;q=0.7') expect(subject.metadata['Content-Encoding']).to eq('gzip') expect(response.headers['Content-Encoding']).to eq('gzip') end - it "should not set the encoding if none are acceptable" do - subject.choose_encoding({"gzip" => :encode_gzip}, "identity") + it 'should not set the encoding if none are acceptable' do + subject.choose_encoding({'gzip' => :encode_gzip}, 'identity') expect(subject.metadata['Content-Encoding']).to be_nil expect(response.headers['Content-Encoding']).to be_nil end end - context "choosing a charset" do - it "should not set the charset when none are provided" do - subject.choose_charset([], "ISO-8859-1") + context 'choosing a charset' do + it 'should not set the charset when none are provided' do + subject.choose_charset([], 'ISO-8859-1') expect(subject.metadata['Charset']).to be_nil end - it "should choose the first acceptable charset" do - subject.choose_charset([["UTF-8", :to_utf8],["US-ASCII", :to_ascii]], "US-ASCII, UTF-8") - expect(subject.metadata['Charset']).to eq("US-ASCII") + it 'should choose the first acceptable charset' do + subject.choose_charset([['UTF-8', :to_utf8], ['US-ASCII', :to_ascii]], 'US-ASCII, UTF-8') + expect(subject.metadata['Charset']).to eq('US-ASCII') end - it "should choose the preferred charset over less-preferred charsets" do - subject.choose_charset([["UTF-8", :to_utf8],["US-ASCII", :to_ascii]], "US-ASCII;q=0.7, UTF-8") - expect(subject.metadata['Charset']).to eq("UTF-8") + it 'should choose the preferred charset over less-preferred charsets' do + subject.choose_charset([['UTF-8', :to_utf8], ['US-ASCII', :to_ascii]], 'US-ASCII;q=0.7, UTF-8') + expect(subject.metadata['Charset']).to eq('UTF-8') end - it "should not set the charset if none are acceptable" do - subject.choose_charset([["UTF-8", :to_utf8],["US-ASCII", :to_ascii]], "ISO-8859-1") + it 'should not set the charset if none are acceptable' do + subject.choose_charset([['UTF-8', :to_utf8], ['US-ASCII', :to_ascii]], 'ISO-8859-1') expect(subject.metadata['Charset']).to be_nil end - it "should choose a charset case-insensitively" do - subject.choose_charset([["UtF-8", :to_utf8],["US-ASCII", :to_ascii]], "iso-8859-1, utf-8") - expect(subject.metadata['Charset']).to eq("utf-8") + it 'should choose a charset case-insensitively' do + subject.choose_charset([['UtF-8', :to_utf8], ['US-ASCII', :to_ascii]], 'iso-8859-1, utf-8') + expect(subject.metadata['Charset']).to eq('utf-8') end end - context "choosing a language" do - it "should not set the language when none are provided" do - subject.choose_language([], "en") + context 'choosing a language' do + it 'should not set the language when none are provided' do + subject.choose_language([], 'en') expect(subject.metadata['Language']).to be_nil end - it "should choose the first acceptable language" do - subject.choose_language(['en', 'en-US', 'es'], "en-US, es") - expect(subject.metadata['Language']).to eq("en-US") - expect(response.headers['Content-Language']).to eq("en-US") + it 'should choose the first acceptable language' do + subject.choose_language(['en', 'en-US', 'es'], 'en-US, es') + expect(subject.metadata['Language']).to eq('en-US') + expect(response.headers['Content-Language']).to eq('en-US') end - it "should choose the preferred language over less-preferred languages" do - subject.choose_language(['en', 'en-US', 'es'], "en-US;q=0.6, es") - expect(subject.metadata['Language']).to eq("es") - expect(response.headers['Content-Language']).to eq("es") + it 'should choose the preferred language over less-preferred languages' do + subject.choose_language(['en', 'en-US', 'es'], 'en-US;q=0.6, es') + expect(subject.metadata['Language']).to eq('es') + expect(response.headers['Content-Language']).to eq('es') end - it "should select the first language if all are acceptable" do - subject.choose_language(['en', 'fr', 'es'], "*") - expect(subject.metadata['Language']).to eq("en") - expect(response.headers['Content-Language']).to eq("en") + it 'should select the first language if all are acceptable' do + subject.choose_language(['en', 'fr', 'es'], '*') + expect(subject.metadata['Language']).to eq('en') + expect(response.headers['Content-Language']).to eq('en') end - it "should select the closest acceptable language when an exact match is not available" do - subject.choose_language(['en-US', 'es'], "en, fr") + it 'should select the closest acceptable language when an exact match is not available' do + subject.choose_language(['en-US', 'es'], 'en, fr') expect(subject.metadata['Language']).to eq('en-US') expect(response.headers['Content-Language']).to eq('en-US') end - it "should not set the language if none are acceptable" do + it 'should not set the language if none are acceptable' do subject.choose_language(['en'], 'es') expect(subject.metadata['Language']).to be_nil expect(response.headers).not_to include('Content-Language') end - it "should choose a language case-insensitively" do + it 'should choose a language case-insensitively' do subject.choose_language(['en-US', 'ZH'], 'zh-ch, EN') expect(subject.metadata['Language']).to eq('en-US') expect(response.headers['Content-Language']).to eq('en-US') diff --git a/spec/webmachine/decision/flow_spec.rb b/spec/webmachine/decision/flow_spec.rb index 80a53369..d1e696f6 100644 --- a/spec/webmachine/decision/flow_spec.rb +++ b/spec/webmachine/decision/flow_spec.rb @@ -3,9 +3,9 @@ describe Webmachine::Decision::Flow do subject { Webmachine::Decision::FSM.new(resource, request, response) } let(:method) { 'GET' } - let(:uri) { URI.parse("http://localhost/") } + let(:uri) { URI.parse('http://localhost/') } let(:headers) { Webmachine::Headers.new } - let(:body) { "" } + let(:body) { '' } let(:request) { Webmachine::Request.new(method, uri, headers, body) } let(:response) { Webmachine::Response.new } let(:default_resource) { resource_with } @@ -22,207 +22,246 @@ def resource_with(&block) klass = Class.new(Webmachine::Resource) do - def to_html; "test resource"; end + def to_html + 'test resource' + end end - klass.module_eval(&block) if block_given? + klass.module_eval(&block) if block klass.new(request, response) end def missing_resource_with(&block) resource_with do - def resource_exists?; false; end - self.module_eval(&block) if block + def resource_exists? + false + end + module_eval(&block) if block end end - describe "#b13 (Service Available?)" do + describe '#b13 (Service Available?)' do let(:resource) do resource_with do attr_accessor :available - def service_available?; @available; end + def service_available? + @available + end end end - it "should respond with 503 when the service is unavailable" do + it 'should respond with 503 when the service is unavailable' do resource.available = false subject.run expect(response.code).to eq 503 end end - describe "#b12 (Known method?)" do + describe '#b12 (Known method?)' do let(:resource) do resource_with do - def known_methods; ['HEAD']; end + def known_methods + ['HEAD'] + end end end - it "should respond with 501 when the method is unknown" do + it 'should respond with 501 when the method is unknown' do subject.run expect(response.code).to eq 501 end end - describe "#b11 (URI too long?)" do + describe '#b11 (URI too long?)' do let(:resource) do resource_with do - def uri_too_long?(uri); true; end + def uri_too_long?(uri) + true + end end end - it "should respond with 414 when the URI is too long" do + it 'should respond with 414 when the URI is too long' do subject.run expect(response.code).to eq 414 end end - describe "#b10 (Method allowed?)" do + describe '#b10 (Method allowed?)' do let(:resource) do resource_with do - def allowed_methods; ['POST']; end + def allowed_methods + ['POST'] + end end end - it "should respond with 405 when the method is not allowed" do + it 'should respond with 405 when the method is not allowed' do subject.run expect(response.code).to eq 405 - expect(response.headers['Allow']).to eq "POST" + expect(response.headers['Allow']).to eq 'POST' end end - describe "#b9 (Malformed request?)" do - let(:resource) { resource_with { def malformed_request?; true; end } } + describe '#b9 (Malformed request?)' do + let(:resource) { + resource_with { + def malformed_request? + true + end + } + } - it "should respond with 400 when the request is malformed" do + it 'should respond with 400 when the request is malformed' do subject.run expect(response.code).to eq 400 end - context "when the Content-MD5 header is present" do + context 'when the Content-MD5 header is present' do let(:resource) do resource_with do - def allowed_methods; ['POST']; end; - def process_post; true; end; + def allowed_methods + ['POST'] + end + + def process_post + true + end attr_accessor :validation - def validate_content_checksum; @validation; end + def validate_content_checksum + @validation + end end end - let(:method) { "POST" } - let(:body) { "This is the body." } - let(:headers) { Webmachine::Headers["Content-Type" => "text/plain"] } + let(:method) { 'POST' } + let(:body) { 'This is the body.' } + let(:headers) { Webmachine::Headers['Content-Type' => 'text/plain'] } - it "should respond with 204 when the request body does match the header" do + it 'should respond with 204 when the request body does match the header' do headers['Content-MD5'] = Base64.encode64 Digest::MD5.hexdigest(body) subject.run expect(response.code).to eq 204 end - it "should bypass validation when the header has a nil value" do + it 'should bypass validation when the header has a nil value' do headers['Content-MD5'] = nil subject.run expect(response.code).to eq 204 end - it "should respond with 400 when the header has a empty string value" do - headers['Content-MD5'] = "" + it 'should respond with 400 when the header has a empty string value' do + headers['Content-MD5'] = '' subject.run expect(response.code).to eq 400 end - it "should respond with 400 when the header has a non-hashed, non-encoded value" do - headers["Content-MD5"] = body + it 'should respond with 400 when the header has a non-hashed, non-encoded value' do + headers['Content-MD5'] = body subject.run expect(response.code).to eq 400 end - it "should respond with 400 when the header is not encoded as Base64 but digest matches the body" do + it 'should respond with 400 when the header is not encoded as Base64 but digest matches the body' do headers['Content-MD5'] = Digest::MD5.hexdigest(body) subject.run expect(response.code).to eq 400 end - it "should respond with 400 when the request body does not match the header" do - headers['Content-MD5'] = Base64.encode64 Digest::MD5.hexdigest("thiswillnotmatchthehash") + it 'should respond with 400 when the request body does not match the header' do + headers['Content-MD5'] = Base64.encode64 Digest::MD5.hexdigest('thiswillnotmatchthehash') subject.run expect(response.code).to eq 400 end - it "should respond with 400 when the resource invalidates the checksum" do + it 'should respond with 400 when the resource invalidates the checksum' do resource.validation = false - headers['Content-MD5'] = Base64.encode64 Digest::MD5.hexdigest("thiswillnotmatchthehash") + headers['Content-MD5'] = Base64.encode64 Digest::MD5.hexdigest('thiswillnotmatchthehash') subject.run expect(response.code).to eq 400 end - it "should not respond with 400 when the resource validates the checksum" do + it 'should not respond with 400 when the resource validates the checksum' do resource.validation = true - headers['Content-MD5'] = Base64.encode64 Digest::MD5.hexdigest("thiswillnotmatchthehash") + headers['Content-MD5'] = Base64.encode64 Digest::MD5.hexdigest('thiswillnotmatchthehash') subject.run expect(response.code).to_not eq 400 end - it "should respond with the given code when the resource returns a code while validating" do + it 'should respond with the given code when the resource returns a code while validating' do resource.validation = 500 - headers['Content-MD5'] = Base64.encode64 Digest::MD5.hexdigest("thiswillnotmatchthehash") + headers['Content-MD5'] = Base64.encode64 Digest::MD5.hexdigest('thiswillnotmatchthehash') subject.run expect(response.code).to eq 500 end end end - describe "#b8 (Authorized?)" do - let(:resource) { resource_with { attr_accessor :auth; def is_authorized?(header); @auth; end } } + describe '#b8 (Authorized?)' do + let(:resource) { + resource_with { + attr_accessor :auth + def is_authorized?(header) + @auth + end + } + } - it "should reply with 401 when the client is unauthorized" do + it 'should reply with 401 when the client is unauthorized' do resource.auth = false subject.run expect(response.code).to eq 401 end - it "should reply with 401 when the resource gives a challenge" do - resource.auth = "Basic realm=Webmachine" + it 'should reply with 401 when the resource gives a challenge' do + resource.auth = 'Basic realm=Webmachine' subject.run expect(response.code).to eq 401 - expect(response.headers['WWW-Authenticate']).to eq "Basic realm=Webmachine" + expect(response.headers['WWW-Authenticate']).to eq 'Basic realm=Webmachine' end - it "should halt with the given code when the resource returns a status code" do + it 'should halt with the given code when the resource returns a status code' do resource.auth = 400 subject.run expect(response.code).to eq 400 end - it "should not reply with 401 when the client is authorized" do + it 'should not reply with 401 when the client is authorized' do resource.auth = true subject.run expect(response.code).to_not eq 401 end end - describe "#b7 (Forbidden?)" do - let(:resource) { resource_with { attr_accessor :forbid; def forbidden?; @forbid; end } } + describe '#b7 (Forbidden?)' do + let(:resource) { + resource_with { + attr_accessor :forbid + def forbidden? + @forbid + end + } + } - it "should reply with 403 when the request is forbidden" do + it 'should reply with 403 when the request is forbidden' do resource.forbid = true subject.run expect(response.code).to eq 403 end - it "should not reply with 403 when the request is permitted" do + it 'should not reply with 403 when the request is permitted' do resource.forbid = false subject.run expect(response.code).to_not eq 403 end - it "should halt with the given code when the resource returns a status code" do + it 'should halt with the given code when the resource returns a status code' do resource.forbid = 400 subject.run expect(response.code).to eq 400 end end - describe "#b6 (Unsupported Content-* header?)" do + describe '#b6 (Unsupported Content-* header?)' do let(:resource) do resource_with do def valid_content_headers?(contents) @@ -231,101 +270,126 @@ def valid_content_headers?(contents) end end - it "should reply with 501 when an invalid Content-* header is present" do - headers['Content-Fail'] = "yup" + it 'should reply with 501 when an invalid Content-* header is present' do + headers['Content-Fail'] = 'yup' subject.run expect(response.code).to eq 501 end - it "should not reply with 501 when all Content-* headers are valid" do + it 'should not reply with 501 when all Content-* headers are valid' do subject.run expect(response.code).to_not eq 501 end end - describe "#b5 (Known Content-Type?)" do - let(:method) { "POST" } - let(:body) { "This is the body." } + describe '#b5 (Known Content-Type?)' do + let(:method) { 'POST' } + let(:body) { 'This is the body.' } let(:resource) do resource_with do - def known_content_type?(type) type !~ /unknown/; end; - def process_post; true; end - def allowed_methods; %w{POST}; end + def known_content_type?(type) + type !~ /unknown/ + end + + def process_post + true + end + + def allowed_methods + %w[POST] + end end end before { headers['Content-Length'] = body.length.to_s } - it "should reply with 415 when the Content-Type is unknown" do - headers['Content-Type'] = "application/x-unknown-type" + it 'should reply with 415 when the Content-Type is unknown' do + headers['Content-Type'] = 'application/x-unknown-type' subject.run expect(response.code).to eq 415 end - it "should not reply with 415 when the Content-Type is known" do - headers['Content-Type'] = "text/plain" + it 'should not reply with 415 when the Content-Type is known' do + headers['Content-Type'] = 'text/plain' subject.run expect(response.code).to_not eq 415 end end - describe "#b4 (Request entity too large?)" do + describe '#b4 (Request entity too large?)' do let(:resource) do resource_with do - def allowed_methods; %w{POST}; end - def process_post; true; end - def valid_entity_length?(length); length.to_i < 100; end + def allowed_methods + %w[POST] + end + + def process_post + true + end + + def valid_entity_length?(length) + length.to_i < 100 + end end end - let(:method) { "POST" } - before { headers['Content-Type'] = "text/plain"; headers['Content-Length'] = body.size.to_s } + let(:method) { 'POST' } + before { + headers['Content-Type'] = 'text/plain' + headers['Content-Length'] = body.size.to_s + } - context "when the request body is too large" do - let(:body) { "Big" * 100 } - it "should reply with 413" do + context 'when the request body is too large' do + let(:body) { 'Big' * 100 } + it 'should reply with 413' do subject.run expect(response.code).to eq 413 end end - context "when the request body is not too large" do - let(:body) { "small" } + context 'when the request body is not too large' do + let(:body) { 'small' } - it "should not reply with 413" do + it 'should not reply with 413' do subject.run expect(response.code).to_not eq 413 end end end - describe "#b3 (OPTIONS?)" do - let(:method){ "OPTIONS" } - let(:resource){ resource_with { def allowed_methods; %w[GET HEAD OPTIONS]; end } } - it "should reply with 200 when the request method is OPTIONS" do + describe '#b3 (OPTIONS?)' do + let(:method) { 'OPTIONS' } + let(:resource) { + resource_with { + def allowed_methods + %w[GET HEAD OPTIONS] + end + } + } + it 'should reply with 200 when the request method is OPTIONS' do subject.run expect(response.code).to eq 200 end end - describe "#c3, #c4 (Acceptable media types)" do + describe '#c3, #c4 (Acceptable media types)' do let(:resource) { default_resource } - context "when the Accept header exists" do - it "should reply with 406 when the type is unacceptable" do - headers['Accept'] = "text/plain" + context 'when the Accept header exists' do + it 'should reply with 406 when the type is unacceptable' do + headers['Accept'] = 'text/plain' subject.run expect(response.code).to eq 406 end - it "should not reply with 406 when the type is acceptable" do - headers['Accept'] = "text/*" + it 'should not reply with 406 when the type is acceptable' do + headers['Accept'] = 'text/*' subject.run expect(response.code).to_not eq 406 - expect(response.headers['Content-Type']).to eq "text/html" + expect(response.headers['Content-Type']).to eq 'text/html' end end - context "when the Accept header does not exist" do - it "should not negotiate a media type" do + context 'when the Accept header does not exist' do + it 'should not negotiate a media type' do expect(headers['Accept']).to be_nil expect(subject).to_not receive(:c4) subject.run @@ -334,26 +398,32 @@ def valid_entity_length?(length); length.to_i < 100; end end end - describe "#d4, #d5 (Acceptable languages)" do - let(:resource) { resource_with { def languages_provided; %w{en-US fr}; end } } - context "when the Accept-Language header exists" do - it "should reply with 406 when the language is unacceptable" do - headers['Accept-Language'] = "es, de" + describe '#d4, #d5 (Acceptable languages)' do + let(:resource) { + resource_with { + def languages_provided + %w[en-US fr] + end + } + } + context 'when the Accept-Language header exists' do + it 'should reply with 406 when the language is unacceptable' do + headers['Accept-Language'] = 'es, de' subject.run expect(response.code).to eq 406 end - it "should not reply with 406 when the language is acceptable" do - headers['Accept-Language'] = "en-GB, en;q=0.7" + it 'should not reply with 406 when the language is acceptable' do + headers['Accept-Language'] = 'en-GB, en;q=0.7' subject.run expect(response.code).to_not eq 406 - expect(response.headers['Content-Language']).to eq "en-US" + expect(response.headers['Content-Language']).to eq 'en-US' expect(resource.instance_variable_get(:@language)).to eq 'en-US' end end - context "when the Accept-Language header is absent" do - it "should not negotiate the language" do + context 'when the Accept-Language header is absent' do + it 'should not negotiate the language' do expect(headers['Accept-Language']).to be_nil expect(subject).to_not receive(:d5) subject.run @@ -363,34 +433,40 @@ def valid_entity_length?(length); length.to_i < 100; end end end - describe "#e5, #e6 (Acceptable charsets)" do + describe '#e5, #e6 (Acceptable charsets)' do let(:resource) do resource_with do def charsets_provided - [["iso8859-1", :to_iso],["utf-8", :to_utf]]; + [['iso8859-1', :to_iso], ['utf-8', :to_utf]] + end + + def to_iso(chunk) + chunk + end + + def to_utf(chunk) + chunk end - def to_iso(chunk); chunk; end - def to_utf(chunk); chunk; end end end - context "when the Accept-Charset header exists" do - it "should reply with 406 when the charset is unacceptable" do - headers['Accept-Charset'] = "utf-16" + context 'when the Accept-Charset header exists' do + it 'should reply with 406 when the charset is unacceptable' do + headers['Accept-Charset'] = 'utf-16' subject.run expect(response.code).to eq 406 end - it "should not reply with 406 when the charset is acceptable" do - headers['Accept-Charset'] = "iso8859-1" + it 'should not reply with 406 when the charset is acceptable' do + headers['Accept-Charset'] = 'iso8859-1' subject.run expect(response.code).to_not eq 406 - expect(response.headers['Content-Type']).to eq "text/html;charset=iso8859-1" + expect(response.headers['Content-Type']).to eq 'text/html;charset=iso8859-1' end end - context "when the Accept-Charset header is absent" do - it "should not negotiate the language" do + context 'when the Accept-Charset header is absent' do + it 'should not negotiate the language' do expect(headers['Accept-Charset']).to be_nil expect(subject).to_not receive(:e6) subject.run @@ -399,23 +475,23 @@ def to_utf(chunk); chunk; end end end - describe "#f6, #f7 (Acceptable encodings)" do + describe '#f6, #f7 (Acceptable encodings)' do let(:resource) do resource_with do def encodings_provided - super.merge("gzip" => :encode_gzip) + super.merge('gzip' => :encode_gzip) end end end - context "when the Accept-Encoding header is present" do - it "should reply with 406 if the encoding is unacceptable" do + context 'when the Accept-Encoding header is present' do + it 'should reply with 406 if the encoding is unacceptable' do headers['Accept-Encoding'] = 'deflate, identity;q=0.0' subject.run expect(response.code).to eq 406 end - it "should not reply with 406 if the encoding is acceptable" do + it 'should not reply with 406 if the encoding is acceptable' do headers['Accept-Encoding'] = 'gzip, deflate' subject.run expect(response.code).to_not eq 406 @@ -425,8 +501,8 @@ def encodings_provided end end - context "when the Accept-Encoding header is not present" do - it "should not negotiate an encoding" do + context 'when the Accept-Encoding header is not present' do + it 'should not negotiate an encoding' do expect(headers['Accept-Encoding']).to be_nil expect(subject).to_not receive(:f7) subject.run @@ -437,30 +513,37 @@ def encodings_provided end end - describe "#g7 (Resource exists?)" do - let(:resource) { resource_with { attr_accessor :exist; def resource_exists?; @exist; end } } + describe '#g7 (Resource exists?)' do + let(:resource) { + resource_with { + attr_accessor :exist + def resource_exists? + @exist + end + } + } - it "should not enter conditional requests if missing (and eventually reply with 404)" do + it 'should not enter conditional requests if missing (and eventually reply with 404)' do resource.exist = false expect(subject).to_not receive(:g8) subject.run expect(response.code).to eq 404 end - it "should not reply with 404 if it does exist" do + it 'should not reply with 404 if it does exist' do resource.exist = true expect(subject).to_not receive(:h7) subject.run expect(response.code).to_not eq 404 end - it "should not reply with 404 for truthy non-booleans" do + it 'should not reply with 404 for truthy non-booleans' do resource.exist = [] subject.run expect(response.code).to_not eq 404 end - it "should reply with 404 for nil" do + it 'should reply with 404 for nil' do resource.exist = nil subject.run expect(response.code).to eq 404 @@ -468,37 +551,50 @@ def encodings_provided end # Conditional requests/preconditions - describe "#g8, #g9, #g10 (ETag match)" do - let(:resource) { resource_with { def generate_etag; "etag"; end } } - it "should skip ETag matching when If-Match is missing" do + describe '#g8, #g9, #g10 (ETag match)' do + let(:resource) { + resource_with { + def generate_etag + 'etag' + end + } + } + it 'should skip ETag matching when If-Match is missing' do expect(headers['If-Match']).to be_nil expect(subject).to_not receive(:g9) expect(subject).to_not receive(:g11) subject.run expect(response.code).to_not eq 412 end - it "should not reply with 304 when If-Match is *" do - headers['If-Match'] = "*" + it 'should not reply with 304 when If-Match is *' do + headers['If-Match'] = '*' subject.run expect(response.code).to_not eq 412 end - it "should reply with 412 if the ETag is not in If-Match" do + it 'should reply with 412 if the ETag is not in If-Match' do headers['If-Match'] = '"notetag"' subject.run expect(response.code).to eq 412 end - it "should not reply with 412 if the ETag is in If-Match" do + it 'should not reply with 412 if the ETag is in If-Match' do headers['If-Match'] = '"etag"' subject.run expect(response.code).to_not eq 412 end end - describe "#h10, #h11, #h12 (If-Unmodified-Since match [IUMS])" do - let(:resource) { resource_with { attr_accessor :now; def last_modified; @now; end } } + describe '#h10, #h11, #h12 (If-Unmodified-Since match [IUMS])' do + let(:resource) { + resource_with { + attr_accessor :now + def last_modified + @now + end + } + } before { @now = resource.now = Time.now } - it "should skip LM matching if IUMS is missing" do + it 'should skip LM matching if IUMS is missing' do expect(headers['If-Unmodified-Since']).to be_nil expect(subject).to_not receive(:h11) expect(subject).to_not receive(:h12) @@ -506,90 +602,106 @@ def encodings_provided expect(response.code).to_not eq 412 end - it "should skip LM matching if IUMS is an invalid date" do - headers['If-Unmodified-Since'] = "garbage" + it 'should skip LM matching if IUMS is an invalid date' do + headers['If-Unmodified-Since'] = 'garbage' expect(subject).to_not receive(:h12) subject.run expect(response.code).to_not eq 412 end - it "should not reply with 412 if LM is <= IUMS" do + it 'should not reply with 412 if LM is <= IUMS' do headers['If-Unmodified-Since'] = (@now + 100).httpdate subject.run expect(response.code).to_not eq 412 end - it "should reply with 412 if LM is > IUMS" do + it 'should reply with 412 if LM is > IUMS' do headers['If-Unmodified-Since'] = (@now - 100).httpdate subject.run expect(response.code).to eq 412 end end - describe "#i12, #i13, #k13, #j18 (If-None-Match match)" do + describe '#i12, #i13, #k13, #j18 (If-None-Match match)' do let(:resource) do resource_with do - def generate_etag; "etag"; end; - def process_post; true; end - def allowed_methods; %w{GET HEAD POST}; end + def generate_etag + 'etag' + end + + def process_post + true + end + + def allowed_methods + %w[GET HEAD POST] + end end end - it "should skip ETag matching if If-None-Match is missing" do + it 'should skip ETag matching if If-None-Match is missing' do expect(headers['If-None-Match']).to be_nil - %w{i13 k13 j18}.each do |m| + %w[i13 k13 j18].each do |m| expect(subject).to_not receive(m.to_sym) end subject.run expect([304, 412]).to_not include(response.code) end - it "should not reply with 412 or 304 if the ETag is not in If-None-Match" do + it 'should not reply with 412 or 304 if the ETag is not in If-None-Match' do headers['If-None-Match'] = '"notetag"' subject.run expect([304, 412]).to_not include(response.code) end - context "when the method is GET or HEAD" do - let(:method){ %w{GET HEAD}[rand(1)] } - it "should reply with 304 when If-None-Match is *" do + context 'when the method is GET or HEAD' do + let(:method) { %w[GET HEAD][rand(2)] } + it 'should reply with 304 when If-None-Match is *' do headers['If-None-Match'] = '*' end - it "should reply with 304 when the ETag is in If-None-Match" do + it 'should reply with 304 when the ETag is in If-None-Match' do headers['If-None-Match'] = '"etag", "foobar"' end - after { subject.run; expect(response.code).to eq 304 } + after { + subject.run + expect(response.code).to eq 304 + } end - context "when the method is not GET or HEAD" do - let(:method){ "POST" } - let(:body) { "This is the body." } - let(:headers){ Webmachine::Headers["Content-Type" => "text/plain"] } + context 'when the method is not GET or HEAD' do + let(:method) { 'POST' } + let(:body) { 'This is the body.' } + let(:headers) { Webmachine::Headers['Content-Type' => 'text/plain'] } - it "should reply with 412 when If-None-Match is *" do + it 'should reply with 412 when If-None-Match is *' do headers['If-None-Match'] = '*' end - it "should reply with 412 when the ETag is in If-None-Match" do + it 'should reply with 412 when the ETag is in If-None-Match' do headers['If-None-Match'] = '"etag"' end - after { subject.run; expect(response.code).to eq 412 } + after { + subject.run + expect(response.code).to eq 412 + } end - context "when the resource does not define an ETag" do + context 'when the resource does not define an ETag' do let(:resource) do resource_with do - def generate_etag; nil; end + def generate_etag + nil + end end end - it "should reply with 200 when If-None-Match is missing" do + it 'should reply with 200 when If-None-Match is missing' do headers.delete 'If-None-Match' subject.run expect(response.code).to eq 200 end - it "should reply with 200 when If-None-Match is present" do + it 'should reply with 200 when If-None-Match is present' do headers['If-None-Match'] = '"etag"' subject.run expect(response.code).to eq 200 @@ -597,42 +709,49 @@ def generate_etag; nil; end end end - describe "#l13, #l14, #l15, #l17 (If-Modified-Since match)" do - let(:resource) { resource_with { attr_accessor :now; def last_modified; @now; end } } + describe '#l13, #l14, #l15, #l17 (If-Modified-Since match)' do + let(:resource) { + resource_with { + attr_accessor :now + def last_modified + @now + end + } + } before { @now = resource.now = Time.now } - it "should skip LM matching if IMS is missing" do + it 'should skip LM matching if IMS is missing' do expect(headers['If-Modified-Since']).to be_nil - %w{l14 l15 l17}.each do |m| + %w[l14 l15 l17].each do |m| expect(subject).to_not receive(m.to_sym) end subject.run expect(response.code).to_not eq 304 end - it "should skip LM matching if IMS is an invalid date" do - headers['If-Modified-Since'] = "garbage" - %w{l15 l17}.each do |m| + it 'should skip LM matching if IMS is an invalid date' do + headers['If-Modified-Since'] = 'garbage' + %w[l15 l17].each do |m| expect(subject).to_not receive(m.to_sym) end subject.run expect(response.code).to_not eq 304 end - it "should skip LM matching if IMS is later than current time" do + it 'should skip LM matching if IMS is later than current time' do headers['If-Modified-Since'] = (@now + 1000).httpdate expect(subject).to_not receive(:l17) subject.run expect(response.code).to_not eq 304 end - it "should reply with 304 if LM is <= IMS" do + it 'should reply with 304 if LM is <= IMS' do headers['If-Modified-Since'] = (@now - 1).httpdate resource.now = @now - 1000 subject.run expect(response.code).to eq 304 end - it "should not reply with 304 if LM is > IMS" do + it 'should not reply with 304 if LM is > IMS' do headers['If-Modified-Since'] = (@now - 1000).httpdate subject.run expect(response.code).to_not eq 304 @@ -640,35 +759,40 @@ def generate_etag; nil; end end # Resource missing branch (upper right) - describe "#h7 (If-Match: * exists?)" do + describe '#h7 (If-Match: * exists?)' do let(:resource) { missing_resource } - it "should reply with 412 when the If-Match header is *" do + it 'should reply with 412 when the If-Match header is *' do headers['If-Match'] = '"*"' subject.run expect(response.code).to eq 412 end - it "should not reply with 412 when the If-Match header is missing or not *" do - headers['If-Match'] = ['"etag"', nil][rand(1)] + it 'should not reply with 412 when the If-Match header is missing or not *' do + headers['If-Match'] = ['"etag"', nil][rand(2)] subject.run expect(response.code).to_not eq 412 end end - describe "#i7 (PUT?)" do + describe '#i7 (PUT?)' do let(:resource) do missing_resource_with do - def allowed_methods; %w{GET HEAD PUT POST}; end - def process_post; true; end + def allowed_methods + %w[GET HEAD PUT POST] + end + + def process_post + true + end end end - let(:body) { %W{GET HEAD DELETE}.include?(method) ? nil : "This is the body." } + let(:body) { %W[GET HEAD DELETE].include?(method) ? nil : 'This is the body.' } before { headers['Content-Type'] = 'text/plain' } - context "when the method is PUT" do - let(:method){ "PUT" } + context 'when the method is PUT' do + let(:method) { 'PUT' } - it "should not reach state k7" do + it 'should not reach state k7' do expect(subject).to_not receive(:k7) subject.run end @@ -676,10 +800,10 @@ def process_post; true; end after { expect([404, 410, 303]).to_not include(response.code) } end - context "when the method is not PUT" do - let(:method){ %W{GET HEAD POST DELETE}[rand(4)] } + context 'when the method is not PUT' do + let(:method) { %W[GET HEAD POST DELETE][rand(4)] } - it "should not reach state i4" do + it 'should not reach state i4' do expect(subject).to_not receive(:i4) subject.run end @@ -688,90 +812,112 @@ def process_post; true; end end end - describe "#i4 (Apply to a different URI?)" do + describe '#i4 (Apply to a different URI?)' do let(:resource) do missing_resource_with do attr_accessor :location - def moved_permanently?; @location; end - def allowed_methods; %w[PUT]; end + def moved_permanently? + @location + end + + def allowed_methods + %w[PUT] + end end end - let(:method){ "PUT" } - let(:body){ "This is the body." } - let(:headers) { Webmachine::Headers["Content-Type" => "text/plain", "Content-Length" => body.size.to_s] } + let(:method) { 'PUT' } + let(:body) { 'This is the body.' } + let(:headers) { Webmachine::Headers['Content-Type' => 'text/plain', 'Content-Length' => body.size.to_s] } - it "should reply with 301 when the resource has moved" do - resource.location = URI.parse("http://localhost:8098/newuri") + it 'should reply with 301 when the resource has moved' do + resource.location = URI.parse('http://localhost:8098/newuri') subject.run expect(response.code).to eq 301 expect(response.headers['Location']).to eq resource.location.to_s end - it "should not reply with 301 when resource has not moved" do + it 'should not reply with 301 when resource has not moved' do resource.location = false subject.run expect(response.code).to_not eq 301 end end - describe "Redirection (Resource previously existed)" do + describe 'Redirection (Resource previously existed)' do let(:resource) do missing_resource_with do attr_writer :moved_perm, :moved_temp, :allow_missing - def previously_existed?; true; end - def moved_permanently?; @moved_perm; end - def moved_temporarily?; @moved_temp; end - def allow_missing_post?; @allow_missing; end - def allowed_methods; %W{GET POST}; end - def process_post; true; end + def previously_existed? + true + end + + def moved_permanently? + @moved_perm + end + + def moved_temporarily? + @moved_temp + end + + def allow_missing_post? + @allow_missing + end + + def allowed_methods + %W[GET POST] + end + + def process_post + true + end end end - let(:method){ @method || "GET" } + let(:method) { @method || 'GET' } - describe "#k5 (Moved permanently?)" do - it "should reply with 301 when the resource has moved permanently" do - uri = resource.moved_perm = URI.parse("http://www.google.com/") + describe '#k5 (Moved permanently?)' do + it 'should reply with 301 when the resource has moved permanently' do + uri = resource.moved_perm = URI.parse('http://www.google.com/') subject.run expect(response.code).to eq 301 expect(response.headers['Location']).to eq uri.to_s end - it "should not reply with 301 when the resource has not moved permanently" do + it 'should not reply with 301 when the resource has not moved permanently' do resource.moved_perm = false subject.run expect(response.code).to_not eq 301 end end - describe "#l5 (Moved temporarily?)" do + describe '#l5 (Moved temporarily?)' do before { resource.moved_perm = false } - it "should reply with 307 when the resource has moved temporarily" do - uri = resource.moved_temp = URI.parse("http://www.basho.com/") + it 'should reply with 307 when the resource has moved temporarily' do + uri = resource.moved_temp = URI.parse('http://www.basho.com/') subject.run expect(response.code).to eq 307 expect(response.headers['Location']).to eq uri.to_s end - it "should not reply with 307 when the resource has not moved temporarily" do + it 'should not reply with 307 when the resource has not moved temporarily' do resource.moved_temp = false subject.run expect(response.code).to_not eq 307 end end - describe "#m5 (POST?), #n5 (POST to missing resource?)" do + describe '#m5 (POST?), #n5 (POST to missing resource?)' do before { resource.moved_perm = resource.moved_temp = false } - it "should reply with 410 when the method is not POST" do - expect(method).to_not eq "POST" + it 'should reply with 410 when the method is not POST' do + expect(method).to_not eq 'POST' subject.run expect(response.code).to eq 410 end - it "should reply with 410 when the resource disallows missing POSTs" do - @method = "POST" + it 'should reply with 410 when the resource disallows missing POSTs' do + @method = 'POST' resource.allow_missing = false subject.run expect(response.code).to eq 410 end - it "should not reply with 410 when the resource allows missing POSTs" do - @method = "POST" + it 'should not reply with 410 when the resource allows missing POSTs' do + @method = 'POST' resource.allow_missing = true subject.run expect(response.code).to eq 410 @@ -779,51 +925,67 @@ def process_post; true; end end end - describe "#l7 (POST?), #m7 (POST to missing resource?)" do + describe '#l7 (POST?), #m7 (POST to missing resource?)' do let(:resource) do missing_resource_with do attr_accessor :allow_missing - def allowed_methods; %W{GET POST}; end - def previously_existed?; false; end - def allow_missing_post?; @allow_missing; end - def process_post; true; end + def allowed_methods + %W[GET POST] + end + + def previously_existed? + false + end + + def allow_missing_post? + @allow_missing + end + + def process_post + true + end end end - let(:method){ @method || "GET" } - it "should reply with 404 when the method is not POST" do - expect(method).to_not eq "POST" + let(:method) { @method || 'GET' } + it 'should reply with 404 when the method is not POST' do + expect(method).to_not eq 'POST' subject.run expect(response.code).to eq 404 end - it "should reply with 404 when the resource disallows missing POSTs" do - @method = "POST" + it 'should reply with 404 when the resource disallows missing POSTs' do + @method = 'POST' resource.allow_missing = false subject.run expect(response.code).to eq 404 end - it "should not reply with 404 when the resource allows missing POSTs" do - @method = "POST" + it 'should not reply with 404 when the resource allows missing POSTs' do + @method = 'POST' resource.allow_missing = true subject.run expect(response.code).to_not eq 404 end end - describe "#p3 (Conflict?)" do + describe '#p3 (Conflict?)' do let(:resource) do missing_resource_with do attr_writer :conflict - def allowed_methods; %W{PUT}; end - def is_conflict?; @conflict; end + def allowed_methods + %W[PUT] + end + + def is_conflict? + @conflict + end end end - let(:method){ "PUT" } - it "should reply with 409 if the resource is in conflict" do + let(:method) { 'PUT' } + it 'should reply with 409 if the resource is in conflict' do resource.conflict = true subject.run expect(response.code).to eq 409 end - it "should not reply with 409 if the resource is in conflict" do + it 'should not reply with 409 if the resource is in conflict' do resource.conflict = false subject.run expect(response.code).to_not eq 409 @@ -831,13 +993,19 @@ def is_conflict?; @conflict; end end # Bottom right - describe "#n11 (Redirect?)" do - let(:method) { "POST" } + describe '#n11 (Redirect?)' do + let(:method) { 'POST' } let(:resource) do resource_with do attr_writer :new_loc, :exist - def allowed_methods; %w{POST}; end - def allow_missing_post?; true; end + def allowed_methods + %w[POST] + end + + def allow_missing_post? + true + end + def process_post response.redirect_to(@new_loc) if @new_loc true @@ -845,17 +1013,17 @@ def process_post end end [true, false].each do |e| - context "and the resource #{ e ? "does not exist" : 'exists'}" do + context "and the resource #{e ? "does not exist" : "exists"}" do before { resource.exist = e } - it "should reply with 303 if the resource redirected" do - resource.new_loc = URI.parse("/foo/bar") + it 'should reply with 303 if the resource redirected' do + resource.new_loc = URI.parse('/foo/bar') subject.run expect(response.code).to eq 303 - expect(response.headers['Location']).to eq "/foo/bar" + expect(response.headers['Location']).to eq '/foo/bar' end - it "should not reply with 303 if the resource did not redirect" do + it 'should not reply with 303 if the resource did not redirect' do resource.new_loc = nil subject.run expect(response.code).to_not eq 303 @@ -864,40 +1032,61 @@ def process_post end end - describe "#p11 (New resource?)" do + describe '#p11 (New resource?)' do let(:resource) do resource_with do attr_writer :exist, :new_loc, :create - def allowed_methods; %W{PUT POST}; end - def resource_exists?; @exist; end - def process_post; true; end - def allow_missing_post?; true; end - def post_is_create?; @create; end - def create_path; @new_loc; end - def content_types_accepted; [["text/plain", :accept_text]]; end + def allowed_methods + %W[PUT POST] + end + + def resource_exists? + @exist + end + + def process_post + true + end + + def allow_missing_post? + true + end + + def post_is_create? + @create + end + + def create_path + @new_loc + end + + def content_types_accepted + [['text/plain', :accept_text]] + end + def accept_text response.headers['Location'] = @new_loc.to_s if @new_loc true end end end - let(:body) { "new content" } - let(:headers){ Webmachine::Headers['content-type' => 'text/plain'] } + let(:body) { 'new content' } + let(:headers) { Webmachine::Headers['content-type' => 'text/plain'] } - context "when the method is PUT" do - let(:method){ "PUT" } + context 'when the method is PUT' do + let(:method) { 'PUT' } [true, false].each do |e| - context "and the resource #{ e ? "does not exist" : 'exists'}" do + context "and the resource #{e ? "does not exist" : "exists"}" do before { resource.exist = e } - it "should reply with 201 when the Location header has been set" do + it 'should reply with 201 when the Location header has been set' do resource.exist = e - resource.new_loc = "http://ruby-doc.org/" + resource.new_loc = 'http://ruby-doc.org/' subject.run expect(response.code).to eq 201 end - it "should not reply with 201 when the Location header has been set" do + it 'should not reply with 201 when the Location header has been set' do resource.exist = e subject.run expect(response.headers['Location']).to be_nil @@ -907,25 +1096,25 @@ def accept_text end end - context "when the method is POST" do - let(:method){ "POST" } + context 'when the method is POST' do + let(:method) { 'POST' } [true, false].each do |e| - context "and the resource #{ e ? 'exists' : "does not exist"}" do + context "and the resource #{e ? "exists" : "does not exist"}" do before { resource.exist = e } - it "should reply with 201 when post_is_create is true and create_path returns a URI" do - resource.new_loc = created = "/foo/bar/baz" + it 'should reply with 201 when post_is_create is true and create_path returns a URI' do + resource.new_loc = created = '/foo/bar/baz' resource.create = true subject.run expect(response.code).to eq 201 expect(response.headers['Location']).to eq created end - it "should reply with 500 when post_is_create is true and create_path returns nil" do + it 'should reply with 500 when post_is_create is true and create_path returns nil' do resource.create = true subject.run expect(response.code).to eq 500 expect(response.error).to_not be_nil end - it "should not reply with 201 when post_is_create is false" do + it 'should not reply with 201 when post_is_create is false' do resource.create = false subject.run expect(response.code).to_not eq 201 @@ -935,54 +1124,67 @@ def accept_text end end - describe "#o14 (Conflict?)" do + describe '#o14 (Conflict?)' do let(:resource) do resource_with do attr_writer :conflict - def allowed_methods; %W{PUT}; end - def is_conflict?; @conflict; end + def allowed_methods + %W[PUT] + end + + def is_conflict? + @conflict + end end end - let(:method){ "PUT" } - it "should reply with 409 if the resource is in conflict" do + let(:method) { 'PUT' } + it 'should reply with 409 if the resource is in conflict' do resource.conflict = true subject.run expect(response.code).to eq 409 end - it "should not reply with 409 if the resource is in conflict" do + it 'should not reply with 409 if the resource is in conflict' do resource.conflict = false subject.run expect(response.code).to_not eq 409 end end - describe "#m16 (DELETE?), #m20 (Delete enacted?)" do - let(:method){ @method || "DELETE" } + describe '#m16 (DELETE?), #m20 (Delete enacted?)' do + let(:method) { @method || 'DELETE' } let(:resource) do resource_with do attr_writer :deleted, :completed - def allowed_methods; %w{GET DELETE}; end - def delete_resource; @deleted; end - def delete_completed?; @completed; end + def allowed_methods + %w[GET DELETE] + end + + def delete_resource + @deleted + end + + def delete_completed? + @completed + end end end - it "should not reply with 202 if the method is not DELETE" do - @method = "GET" + it 'should not reply with 202 if the method is not DELETE' do + @method = 'GET' subject.run expect(response.code).to_not eq 202 end - it "should reply with 500 if the DELETE fails" do + it 'should reply with 500 if the DELETE fails' do resource.deleted = false subject.run expect(response.code).to eq 500 end - it "should reply with 202 if the DELETE succeeds but is not complete" do + it 'should reply with 202 if the DELETE succeeds but is not complete' do resource.deleted = true resource.completed = false subject.run expect(response.code).to eq 202 end - it "should not reply with 202 if the DELETE succeeds and completes" do + it 'should not reply with 202 if the DELETE succeeds and completes' do resource.completed = resource.deleted = true subject.run expect(response.code).to_not eq 202 @@ -994,45 +1196,65 @@ def delete_completed?; @completed; end # describe "#n16 (POST?)" do it; end # describe "#o16 (PUT?)" do it; end - describe "#o18 (Multiple representations?)" do + describe '#o18 (Multiple representations?)' do let(:resource) do resource_with do attr_writer :exist, :multiple def delete_resource - response.body = "Response content." + response.body = 'Response content.' + true + end + + def delete_completed? true end - def delete_completed?; true; end - def allowed_methods; %W{GET HEAD PUT POST DELETE}; end - def resource_exists?; @exist; end - def allow_missing_post?; true; end - def content_types_accepted; [[request.content_type, :accept_all]]; end - def multiple_choices?; @multiple; end + + def allowed_methods + %W[GET HEAD PUT POST DELETE] + end + + def resource_exists? + @exist + end + + def allow_missing_post? + true + end + + def content_types_accepted + [[request.content_type, :accept_all]] + end + + def multiple_choices? + @multiple + end + def process_post - response.body = "Response content." + response.body = 'Response content.' true end + def accept_all - response.body = "Response content." + response.body = 'Response content.' true end end end - [["GET", true],["HEAD", true],["PUT", true],["PUT", false],["POST",true],["POST",false], - ["DELETE", true]].each do |m, e| - context "when the method is #{m} and the resource #{e ? 'exists' : 'does not exist' }" do - let(:method){ m } - let(:body) { %W{PUT POST}.include?(m) ? "request body" : "" } - let(:headers) { %W{PUT POST}.include?(m) ? Webmachine::Headers['content-type' => 'text/plain'] : Webmachine::Headers.new } + [['GET', true], ['HEAD', true], ['PUT', true], ['PUT', false], ['POST', true], ['POST', false], + ['DELETE', true]].each do |m, e| + context "when the method is #{m} and the resource #{e ? "exists" : "does not exist"}" do + let(:method) { m } + let(:body) { %W[PUT POST].include?(m) ? 'request body' : '' } + let(:headers) { %W[PUT POST].include?(m) ? Webmachine::Headers['content-type' => 'text/plain'] : Webmachine::Headers.new } before { resource.exist = e } - it "should reply with 200 if there are not multiple representations" do + it 'should reply with 200 if there are not multiple representations' do resource.multiple = false subject.run puts response.error if response.code == 500 expect(response.code).to eq 200 end - it "should reply with 300 if there are multiple representations" do + it 'should reply with 300 if there are multiple representations' do resource.multiple = true subject.run puts response.error if response.code == 500 @@ -1042,37 +1264,56 @@ def accept_all end end - describe "#o20 (Response has entity?)" do + describe '#o20 (Response has entity?)' do let(:resource) do resource_with do attr_writer :exist, :body - def delete_resource; true; end - def delete_completed?; true; end - def allowed_methods; %{GET PUT POST DELETE}; end - def resource_exists?; @exist; end - def allow_missing_post?; true; end - def content_types_accepted; [[request.content_type, :accept_all]]; end + def delete_resource + true + end + + def delete_completed? + true + end + + def allowed_methods + %(GET PUT POST DELETE) + end + + def resource_exists? + @exist + end + + def allow_missing_post? + true + end + + def content_types_accepted + [[request.content_type, :accept_all]] + end + def process_post response.body = @body if @body true end + def accept_all response.body = @body if @body true end end end - let(:method) { @method || "GET" } - let(:headers) { %{PUT POST}.include?(method) ? Webmachine::Headers["content-type" => "text/plain"] : Webmachine::Headers.new } - let(:body) { %{PUT POST}.include?(method) ? "This is the body." : nil } - context "when a response body is present" do - before { resource.body = "Hello, world!" } + let(:method) { @method || 'GET' } + let(:headers) { %(PUT POST).include?(method) ? Webmachine::Headers['content-type' => 'text/plain'] : Webmachine::Headers.new } + let(:body) { %(PUT POST).include?(method) ? 'This is the body.' : nil } + context 'when a response body is present' do + before { resource.body = 'Hello, world!' } [ - ["PUT", false], - ["POST", false], - ["DELETE", true], - ["POST", true], - ["PUT", true] + ['PUT', false], + ['POST', false], + ['DELETE', true], + ['POST', true], + ['PUT', true] ].each do |m, e| it "should not reply with 204 (via exists:#{e}, #{m})" do @method = m @@ -1082,13 +1323,13 @@ def accept_all end end end - context "when a response body is not present" do + context 'when a response body is not present' do [ - ["PUT", false], - ["POST", false], - ["DELETE", true], - ["POST", true], - ["PUT", true] + ['PUT', false], + ['POST', false], + ['DELETE', true], + ['POST', true], + ['PUT', true] ].each do |m, e| it "should reply with 204 (via exists:#{e}, #{m})" do @method = m @@ -1100,8 +1341,8 @@ def accept_all end end - describe "On error" do - context "handle_exception is inherited." do + describe 'On error' do + context 'handle_exception is inherited.' do let :resource do resource_with do def to_html @@ -1110,22 +1351,22 @@ def to_html end end - it "calls handle_exception" do + it 'calls handle_exception' do expect(resource).to receive(:handle_exception).with instance_of(RuntimeError) subject.run end - it "sets the response code to 500" do + it 'sets the response code to 500' do subject.run expect(response.code).to eq 500 end end - context "handle_exception is defined" do + context 'handle_exception is defined' do let :resource do resource_with do def handle_exception(e) - response.body = "error" + response.body = 'error' end def to_html @@ -1134,12 +1375,12 @@ def to_html end end - it "can define a response body" do + it 'can define a response body' do subject.run - expect(response.body).to eq "error" + expect(response.body).to eq 'error' end - it "sets the response code to 500" do + it 'sets the response code to 500' do subject.run expect(response.code).to eq 500 end diff --git a/spec/webmachine/decision/fsm_spec.rb b/spec/webmachine/decision/fsm_spec.rb index 957b841b..e1f8e800 100644 --- a/spec/webmachine/decision/fsm_spec.rb +++ b/spec/webmachine/decision/fsm_spec.rb @@ -6,10 +6,8 @@ subject { described_class.new(resource, request, response) } let(:run_with_exception) do - begin - subject.run - rescue Exception - end + subject.run + rescue Exception end describe 'handling of exceptions from decision methods' do @@ -17,7 +15,7 @@ Webmachine::RescuableException::UNRESCUABLE end - describe "rescueable exceptions" do + describe 'rescueable exceptions' do it 'does rescue Exception' do allow(subject).to receive(Webmachine::Decision::Flow::START) { raise(Exception) } expect(resource).to receive(:handle_exception).with instance_of(Exception) @@ -31,10 +29,10 @@ end end - describe "UNRESCUABLE exceptions" do - shared_examples "UNRESCUABLE" do |e| + describe 'UNRESCUABLE exceptions' do + shared_examples 'UNRESCUABLE' do |e| specify "#{e} is not rescued" do - allow(subject).to receive(Webmachine::Decision::Flow::START) {raise(e)} + allow(subject).to receive(Webmachine::Decision::Flow::START) { raise(e) } expect(resource).to_not receive(:handle_exception).with instance_of(e) expect { subject.run }.to raise_error(e) end @@ -42,9 +40,9 @@ eary = Webmachine::RescuableException::UNRESCUABLE_DEFAULTS - [ Webmachine::MalformedRequest, # Webmachine rescues by default, so it won't re-raise. SignalException # Requires raise in form 'raise SignalException, "SIGSOMESIGNAL"'. - # Haven't found a good no-op signal to use here. + # Haven't found a good no-op signal to use here. ] - eary.each{|e| include_examples "UNRESCUABLE", e} + eary.each { |e| include_examples 'UNRESCUABLE', e } end end @@ -85,15 +83,15 @@ end it 'renders an error' do - expect(Webmachine). - to receive(:render_error). - with(500, request, response, { :message => error.message }) + expect(Webmachine) + .to receive(:render_error) + .with(500, request, response, {message: error.message}) subject.run end end describe 'handling of exceptions from resource.finish_request' do - let(:exception) { Class.new(Exception).new } + let(:exception) { Class.new(RuntimeError).new } before do Webmachine::RescuableException.remove(exception) @@ -129,7 +127,7 @@ end end - it "sets the response code before calling finish_request" do + it 'sets the response code before calling finish_request' do resource_class.class_eval do class << self attr_accessor :current_response_code diff --git a/spec/webmachine/decision/helpers_spec.rb b/spec/webmachine/decision/helpers_spec.rb index d495e045..4caab4bb 100644 --- a/spec/webmachine/decision/helpers_spec.rb +++ b/spec/webmachine/decision/helpers_spec.rb @@ -1,20 +1,22 @@ require 'spec_helper' describe Webmachine::Decision::Helpers do - include_context "default resource" + include_context 'default resource' subject { Webmachine::Decision::FSM.new(resource, request, response) } def resource_with(&block) klass = Class.new(Webmachine::Resource) do - def to_html; "test resource"; end + def to_html + 'test resource' + end end - klass.module_eval(&block) if block_given? + klass.module_eval(&block) if block klass.new(request, response) end let(:resource) { resource_with } - describe "accepting request bodies" do + describe 'accepting request bodies' do let(:resource) do resource_with do def initialize @@ -22,31 +24,34 @@ def initialize end attr_accessor :accepted, :result def content_types_accepted - (accepted || []).map {|t| Array === t ? t : [t, :accept_doc] } + (accepted || []).map { |t| (Array === t) ? t : [t, :accept_doc] } + end + + def accept_doc + result end - def accept_doc; result; end end end - it "should return 415 when no types are accepted" do + it 'should return 415 when no types are accepted' do expect(subject.accept_helper).to eq 415 end - it "should return 415 when the posted type is not acceptable" do - resource.accepted = %W{application/json} - headers['Content-Type'] = "text/xml" + it 'should return 415 when the posted type is not acceptable' do + resource.accepted = %W[application/json] + headers['Content-Type'] = 'text/xml' expect(subject.accept_helper).to eq 415 end - it "should call the method for the first acceptable type, taking into account params" do - resource.accepted = ["application/json;v=3", ["application/json", :other]] + it 'should call the method for the first acceptable type, taking into account params' do + resource.accepted = ['application/json;v=3', ['application/json', :other]] expect(resource).to receive(:other).and_return(true) headers['Content-Type'] = 'application/json;v=2' expect(subject.accept_helper).to be(true) end end - context "setting the Content-Length header when responding" do + context 'setting the Content-Length header when responding' do [204, 205, 304].each do |code| it "removes the header for entity-less response code #{code}" do response.headers['Content-Length'] = '0' @@ -81,82 +86,82 @@ def accept_doc; result; end end end - describe "#encode_body" do + describe '#encode_body' do before { subject.run } - context "with a String body" do + context 'with a String body' do before { response.body = '' } - it "does not modify the response body" do + it 'does not modify the response body' do subject.encode_body expect(response.body).to be_instance_of(String) end - it "sets the Content-Length header in the response" do + it 'sets the Content-Length header in the response' do subject.encode_body expect(response.headers['Content-Length']).to eq response.body.bytesize.to_s end end - shared_examples_for "a non-String body" do - it "does not set the Content-Length header in the response" do + shared_examples_for 'a non-String body' do + it 'does not set the Content-Length header in the response' do subject.encode_body expect(response.headers).to_not have_key('Content-Length') end - it "sets the Transfer-Encoding response header to chunked" do + it 'sets the Transfer-Encoding response header to chunked' do subject.encode_body expect(response.headers['Transfer-Encoding']).to eq 'chunked' end end - context "with an Enumerable body" do + context 'with an Enumerable body' do before { response.body = ['one', 'two'] } - it "wraps the response body in an EnumerableEncoder" do + it 'wraps the response body in an EnumerableEncoder' do subject.encode_body expect(response.body).to be_instance_of(Webmachine::Streaming::EnumerableEncoder) end - it_should_behave_like "a non-String body" + it_should_behave_like 'a non-String body' end - context "with a callable body" do - before { response.body = Proc.new { 'proc' } } + context 'with a callable body' do + before { response.body = proc { 'proc' } } - it "wraps the response body in a CallableEncoder" do + it 'wraps the response body in a CallableEncoder' do subject.encode_body expect(response.body).to be_instance_of(Webmachine::Streaming::CallableEncoder) end - it_should_behave_like "a non-String body" + it_should_behave_like 'a non-String body' end - context "with a Fiber body" do - before { response.body = Fiber.new { Fiber.yield "foo" } } + context 'with a Fiber body' do + before { response.body = Fiber.new { Fiber.yield 'foo' } } - it "wraps the response body in a FiberEncoder" do + it 'wraps the response body in a FiberEncoder' do subject.encode_body expect(response.body).to be_instance_of(Webmachine::Streaming::FiberEncoder) end - it_should_behave_like "a non-String body" + it_should_behave_like 'a non-String body' end - context "with a File body" do - before { response.body = File.open("spec/spec_helper.rb", "r") } + context 'with a File body' do + before { response.body = File.open('spec/spec_helper.rb', 'r') } - it "wraps the response body in an IOEncoder" do + it 'wraps the response body in an IOEncoder' do subject.encode_body expect(response.body).to be_instance_of(Webmachine::Streaming::IOEncoder) end - it "sets the Content-Length header to the size of the file" do + it 'sets the Content-Length header to the size of the file' do subject.encode_body expect(response.headers['Content-Length']).to eq File.stat('spec/spec_helper.rb').size.to_s end - it "progressively yields file contents for each enumeration" do + it 'progressively yields file contents for each enumeration' do subject.encode_body body_size = 0 response.body.each do |chunk| @@ -166,50 +171,50 @@ def accept_doc; result; end expect(body_size).to eq File.stat('spec/spec_helper.rb').size end - context "when the resource provides a non-identity encoding that the client accepts" do + context 'when the resource provides a non-identity encoding that the client accepts' do let(:resource) do resource_with do def encodings_provided - { "deflate" => :encode_deflate, "identity" => :encode_identity } + {'deflate' => :encode_deflate, 'identity' => :encode_identity} end end end let(:headers) do - Webmachine::Headers.new({"Accept-Encoding" => "deflate, identity"}) + Webmachine::Headers.new({'Accept-Encoding' => 'deflate, identity'}) end - it_should_behave_like "a non-String body" + it_should_behave_like 'a non-String body' end end - context "with a StringIO body" do - before { response.body = StringIO.new("A VERY LONG STRING, NOT") } + context 'with a StringIO body' do + before { response.body = StringIO.new('A VERY LONG STRING, NOT') } - it "wraps the response body in an IOEncoder" do + it 'wraps the response body in an IOEncoder' do subject.encode_body expect(response.body).to be_instance_of(Webmachine::Streaming::IOEncoder) end - it "sets the Content-Length header to the size of the string" do + it 'sets the Content-Length header to the size of the string' do subject.encode_body expect(response.headers['Content-Length']).to eq response.body.size.to_s end - context "when the resource provides a non-identity encoding that the client accepts" do + context 'when the resource provides a non-identity encoding that the client accepts' do let(:resource) do resource_with do def encodings_provided - { "deflate" => :encode_deflate, "identity" => :encode_identity } + {'deflate' => :encode_deflate, 'identity' => :encode_identity} end end end let(:headers) do - Webmachine::Headers.new({"Accept-Encoding" => "deflate, identity"}) + Webmachine::Headers.new({'Accept-Encoding' => 'deflate, identity'}) end - it_should_behave_like "a non-String body" + it_should_behave_like 'a non-String body' end end end diff --git a/spec/webmachine/dispatcher/route_spec.rb b/spec/webmachine/dispatcher/route_spec.rb index 0a43d810..27272ad0 100644 --- a/spec/webmachine/dispatcher/route_spec.rb +++ b/spec/webmachine/dispatcher/route_spec.rb @@ -1,15 +1,17 @@ require 'spec_helper' Webmachine::Dispatcher::Route.class_eval do - def warn(*msgs); end # silence warnings for tests + # silence warnings for tests + def warn(*msgs) + end end describe Webmachine::Dispatcher::Route do - let(:method) { "GET" } - let(:uri) { URI.parse("http://localhost:8080/") } + let(:method) { 'GET' } + let(:uri) { URI.parse('http://localhost:8080/') } let(:routing_tokens) { nil } - let(:request){ Webmachine::Request.new(method, uri, Webmachine::Headers.new, "", routing_tokens) } - let(:resource){ Class.new(Webmachine::Resource) } + let(:request) { Webmachine::Request.new(method, uri, Webmachine::Headers.new, '', routing_tokens) } + let(:resource) { Class.new(Webmachine::Resource) } describe '#apply' do let(:route) { @@ -17,11 +19,11 @@ def warn(*msgs); end # silence warnings for tests } describe 'a path_info fragment' do - let(:uri) { URI.parse("http://localhost:8080/hello/planet%20earth%20++") } + let(:uri) { URI.parse('http://localhost:8080/hello/planet%20earth%20++') } it 'should decode the value' do route.apply(request) - expect(request.path_info).to eq({:string => 'planet earth ++'}) + expect(request.path_info).to eq({string: 'planet earth ++'}) end end end @@ -29,9 +31,9 @@ def warn(*msgs); end # silence warnings for tests matcher :match_route do |*expected| route = Webmachine::Dispatcher::Route.new(expected[0], Class.new(Webmachine::Resource), expected[1] || {}) match do |actual| - uri = URI.parse("http://localhost:8080") + uri = URI.parse('http://localhost:8080') uri.path = actual - req = Webmachine::Request.new("GET", uri, Webmachine::Headers.new, "", routing_tokens) + req = Webmachine::Request.new('GET', uri, Webmachine::Headers.new, '', routing_tokens) route.match?(req) end @@ -43,61 +45,61 @@ def warn(*msgs); end # silence warnings for tests end end - it "warns about the deprecated string splat when initializing" do - [["*"],["foo", "*"],["foo", :bar, "*"]].each do |path| + it 'warns about the deprecated string splat when initializing' do + [['*'], ['foo', '*'], ['foo', :bar, '*']].each do |path| route = described_class.allocate expect(route).to receive(:warn) route.send :initialize, path, resource, {} end end - context "matching a request" do - context "on the root path" do - subject { "/" } + context 'matching a request' do + context 'on the root path' do + subject { '/' } it { is_expected.to match_route([]) } it { is_expected.to match_route ['*'] } it { is_expected.to match_route [:*] } - it { is_expected.not_to match_route %w{foo} } + it { is_expected.not_to match_route %w[foo] } it { is_expected.not_to match_route [:id] } end - context "on a deep path" do - subject { "/foo/bar/baz" } - it { is_expected.to match_route %w{foo bar baz} } - it { is_expected.to match_route ['foo', :id, "baz"] } + context 'on a deep path' do + subject { '/foo/bar/baz' } + it { is_expected.to match_route %w[foo bar baz] } + it { is_expected.to match_route ['foo', :id, 'baz'] } it { is_expected.to match_route ['foo', :*] } it { is_expected.to match_route [:id, :*] } it { is_expected.not_to match_route [] } it { is_expected.not_to match_route ['bar', :*] } end - context "with a guard on the request method" do - let(:uri){ URI.parse("http://localhost:8080/notes") } + context 'with a guard on the request method' do + let(:uri) { URI.parse('http://localhost:8080/notes') } let(:route) do described_class.new( - ["notes"], - lambda { |request| request.method == "POST" }, - resource - ) + ['notes'], + lambda { |request| request.method == 'POST' }, + resource + ) end subject { route } - context "when guard passes" do - let(:method){ "POST" } + context 'when guard passes' do + let(:method) { 'POST' } it { is_expected.to be_match(request) } - context "but the path match fails" do - let(:uri){ URI.parse("http://localhost:8080/other") } + context 'but the path match fails' do + let(:uri) { URI.parse('http://localhost:8080/other') } it { is_expected.not_to be_match(request) } end end - context "when guard fails" do - let(:method) { "GET" } + context 'when guard fails' do + let(:method) { 'GET' } it { is_expected.not_to be_match(request) } end - context "when the guard responds to #call" do + context 'when the guard responds to #call' do let(:guard_class) do Class.new do def initialize(method) @@ -111,136 +113,136 @@ def call(request) end let(:route) do - described_class.new(["notes"], guard_class.new("POST"), resource) + described_class.new(['notes'], guard_class.new('POST'), resource) end - context "when the guard passes" do - let(:method){ "POST" } + context 'when the guard passes' do + let(:method) { 'POST' } it { is_expected.to be_match(request) } end - context "when the guard fails" do + context 'when the guard fails' do # let(:method){ "GET" } it { is_expected.not_to be_match(request) } end end end - context "with a request with explicitly specified routing tokens" do - subject { "/some/route/foo/bar" } - let(:routing_tokens) { ["foo", "bar"] } - it { is_expected.to match_route(["foo", "bar"]) } - it { is_expected.to match_route(["foo", :id]) } + context 'with a request with explicitly specified routing tokens' do + subject { '/some/route/foo/bar' } + let(:routing_tokens) { ['foo', 'bar'] } + it { is_expected.to match_route(['foo', 'bar']) } + it { is_expected.to match_route(['foo', :id]) } it { is_expected.to match_route ['*'] } it { is_expected.to match_route [:*] } - it { is_expected.not_to match_route(["some", "route", "foo", "bar"]) } - it { is_expected.not_to match_route %w{foo} } + it { is_expected.not_to match_route(['some', 'route', 'foo', 'bar']) } + it { is_expected.not_to match_route %w[foo] } it { is_expected.not_to match_route [:id] } end end - context "applying bindings" do - context "on the root path" do + context 'applying bindings' do + context 'on the root path' do subject { described_class.new([], resource) } before { subject.apply(request) } - it "should assign the dispatched path to the empty string" do - expect(request.disp_path).to eq("") + it 'should assign the dispatched path to the empty string' do + expect(request.disp_path).to eq('') end - it "should assign empty bindings" do + it 'should assign empty bindings' do expect(request.path_info).to eq({}) end - it "should assign empty path tokens" do + it 'should assign empty path tokens' do expect(request.path_tokens).to eq([]) end - context "with extra user-defined bindings" do - subject { described_class.new([], resource, "bar" => "baz") } + context 'with extra user-defined bindings' do + subject { described_class.new([], resource, 'bar' => 'baz') } - it "should assign the user-defined bindings" do - expect(request.path_info).to eq({"bar" => "baz"}) + it 'should assign the user-defined bindings' do + expect(request.path_info).to eq({'bar' => 'baz'}) end end - context "with a splat" do + context 'with a splat' do subject { described_class.new([:*], resource) } - it "should assign empty path tokens" do + it 'should assign empty path tokens' do expect(request.path_tokens).to eq([]) end end - context "with a deprecated splat string" do + context 'with a deprecated splat string' do subject { described_class.new(['*'], resource) } - it "should assign empty path tokens" do + it 'should assign empty path tokens' do expect(request.path_tokens).to eq([]) end end end - context "on a deep path" do - subject { described_class.new(%w{foo bar baz}, resource) } - let(:uri) { URI.parse("http://localhost:8080/foo/bar/baz") } + context 'on a deep path' do + subject { described_class.new(%w[foo bar baz], resource) } + let(:uri) { URI.parse('http://localhost:8080/foo/bar/baz') } before { subject.apply(request) } - it "should assign the dispatched path as the path past the initial slash" do - expect(request.disp_path).to eq("foo/bar/baz") + it 'should assign the dispatched path as the path past the initial slash' do + expect(request.disp_path).to eq('foo/bar/baz') end - it "should assign empty bindings" do + it 'should assign empty bindings' do expect(request.path_info).to eq({}) end - it "should assign empty path tokens" do + it 'should assign empty path tokens' do expect(request.path_tokens).to eq([]) end - context "with path variables" do + context 'with path variables' do subject { described_class.new(['foo', :id, 'baz'], resource) } - it "should assign the path variables in the bindings" do - expect(request.path_info).to eq({:id => "bar"}) + it 'should assign the path variables in the bindings' do + expect(request.path_info).to eq({id: 'bar'}) end end - context "with regex" do + context 'with regex' do subject { described_class.new([/foo/, /(.*)/, 'baz'], resource) } - it "should assign the captures path variables" do - expect(request.path_info).to eq({:captures => ["bar"]}) + it 'should assign the captures path variables' do + expect(request.path_info).to eq({captures: ['bar']}) end end - context "with multi-capture regex" do + context 'with multi-capture regex' do subject { described_class.new([/foo/, /(.*)/, /baz\.(.*)/], resource) } - let(:uri) { URI.parse("http://localhost:8080/foo/bar/baz.json") } + let(:uri) { URI.parse('http://localhost:8080/foo/bar/baz.json') } - it "should assign the captures path variables" do - expect(request.path_info).to eq({:captures => ["bar", "json"]}) + it 'should assign the captures path variables' do + expect(request.path_info).to eq({captures: ['bar', 'json']}) end end - context "with named capture regex" do + context 'with named capture regex' do subject { described_class.new(['foo', :bar, /(?[^.]+)\.(?.*)/], resource) } - let(:uri) { URI.parse("http://localhost:8080/foo/bar/baz.json") } + let(:uri) { URI.parse('http://localhost:8080/foo/bar/baz.json') } - it "should assign the captures path variables" do - expect(request.path_info).to eq({bar: 'bar', baz: 'baz', format: "json"}) + it 'should assign the captures path variables' do + expect(request.path_info).to eq({bar: 'bar', baz: 'baz', format: 'json'}) end end - context "with a splat" do + context 'with a splat' do subject { described_class.new(['foo', :*], resource) } - it "should capture the path tokens matched by the splat" do - expect(request.path_tokens).to eq(%w{ bar baz }) + it 'should capture the path tokens matched by the splat' do + expect(request.path_tokens).to eq(%w[bar baz]) end end - context "with a deprecated splat string" do - subject { described_class.new(%w{foo *}, resource) } + context 'with a deprecated splat string' do + subject { described_class.new(%w[foo *], resource) } - it "should capture the path tokens matched by the splat" do - expect(request.path_tokens).to eq(%w{ bar baz }) + it 'should capture the path tokens matched by the splat' do + expect(request.path_tokens).to eq(%w[bar baz]) end end end diff --git a/spec/webmachine/dispatcher_spec.rb b/spec/webmachine/dispatcher_spec.rb index 229f3991..795ff0ab 100644 --- a/spec/webmachine/dispatcher_spec.rb +++ b/spec/webmachine/dispatcher_spec.rb @@ -2,17 +2,21 @@ describe Webmachine::Dispatcher do let(:dispatcher) { Webmachine.application.dispatcher } - let(:request) { Webmachine::Request.new("GET", URI.parse("http://localhost:8080/"), Webmachine::Headers["accept" => "*/*"], "") } - let(:request2) { Webmachine::Request.new("GET", URI.parse("http://localhost:8080/hello/bob.html"), Webmachine::Headers["accept" => "*/*"], "") } + let(:request) { Webmachine::Request.new('GET', URI.parse('http://localhost:8080/'), Webmachine::Headers['accept' => '*/*'], '') } + let(:request2) { Webmachine::Request.new('GET', URI.parse('http://localhost:8080/hello/bob.html'), Webmachine::Headers['accept' => '*/*'], '') } let(:response) { Webmachine::Response.new } let(:resource) do Class.new(Webmachine::Resource) do - def to_html; "hello world!"; end + def to_html + 'hello world!' + end end end let(:resource2) do Class.new(Webmachine::Resource) do - def to_html; "goodbye, cruel world"; end + def to_html + 'goodbye, cruel world' + end end end let(:resource3) do @@ -23,11 +27,11 @@ def to_html end end end - let(:fsm){ double } + let(:fsm) { double } before { dispatcher.reset } - it "should add routes from a block" do + it 'should add routes from a block' do _resource = resource expect(Webmachine.routes do add [:*], _resource @@ -35,33 +39,33 @@ def to_html expect(dispatcher.routes.size).to eq(1) end - it "should add routes" do + it 'should add routes' do expect { dispatcher.add_route [:*], resource }.to_not raise_error end - it "should have add_route return the newly created route" do + it 'should have add_route return the newly created route' do route = dispatcher.add_route [:*], resource expect(route).to be_instance_of Webmachine::Dispatcher::Route end - it "should route to the proper resource" do - dispatcher.add_route ["goodbye"], resource2 + it 'should route to the proper resource' do + dispatcher.add_route ['goodbye'], resource2 dispatcher.add_route [:*], resource expect(Webmachine::Decision::FSM).to receive(:new).with(instance_of(resource), request, response).and_return(fsm) expect(fsm).to receive(:run) dispatcher.dispatch(request, response) end - it "should handle regex path segments in route definition" do - dispatcher.add_route ["hello", /(.*)\.(.*)/], resource3 + it 'should handle regex path segments in route definition' do + dispatcher.add_route ['hello', /(.*)\.(.*)/], resource3 expect(Webmachine::Decision::FSM).to receive(:new).with(instance_of(resource3), request2, response).and_return(fsm) expect(fsm).to receive(:run) dispatcher.dispatch(request2, response) end - it "should apply route to request before creating the resource" do - route = dispatcher.add_route [:*], resource + it 'should apply route to request before creating the resource' do + route = dispatcher.add_route [:*], resource applied = false expect(route).to receive(:apply) { applied = true } @@ -73,32 +77,32 @@ def to_html dispatcher.dispatch(request, response) end - it "should add routes with guards" do - dispatcher.add [], lambda {|req| req.method == "POST" }, resource + it 'should add routes with guards' do + dispatcher.add [], lambda { |req| req.method == 'POST' }, resource dispatcher.add [:*], resource2 do |req| !req.query.empty? end - request.uri.query = "?foo=bar" + request.uri.query = '?foo=bar' expect(dispatcher.routes.size).to eq(2) expect(Webmachine::Decision::FSM).to receive(:new).with(instance_of(resource2), request, response).and_return(fsm) expect(fsm).to receive(:run) dispatcher.dispatch(request, response) end - it "should respond with a valid resource for a 404" do + it 'should respond with a valid resource for a 404' do dispatcher.dispatch(request, response) - expect(response.code).to eq(404) + expect(response.code).to eq(404) expect(response.body).to_not be_empty - expect(response.headers).to have_key('Content-Length') - expect(response.headers).to have_key('Date') + expect(response.headers).to have_key('Content-Length') + expect(response.headers).to have_key('Date') end - it "should respond with a valid resource for a 404 with a custom Accept header" do - request.headers['Accept'] = "application/json" + it 'should respond with a valid resource for a 404 with a custom Accept header' do + request.headers['Accept'] = 'application/json' dispatcher.dispatch(request, response) - expect(response.code).to eq(404) + expect(response.code).to eq(404) expect(response.body).to_not be_empty - expect(response.headers).to have_key('Content-Length') - expect(response.headers).to have_key('Date') + expect(response.headers).to have_key('Content-Length') + expect(response.headers).to have_key('Date') end end diff --git a/spec/webmachine/errors_spec.rb b/spec/webmachine/errors_spec.rb index 84b9c493..2b10ae59 100644 --- a/spec/webmachine/errors_spec.rb +++ b/spec/webmachine/errors_spec.rb @@ -1,9 +1,9 @@ require 'spec_helper' -describe "Webmachine errors" do - describe ".render_error" do - it "sets the given response code on the response object" do - req = double('request', :method => 'GET').as_null_object +describe 'Webmachine errors' do + describe '.render_error' do + it 'sets the given response code on the response object' do + req = double('request', method: 'GET').as_null_object res = Webmachine::Response.new Webmachine.render_error(404, req, res) diff --git a/spec/webmachine/etags_spec.rb b/spec/webmachine/etags_spec.rb index c3266c03..e8e65629 100644 --- a/spec/webmachine/etags_spec.rb +++ b/spec/webmachine/etags_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Webmachine::ETag do - let(:etag_str){ '"deadbeef12345678"' } + let(:etag_str) { '"deadbeef12345678"' } let(:etag) { described_class.new etag_str } subject { etag } @@ -12,7 +12,7 @@ its(:etag) { should == '"deadbeef12345678"' } it { is_expected.to eq(described_class.new(etag_str.dup)) } - context "when the original etag is unquoted" do + context 'when the original etag is unquoted' do let(:etag_str) { 'deadbeef12345678' } it { is_expected.to eq(etag_str) } @@ -21,7 +21,7 @@ it { is_expected.to eq(described_class.new(etag_str.dup)) } end - context "when the original etag contains unbalanced quotes" do + context 'when the original etag contains unbalanced quotes' do let(:etag_str) { 'deadbeef"12345678' } it { is_expected.to eq(etag_str) } @@ -32,7 +32,7 @@ end describe Webmachine::WeakETag do - let(:strong_etag){ '"deadbeef12345678"' } + let(:strong_etag) { '"deadbeef12345678"' } let(:weak_etag) { described_class.new strong_etag } subject { weak_etag } @@ -43,7 +43,7 @@ its(:etag) { should == '"deadbeef12345678"' } it { is_expected.to eq(described_class.new(strong_etag.dup)) } - context "when the original etag is unquoted" do + context 'when the original etag is unquoted' do let(:strong_etag) { 'deadbeef12345678' } it { is_expected.to eq(strong_etag) } @@ -53,7 +53,7 @@ it { is_expected.to eq(described_class.new(strong_etag.dup)) } end - context "when the original etag contains unbalanced quotes" do + context 'when the original etag contains unbalanced quotes' do let(:strong_etag) { 'deadbeef"12345678' } it { is_expected.to eq(strong_etag) } @@ -63,7 +63,7 @@ it { is_expected.to eq(described_class.new(strong_etag.dup)) } end - context "when the original etag is already a weak tag" do + context 'when the original etag is already a weak tag' do let(:strong_etag) { 'W/"deadbeef12345678"' } it { is_expected.to eq(strong_etag) } diff --git a/spec/webmachine/events_spec.rb b/spec/webmachine/events_spec.rb index aa703476..889802be 100644 --- a/spec/webmachine/events_spec.rb +++ b/spec/webmachine/events_spec.rb @@ -1,54 +1,54 @@ require 'spec_helper' describe Webmachine::Events do - describe ".backend" do - it "defaults to AS::Notifications" do + describe '.backend' do + it 'defaults to AS::Notifications' do expect(described_class.backend).to be(AS::Notifications) end end - describe ".publish" do - it "calls the backend" do + describe '.publish' do + it 'calls the backend' do expect(described_class.backend).to receive(:publish).with('test.event', 1, 'two') described_class.publish('test.event', 1, 'two') end end - describe ".instrument" do - it "calls the backend" do + describe '.instrument' do + it 'calls the backend' do expect(described_class.backend).to receive(:instrument).with( 'test.event', {} ).and_yield - described_class.instrument('test.event') { } + described_class.instrument('test.event') {} end end - describe ".subscribe" do - it "calls the backend" do + describe '.subscribe' do + it 'calls the backend' do expect(described_class.backend).to receive(:subscribe).with( 'test.event' ).and_yield - described_class.subscribe('test.event') { } + described_class.subscribe('test.event') {} end end - describe ".subscribed" do - it "calls the backend" do - callback = Proc.new { } + describe '.subscribed' do + it 'calls the backend' do + callback = proc {} expect(described_class.backend).to receive(:subscribed).with( callback, 'test.event' ).and_yield - described_class.subscribed(callback, 'test.event') { } + described_class.subscribed(callback, 'test.event') {} end end - describe ".unsubscribe" do - it "calls the backend" do - subscriber = described_class.subscribe('test.event') { } + describe '.unsubscribe' do + it 'calls the backend' do + subscriber = described_class.subscribe('test.event') {} expect(described_class.backend).to receive(:unsubscribe).with(subscriber) diff --git a/spec/webmachine/headers_spec.rb b/spec/webmachine/headers_spec.rb index bc2c497c..fe1107ae 100644 --- a/spec/webmachine/headers_spec.rb +++ b/spec/webmachine/headers_spec.rb @@ -1,22 +1,22 @@ require 'spec_helper' describe Webmachine::Headers do - it "should set and access values insensitive to case" do - subject['Content-TYPE'] = "text/plain" + it 'should set and access values insensitive to case' do + subject['Content-TYPE'] = 'text/plain' expect(subject['CONTENT-TYPE']).to eq('text/plain') expect(subject.delete('CoNtEnT-tYpE')).to eq('text/plain') end - describe "#from_cgi" do - it "should understand the Content-Length header" do - headers = described_class.from_cgi("CONTENT_LENGTH" => 14) - expect(headers["content-length"]).to eq(14) + describe '#from_cgi' do + it 'should understand the Content-Length header' do + headers = described_class.from_cgi('CONTENT_LENGTH' => 14) + expect(headers['content-length']).to eq(14) end end - describe ".[]" do + describe '.[]' do context "Webmachine::Headers['Content-Type', 'application/json']" do - it "creates a hash with lowercase keys" do + it 'creates a hash with lowercase keys' do headers = described_class[ 'Content-Type', 'application/json', 'Accept', 'application/json' @@ -30,7 +30,7 @@ end context "Webmachine::Headers[[['Content-Type', 'application/json']]]" do - it "creates a hash with lowercase keys" do + it 'creates a hash with lowercase keys' do headers = described_class[ [ ['Content-Type', 'application/json'], @@ -46,7 +46,7 @@ end context "Webmachine::Headers['Content-Type' => 'application/json']" do - it "creates a hash with lowercase keys" do + it 'creates a hash with lowercase keys' do headers = described_class[ 'Content-Type' => 'application/json', 'Accept' => 'application/json' @@ -60,39 +60,39 @@ end end - describe "#fetch" do + describe '#fetch' do subject { described_class['Content-Type' => 'application/json'] } - it "returns the value for the given key" do + it 'returns the value for the given key' do expect(subject.fetch('conTent-tYpe')).to eq('application/json') end - context "acessing a missing key" do - it "raises an IndexError" do + context 'acessing a missing key' do + it 'raises an IndexError' do expect { subject.fetch('accept') }.to raise_error(IndexError) end - context "and a default value given" do - it "returns the default value if the key does not exist" do + context 'and a default value given' do + it 'returns the default value if the key does not exist' do expect(subject.fetch('accept', 'text/html')).to eq('text/html') end end - context "and a block given" do + context 'and a block given' do it "passes the value to the block and returns the block's result" do - expect(subject.fetch('access') {|k| "#{k} not found"}).to eq('access not found') + expect(subject.fetch('access') { |k| "#{k} not found" }).to eq('access not found') end end end end - context "filtering with #grep" do - subject { described_class["content-type" => "text/plain", "etag" => '"abcdef1234567890"'] } - it "should filter keys by the given pattern" do - expect(subject.grep(/content/i)).to include("content-type") + context 'filtering with #grep' do + subject { described_class['content-type' => 'text/plain', 'etag' => '"abcdef1234567890"'] } + it 'should filter keys by the given pattern' do + expect(subject.grep(/content/i)).to include('content-type') end - it "should return a Headers instance" do + it 'should return a Headers instance' do expect(subject.grep(/etag/i)).to be_instance_of(described_class) end end diff --git a/spec/webmachine/media_type_spec.rb b/spec/webmachine/media_type_spec.rb index 9d7b7598..e9cc4144 100644 --- a/spec/webmachine/media_type_spec.rb +++ b/spec/webmachine/media_type_spec.rb @@ -1,85 +1,85 @@ require 'spec_helper' describe Webmachine::MediaType do - let(:raw_type){ "application/xml;charset=UTF-8" } - subject { described_class.new("application/xml", {"charset" => "UTF-8"}) } + let(:raw_type) { 'application/xml;charset=UTF-8' } + subject { described_class.new('application/xml', {'charset' => 'UTF-8'}) } - context "equivalence" do + context 'equivalence' do it { is_expected.to eq(raw_type) } it { is_expected.to eq(described_class.parse(raw_type)) } end - context "when it is the wildcard type" do - subject { described_class.new("*/*") } + context 'when it is the wildcard type' do + subject { described_class.new('*/*') } it { is_expected.to be_matches_all } end - context "parsing a type" do - it "should return MediaTypes untouched" do + context 'parsing a type' do + it 'should return MediaTypes untouched' do expect(described_class.parse(subject)).to equal(subject) end - it "should parse a String" do + it 'should parse a String' do type = described_class.parse(raw_type) expect(type).to be_kind_of(described_class) - expect(type.type).to eq("application/xml") - expect(type.params).to eq({"charset" => "UTF-8"}) + expect(type.type).to eq('application/xml') + expect(type.params).to eq({'charset' => 'UTF-8'}) end - it "should parse a type/params pair" do - type = described_class.parse(["application/xml", {"charset" => "UTF-8"}]) + it 'should parse a type/params pair' do + type = described_class.parse(['application/xml', {'charset' => 'UTF-8'}]) expect(type).to be_kind_of(described_class) - expect(type.type).to eq("application/xml") - expect(type.params).to eq({"charset" => "UTF-8"}) + expect(type.type).to eq('application/xml') + expect(type.params).to eq({'charset' => 'UTF-8'}) end - it "should parse a type/params pair where the type has some params in the string" do - type = described_class.parse(["application/xml;version=1", {"charset" => "UTF-8"}]) + it 'should parse a type/params pair where the type has some params in the string' do + type = described_class.parse(['application/xml;version=1', {'charset' => 'UTF-8'}]) expect(type).to be_kind_of(described_class) - expect(type.type).to eq("application/xml") - expect(type.params).to eq({"charset" => "UTF-8", "version" => "1"}) + expect(type.type).to eq('application/xml') + expect(type.params).to eq({'charset' => 'UTF-8', 'version' => '1'}) end - it "should parse a type/params pair with params and whitespace in the string" do - type = described_class.parse(["multipart/form-data; boundary=----------------------------2c46a7bec2b9", {"charset" => "UTF-8"}]) + it 'should parse a type/params pair with params and whitespace in the string' do + type = described_class.parse(['multipart/form-data; boundary=----------------------------2c46a7bec2b9', {'charset' => 'UTF-8'}]) expect(type).to be_kind_of(described_class) - expect(type.type).to eq("multipart/form-data") - expect(type.params).to eq({"boundary" => "----------------------------2c46a7bec2b9", "charset" => "UTF-8"}) + expect(type.type).to eq('multipart/form-data') + expect(type.params).to eq({'boundary' => '----------------------------2c46a7bec2b9', 'charset' => 'UTF-8'}) end - it "should parse a type/params pair where type has single-token params" do - type = described_class.parse(["text/html;q=1;rdfa", {"charset" => "UTF-8"}]) + it 'should parse a type/params pair where type has single-token params' do + type = described_class.parse(['text/html;q=1;rdfa', {'charset' => 'UTF-8'}]) expect(type).to be_kind_of(described_class) - expect(type.type).to eq("text/html") - expect(type.params).to eq({"q" => "1", "rdfa" => "", "charset" => "UTF-8"}) + expect(type.type).to eq('text/html') + expect(type.params).to eq({'q' => '1', 'rdfa' => '', 'charset' => 'UTF-8'}) end - it "should raise an error when given an invalid type/params pair" do + it 'should raise an error when given an invalid type/params pair' do expect { - described_class.parse([false, "blah"]) + described_class.parse([false, 'blah']) }.to raise_error(ArgumentError) end end - describe "matching a requested type" do - it { is_expected.to be_exact_match("application/xml;charset=UTF-8") } - it { is_expected.to be_exact_match("application/*;charset=UTF-8") } - it { is_expected.to be_exact_match("*/*;charset=UTF-8") } - it { is_expected.to be_exact_match("*;charset=UTF-8") } - it { is_expected.not_to be_exact_match("text/xml") } - it { is_expected.not_to be_exact_match("application/xml") } - it { is_expected.not_to be_exact_match("application/xml;version=1") } + describe 'matching a requested type' do + it { is_expected.to be_exact_match('application/xml;charset=UTF-8') } + it { is_expected.to be_exact_match('application/*;charset=UTF-8') } + it { is_expected.to be_exact_match('*/*;charset=UTF-8') } + it { is_expected.to be_exact_match('*;charset=UTF-8') } + it { is_expected.not_to be_exact_match('text/xml') } + it { is_expected.not_to be_exact_match('application/xml') } + it { is_expected.not_to be_exact_match('application/xml;version=1') } - it { is_expected.to be_type_matches("application/xml") } - it { is_expected.to be_type_matches("application/*") } - it { is_expected.to be_type_matches("*/*") } - it { is_expected.to be_type_matches("*") } - it { is_expected.not_to be_type_matches("text/xml") } - it { is_expected.not_to be_type_matches("text/*") } + it { is_expected.to be_type_matches('application/xml') } + it { is_expected.to be_type_matches('application/*') } + it { is_expected.to be_type_matches('*/*') } + it { is_expected.to be_type_matches('*') } + it { is_expected.not_to be_type_matches('text/xml') } + it { is_expected.not_to be_type_matches('text/*') } - it { is_expected.to be_params_match({}) } - it { is_expected.to be_params_match({"charset" => "UTF-8"}) } - it { is_expected.not_to be_params_match({"charset" => "Windows-1252"}) } - it { is_expected.not_to be_params_match({"version" => "3"}) } + it { is_expected.to be_params_match({}) } + it { is_expected.to be_params_match({'charset' => 'UTF-8'}) } + it { is_expected.not_to be_params_match({'charset' => 'Windows-1252'}) } + it { is_expected.not_to be_params_match({'version' => '3'}) } end end diff --git a/spec/webmachine/request_spec.rb b/spec/webmachine/request_spec.rb index bfcab25c..28c93596 100644 --- a/spec/webmachine/request_spec.rb +++ b/spec/webmachine/request_spec.rb @@ -3,64 +3,64 @@ describe Webmachine::Request do subject { request } - let(:uri) { URI.parse("http://localhost:8080/some/resource") } - let(:http_method) { "GET" } - let(:headers) { Webmachine::Headers.new } - let(:body) { "" } - let(:routing_tokens) { nil } - let(:base_uri) { nil } - let(:request) { Webmachine::Request.new(http_method, uri, headers, body, routing_tokens, base_uri) } - - it "should provide access to the headers via brackets" do - subject.headers['Accept'] = "*/*" - expect(subject["accept"]).to eq("*/*") + let(:uri) { URI.parse('http://localhost:8080/some/resource') } + let(:http_method) { 'GET' } + let(:headers) { Webmachine::Headers.new } + let(:body) { '' } + let(:routing_tokens) { nil } + let(:base_uri) { nil } + let(:request) { Webmachine::Request.new(http_method, uri, headers, body, routing_tokens, base_uri) } + + it 'should provide access to the headers via brackets' do + subject.headers['Accept'] = '*/*' + expect(subject['accept']).to eq('*/*') end - it "should provide access to the cookies" do - subject.headers['Cookie'] = 'name=value;name2=value2'; - expect(subject.cookies).to eq({ 'name' => 'value', 'name2' => 'value2' }) + it 'should provide access to the cookies' do + subject.headers['Cookie'] = 'name=value;name2=value2' + expect(subject.cookies).to eq({'name' => 'value', 'name2' => 'value2'}) end - it "should handle cookies with extra whitespace" do - subject.headers['Cookie'] = 'name = value; name2 = value2'; - expect(subject.cookies).to eq({ 'name' => 'value', 'name2' => 'value2' }) + it 'should handle cookies with extra whitespace' do + subject.headers['Cookie'] = 'name = value; name2 = value2' + expect(subject.cookies).to eq({'name' => 'value', 'name2' => 'value2'}) end - it "should provide access to the headers via underscored methods" do - subject.headers["Accept-Encoding"] = "identity" - expect(subject.accept_encoding).to eq("identity") + it 'should provide access to the headers via underscored methods' do + subject.headers['Accept-Encoding'] = 'identity' + expect(subject.accept_encoding).to eq('identity') expect(subject.content_md5).to be_nil end - context "base_uri" do - it "should calculate a base URI" do - expect(subject.base_uri).to eq(URI.parse("http://localhost:8080/")) + context 'base_uri' do + it 'should calculate a base URI' do + expect(subject.base_uri).to eq(URI.parse('http://localhost:8080/')) end - context "when base_uri has been explicitly set" do - let(:base_uri) { URI.parse("http://localhost:8080/some_base_uri/here") } - it "should use the provided base_uri" do - expect(subject.base_uri).to eq(URI.parse("http://localhost:8080/some_base_uri/here")) + context 'when base_uri has been explicitly set' do + let(:base_uri) { URI.parse('http://localhost:8080/some_base_uri/here') } + it 'should use the provided base_uri' do + expect(subject.base_uri).to eq(URI.parse('http://localhost:8080/some_base_uri/here')) end end end - it "should provide a hash of query parameters" do - subject.uri.query = "foo=bar&baz=bam" - expect(subject.query).to eq({"foo" => "bar", "baz" => "bam"}) + it 'should provide a hash of query parameters' do + subject.uri.query = 'foo=bar&baz=bam' + expect(subject.query).to eq({'foo' => 'bar', 'baz' => 'bam'}) end - it "should handle = being encoded as a query value." do - subject.uri.query = "foo=bar%3D%3D" - expect(subject.query).to eq({ "foo" => "bar=="}) + it 'should handle = being encoded as a query value.' do + subject.uri.query = 'foo=bar%3D%3D' + expect(subject.query).to eq({'foo' => 'bar=='}) end it "should treat '+' characters in query parameters as spaces" do - subject.uri.query = "a%20b=foo+bar&c+d=baz%20quux" - expect(subject.query).to eq({"a b" => "foo bar", "c d" => "baz quux"}) + subject.uri.query = 'a%20b=foo+bar&c+d=baz%20quux' + expect(subject.query).to eq({'a b' => 'foo bar', 'c d' => 'baz quux'}) end - it "should handle a query parameter value of nil" do + it 'should handle a query parameter value of nil' do subject.uri.query = nil expect(subject.query).to eq({}) end @@ -68,38 +68,43 @@ describe '#has_body?' do let(:wreq) do Class.new { - def initialize(body); @body = body; end - def body; block_given? ? yield(@body) : @body; end + def initialize(body) + @body = body + end + + def body + block_given? ? yield(@body) : @body + end } end subject { request.has_body? } - context "when body is nil" do + context 'when body is nil' do let(:body) { nil } it { is_expected.to be(false) } end - context "when body is an empty string" do + context 'when body is an empty string' do let(:body) { '' } it { is_expected.to be(false) } end - context "when body is not empty" do + context 'when body is not empty' do let(:body) { 'foo' } it { is_expected.to be(true) } end - context "when body is an empty LazyRequestBody" do + context 'when body is an empty LazyRequestBody' do let(:body) { Webmachine::Adapters::LazyRequestBody.new(wreq.new('')) } it { is_expected.to be(false) } end - context "when body is a LazyRequestBody" do + context 'when body is a LazyRequestBody' do let(:body) { Webmachine::Adapters::LazyRequestBody.new(wreq.new('foo')) } it { is_expected.to be(true) } @@ -109,14 +114,14 @@ def body; block_given? ? yield(@body) : @body; end describe '#https?' do subject { request.https? } - context "when the request was issued via HTTPS" do - let(:uri) { URI.parse("https://localhost.com:8080/some/resource") } + context 'when the request was issued via HTTPS' do + let(:uri) { URI.parse('https://localhost.com:8080/some/resource') } it { is_expected.to be(true) } end - context "when the request was not issued via HTTPS" do - let(:uri) { URI.parse("http://localhost.com:8080/some/resource") } + context 'when the request was not issued via HTTPS' do + let(:uri) { URI.parse('http://localhost.com:8080/some/resource') } it { is_expected.to be(false) } end @@ -125,14 +130,14 @@ def body; block_given? ? yield(@body) : @body; end describe '#get?' do subject { request.get? } - context "when the request method is GET" do - let(:http_method) { "GET" } + context 'when the request method is GET' do + let(:http_method) { 'GET' } it { is_expected.to be(true) } end - context "when the request method is not GET" do - let(:http_method) { "POST" } + context 'when the request method is not GET' do + let(:http_method) { 'POST' } it { is_expected.to be(false) } end @@ -141,14 +146,14 @@ def body; block_given? ? yield(@body) : @body; end describe '#head?' do subject { request.head? } - context "when the request method is HEAD" do - let(:http_method) { "HEAD" } + context 'when the request method is HEAD' do + let(:http_method) { 'HEAD' } it { is_expected.to be(true) } end - context "when the request method is not HEAD" do - let(:http_method) { "GET" } + context 'when the request method is not HEAD' do + let(:http_method) { 'GET' } it { is_expected.to be(false) } end @@ -157,14 +162,14 @@ def body; block_given? ? yield(@body) : @body; end describe '#post?' do subject { request.post? } - context "when the request method is POST" do - let(:http_method) { "POST" } + context 'when the request method is POST' do + let(:http_method) { 'POST' } it { is_expected.to be(true) } end - context "when the request method is not POST" do - let(:http_method) { "GET" } + context 'when the request method is not POST' do + let(:http_method) { 'GET' } it { is_expected.to be(false) } end @@ -173,14 +178,14 @@ def body; block_given? ? yield(@body) : @body; end describe '#put?' do subject { request.put? } - context "when the request method is PUT" do - let(:http_method) { "PUT" } + context 'when the request method is PUT' do + let(:http_method) { 'PUT' } it { is_expected.to be(true) } end - context "when the request method is not PUT" do - let(:http_method) { "GET" } + context 'when the request method is not PUT' do + let(:http_method) { 'GET' } it { is_expected.to be(false) } end @@ -189,14 +194,14 @@ def body; block_given? ? yield(@body) : @body; end describe '#delete?' do subject { request.delete? } - context "when the request method is DELETE" do - let(:http_method) { "DELETE" } + context 'when the request method is DELETE' do + let(:http_method) { 'DELETE' } it { is_expected.to be(true) } end - context "when the request method is not DELETE" do - let(:http_method) { "GET" } + context 'when the request method is not DELETE' do + let(:http_method) { 'GET' } it { is_expected.to be(false) } end @@ -205,14 +210,14 @@ def body; block_given? ? yield(@body) : @body; end describe '#trace?' do subject { request.trace? } - context "when the request method is TRACE" do - let(:http_method) { "TRACE" } + context 'when the request method is TRACE' do + let(:http_method) { 'TRACE' } it { is_expected.to be(true) } end - context "when the request method is not TRACE" do - let(:http_method) { "GET" } + context 'when the request method is not TRACE' do + let(:http_method) { 'GET' } it { is_expected.to be(false) } end @@ -221,14 +226,14 @@ def body; block_given? ? yield(@body) : @body; end describe '#connect?' do subject { request.connect? } - context "when the request method is CONNECT" do - let(:http_method) { "CONNECT" } + context 'when the request method is CONNECT' do + let(:http_method) { 'CONNECT' } it { is_expected.to be(true) } end - context "when the request method is not CONNECT" do - let(:http_method) { "GET" } + context 'when the request method is not CONNECT' do + let(:http_method) { 'GET' } it { is_expected.to be(false) } end @@ -237,14 +242,14 @@ def body; block_given? ? yield(@body) : @body; end describe '#options?' do subject { request.options? } - context "when the request method is OPTIONS" do - let(:http_method) { "OPTIONS" } + context 'when the request method is OPTIONS' do + let(:http_method) { 'OPTIONS' } it { is_expected.to be(true) } end - context "when the request method is not OPTIONS" do - let(:http_method) { "GET" } + context 'when the request method is not OPTIONS' do + let(:http_method) { 'GET' } it { is_expected.to be(false) } end @@ -255,19 +260,17 @@ def body; block_given? ? yield(@body) : @body; end context "haven't been explicitly set" do let(:routing_tokens) { nil } - it "extracts the routing tokens from the path portion of the uri" do - expect(subject).to eq(["some", "resource"]) + it 'extracts the routing tokens from the path portion of the uri' do + expect(subject).to eq(['some', 'resource']) end end - context "have been explicitly set" do - let(:routing_tokens) { ["foo", "bar"] } + context 'have been explicitly set' do + let(:routing_tokens) { ['foo', 'bar'] } - it "uses the specified routing_tokens" do - expect(subject).to eq(["foo", "bar"]) + it 'uses the specified routing_tokens' do + expect(subject).to eq(['foo', 'bar']) end end - end - end diff --git a/spec/webmachine/rescueable_exception_spec.rb b/spec/webmachine/rescueable_exception_spec.rb index 819c3bad..0147d2ed 100644 --- a/spec/webmachine/rescueable_exception_spec.rb +++ b/spec/webmachine/rescueable_exception_spec.rb @@ -2,12 +2,12 @@ RSpec.describe Webmachine::RescuableException do before { described_class.default! } - describe ".UNRESCUABLEs" do - specify "returns an array of UNRESCUABLE exceptions" do + describe '.UNRESCUABLEs' do + specify 'returns an array of UNRESCUABLE exceptions' do expect(described_class.UNRESCUABLEs).to eq(described_class::UNRESCUABLE_DEFAULTS) end - specify "returns an array of UNRESCUABLE exceptions, with custom exceptions added" do + specify 'returns an array of UNRESCUABLE exceptions, with custom exceptions added' do described_class.remove(Exception) expect(described_class.UNRESCUABLEs).to eq(described_class::UNRESCUABLE_DEFAULTS.dup.concat([Exception])) end diff --git a/spec/webmachine/resource/authentication_spec.rb b/spec/webmachine/resource/authentication_spec.rb index 8dad61bc..cf9ebb58 100644 --- a/spec/webmachine/resource/authentication_spec.rb +++ b/spec/webmachine/resource/authentication_spec.rb @@ -3,63 +3,65 @@ describe Webmachine::Resource::Authentication do subject { Webmachine::Decision::FSM.new(resource, request, response) } let(:method) { 'GET' } - let(:uri) { URI.parse("http://localhost/") } + let(:uri) { URI.parse('http://localhost/') } let(:headers) { Webmachine::Headers.new } - let(:body) { "" } + let(:body) { '' } let(:request) { Webmachine::Request.new(method, uri, headers, body) } let(:response) { Webmachine::Response.new } def resource_with(&block) klass = Class.new(Webmachine::Resource) do - def to_html; "test resource"; end + def to_html + 'test resource' + end end - klass.module_eval(&block) if block_given? + klass.module_eval(&block) if block klass.new(request, response) end - describe "Basic authentication" do + describe 'Basic authentication' do let(:resource) do resource_with do include Webmachine::Resource::Authentication attr_accessor :realm def is_authorized?(auth) - basic_auth(auth, @realm || "Webmachine") {|u,p| u == "webmachine" && p == "http" } + basic_auth(auth, @realm || 'Webmachine') { |u, p| u == 'webmachine' && p == 'http' } end end end - context "when no authorization is sent by the client" do - it "should reply with a 401 Unauthorized and a WWW-Authenticate header using Basic" do + context 'when no authorization is sent by the client' do + it 'should reply with a 401 Unauthorized and a WWW-Authenticate header using Basic' do subject.run expect(response.code).to eq(401) expect(response.headers['WWW-Authenticate']).to eq('Basic realm="Webmachine"') end - it "should use the specified realm in the WWW-Authenticate header" do - resource.realm = "My App" + it 'should use the specified realm in the WWW-Authenticate header' do + resource.realm = 'My App' subject.run expect(response.headers['WWW-Authenticate']).to eq('Basic realm="My App"') end end - context "when the client sends invalid authorization" do + context 'when the client sends invalid authorization' do before do - headers['Authorization'] = "Basic " + ["invalid:auth"].pack('m*').chomp + headers['Authorization'] = 'Basic ' + ['invalid:auth'].pack('m*').chomp end - it "should reply with a 401 Unauthorized and a WWW-Authenticate header using Basic" do + it 'should reply with a 401 Unauthorized and a WWW-Authenticate header using Basic' do subject.run expect(response.code).to eq(401) expect(response.headers['WWW-Authenticate']).to eq('Basic realm="Webmachine"') end end - context "when the client sends valid authorization" do + context 'when the client sends valid authorization' do before do - headers['Authorization'] = "Basic " + ["webmachine:http"].pack('m*').chomp + headers['Authorization'] = 'Basic ' + ['webmachine:http'].pack('m*').chomp end - it "should not reply with 401 Unauthorized" do + it 'should not reply with 401 Unauthorized' do subject.run expect(response.code).not_to eq(401) end diff --git a/spec/webmachine/response_spec.rb b/spec/webmachine/response_spec.rb index b6fc1e5e..4a81e060 100644 --- a/spec/webmachine/response_spec.rb +++ b/spec/webmachine/response_spec.rb @@ -1,50 +1,49 @@ require 'spec_helper' describe Webmachine::Response do - - it "should have sane default values" do + it 'should have sane default values' do expect(subject.code).to eq(200) expect(subject.is_redirect?).to be(false) expect(subject.headers).to be_empty end - describe "a redirected response" do - let(:redirect_url) { "/" } + describe 'a redirected response' do + let(:redirect_url) { '/' } before(:each) { subject.redirect_to redirect_url } its(:is_redirect?) { should be(true) } - it "should have a proper Location header" do - expect(subject.headers["Location"]).to eq(redirect_url) + it 'should have a proper Location header' do + expect(subject.headers['Location']).to eq(redirect_url) end end - describe "setting a cookie" do - let(:cookie) { "monster" } - let(:cookie_value) { "mash" } + describe 'setting a cookie' do + let(:cookie) { 'monster' } + let(:cookie_value) { 'mash' } before(:each) { subject.set_cookie(cookie, cookie_value) } - it "should have a proper Set-Cookie header" do - expect(subject.headers["Set-Cookie"]).to include "monster=mash" + it 'should have a proper Set-Cookie header' do + expect(subject.headers['Set-Cookie']).to include 'monster=mash' end - describe "setting multiple cookies" do - let(:cookie2) { "rodeo" } - let(:cookie2_value) { "clown" } - let(:cookie3) {"color"} - let(:cookie3_value) {"blue"} - before(:each) do + describe 'setting multiple cookies' do + let(:cookie2) { 'rodeo' } + let(:cookie2_value) { 'clown' } + let(:cookie3) { 'color' } + let(:cookie3_value) { 'blue' } + before(:each) do subject.set_cookie(cookie2, cookie2_value) subject.set_cookie(cookie3, cookie3_value) end - it "should have a proper Set-Cookie header" do - expect(subject.headers["Set-Cookie"]).to be_a Array - expect(subject.headers["Set-Cookie"]).to include "rodeo=clown" - expect(subject.headers["Set-Cookie"]).to include "monster=mash" - expect(subject.headers["Set-Cookie"]).to include "color=blue" + it 'should have a proper Set-Cookie header' do + expect(subject.headers['Set-Cookie']).to be_a Array + expect(subject.headers['Set-Cookie']).to include 'rodeo=clown' + expect(subject.headers['Set-Cookie']).to include 'monster=mash' + expect(subject.headers['Set-Cookie']).to include 'color=blue' end end end diff --git a/spec/webmachine/trace/fsm_spec.rb b/spec/webmachine/trace/fsm_spec.rb index 0ecc8a29..6e7a6a57 100644 --- a/spec/webmachine/trace/fsm_spec.rb +++ b/spec/webmachine/trace/fsm_spec.rb @@ -1,34 +1,34 @@ require 'spec_helper' describe Webmachine::Trace::FSM do - include_context "default resource" + include_context 'default resource' subject { Webmachine::Decision::FSM.new(resource, request, response) } before { Webmachine::Trace.trace_store = :memory } - context "when tracing is enabled" do + context 'when tracing is enabled' do before { allow(Webmachine::Trace).to receive(:trace?).and_return(true) } - it "proxies the resource" do + it 'proxies the resource' do expect(subject.resource).to be_kind_of(Webmachine::Trace::ResourceProxy) end - it "records a trace" do + it 'records a trace' do subject.run expect(response.trace).to_not be_empty expect(Webmachine::Trace.traces.size).to eq(1) end - it "commits the trace to separate storage when the request has finished processing" do + it 'commits the trace to separate storage when the request has finished processing' do expect(Webmachine::Trace).to receive(:record).with(subject.resource.object_id.to_s, response.trace).and_return(true) subject.run end end - context "when tracing is disabled" do + context 'when tracing is disabled' do before { allow(Webmachine::Trace).to receive(:trace?).and_return(false) } - it "leaves no trace" do + it 'leaves no trace' do subject.run expect(response.trace).to be_empty expect(Webmachine::Trace.traces).to be_empty diff --git a/spec/webmachine/trace/resource_proxy_spec.rb b/spec/webmachine/trace/resource_proxy_spec.rb index 4d87bf32..86e9cc3f 100644 --- a/spec/webmachine/trace/resource_proxy_spec.rb +++ b/spec/webmachine/trace/resource_proxy_spec.rb @@ -2,33 +2,32 @@ require 'webmachine/trace/resource_proxy' describe Webmachine::Trace::ResourceProxy do - include_context "default resource" + include_context 'default resource' subject { described_class.new(resource) } - it "duck-types all callback methods" do + it 'duck-types all callback methods' do Webmachine::Resource::Callbacks.instance_methods(false).each do |m| expect(subject).to respond_to(m) end end - it "logs invocations of callbacks" do + it 'logs invocations of callbacks' do subject.generate_etag - expect(response.trace).to eq([{:type => :attempt, :name => "(default)#generate_etag"}, - {:type => :result, :value => nil}]) - + expect(response.trace).to eq([{type: :attempt, name: '(default)#generate_etag'}, + {type: :result, value: nil}]) end - it "logs invocations of body-producing methods" do - expect(subject.content_types_provided).to eq([["text/html", :to_html]]) + it 'logs invocations of body-producing methods' do + expect(subject.content_types_provided).to eq([['text/html', :to_html]]) subject.to_html expect(response.trace[-2][:type]).to eq(:attempt) expect(response.trace[-2][:name]).to match(/to_html$/) - expect(response.trace[-2][:source]).to include("spec_helper.rb") if response.trace[-2][:source] - expect(response.trace[-1]).to eq({:type => :result, :value => "Hello, world!"}) + expect(response.trace[-2][:source]).to include('spec_helper.rb') if response.trace[-2][:source] + expect(response.trace[-1]).to eq({type: :result, value: 'Hello, world!'}) end - it "sets the trace id header when the request has finished processing" do + it 'sets the trace id header when the request has finished processing' do subject.finish_request - expect(response.headers["X-Webmachine-Trace-Id"]).to eq(subject.object_id.to_s) + expect(response.headers['X-Webmachine-Trace-Id']).to eq(subject.object_id.to_s) end end diff --git a/spec/webmachine/trace/trace_store_spec.rb b/spec/webmachine/trace/trace_store_spec.rb index 324d80fa..9b4692e3 100644 --- a/spec/webmachine/trace/trace_store_spec.rb +++ b/spec/webmachine/trace/trace_store_spec.rb @@ -1,29 +1,29 @@ require 'spec_helper' require 'fileutils' -shared_examples_for "trace storage" do +shared_examples_for 'trace storage' do it { is_expected.to respond_to(:[]=) } it { is_expected.to respond_to(:keys) } it { is_expected.to respond_to(:fetch) } - it "stores a trace" do - subject["foo"] = [:bar] - expect(subject.fetch("foo")).to eq([:bar]) + it 'stores a trace' do + subject['foo'] = [:bar] + expect(subject.fetch('foo')).to eq([:bar]) end - it "lists a stored trace in the keys" do - subject["foo"] = [:bar] - expect(subject.keys).to eq(["foo"]) + it 'lists a stored trace in the keys' do + subject['foo'] = [:bar] + expect(subject.keys).to eq(['foo']) end end describe Webmachine::Trace::PStoreTraceStore do - subject { described_class.new("./wmtrace") } - after { FileUtils.rm_rf("./wmtrace") } - it_behaves_like "trace storage" + subject { described_class.new('./wmtrace') } + after { FileUtils.rm_rf('./wmtrace') } + it_behaves_like 'trace storage' end -describe "Webmachine::Trace :memory Trace Store (Hash)" do - subject { Hash.new } - it_behaves_like "trace storage" +describe 'Webmachine::Trace :memory Trace Store (Hash)' do + subject { {} } + it_behaves_like 'trace storage' end diff --git a/spec/webmachine/trace_spec.rb b/spec/webmachine/trace_spec.rb index 346e8d27..d855a34d 100644 --- a/spec/webmachine/trace_spec.rb +++ b/spec/webmachine/trace_spec.rb @@ -3,13 +3,13 @@ describe Webmachine::Trace do subject { described_class } - context "determining whether the resource should be traced" do - include_context "default resource" - it "does not trace by default" do + context 'determining whether the resource should be traced' do + include_context 'default resource' + it 'does not trace by default' do expect(subject.trace?(resource)).to be(false) end - it "traces when the resource enables tracing" do + it 'traces when the resource enables tracing' do expect(resource).to receive(:trace?).and_return(true) expect(subject.trace?(resource)).to be(true) end diff --git a/webmachine.gemspec b/webmachine.gemspec index 0c048872..d134fa3c 100644 --- a/webmachine.gemspec +++ b/webmachine.gemspec @@ -1,34 +1,33 @@ -$:.push File.expand_path("../lib", __FILE__) +$:.push File.expand_path('../lib', __FILE__) require 'webmachine/version' Gem::Specification.new do |gem| - gem.name = "webmachine" + gem.name = 'webmachine' gem.version = Webmachine::VERSION - gem.summary = %Q{webmachine is a toolkit for building HTTP applications,} + gem.summary = %(webmachine is a toolkit for building HTTP applications,) gem.description = <<-DESC.gsub(/\s+/, ' ') webmachine is a toolkit for building HTTP applications in a declarative fashion, that avoids the confusion of going through a CGI-style interface like Rack. It is strongly influenced by the original Erlang project of the same name and shares its opinionated nature about HTTP. DESC - gem.homepage = "https://github.com/webmachine/webmachine-ruby" - gem.authors = ["Sean Cribbs"] - gem.email = ["sean@basho.com"] - gem.license = "Apache-2.0" + gem.homepage = 'https://github.com/webmachine/webmachine-ruby' + gem.authors = ['Sean Cribbs'] + gem.email = ['sean@basho.com'] + gem.license = 'Apache-2.0' - gem.metadata["bug_tracker_uri"] = "#{gem.homepage}/issues" - gem.metadata["changelog_uri"] = "#{gem.homepage}/blob/HEAD/CHANGELOG.md" - gem.metadata["documentation_uri"] = "https://www.rubydoc.info/gems/webmachine/#{gem.version}" - gem.metadata["homepage_uri"] = gem.homepage - gem.metadata["source_code_uri"] = gem.homepage - gem.metadata["wiki_uri"] = "#{gem.homepage}/wiki" + gem.metadata['bug_tracker_uri'] = "#{gem.homepage}/issues" + gem.metadata['changelog_uri'] = "#{gem.homepage}/blob/HEAD/CHANGELOG.md" + gem.metadata['documentation_uri'] = "https://www.rubydoc.info/gems/webmachine/#{gem.version}" + gem.metadata['homepage_uri'] = gem.homepage + gem.metadata['source_code_uri'] = gem.homepage + gem.metadata['wiki_uri'] = "#{gem.homepage}/wiki" - gem.add_runtime_dependency(%q, [">= 0.4.0"]) - gem.add_runtime_dependency(%q) - gem.add_runtime_dependency(%q, [">= 1.0.2", "< 2.0"]) + gem.add_runtime_dependency('i18n', ['>= 0.4.0']) + gem.add_runtime_dependency('multi_json') + gem.add_runtime_dependency('as-notifications', ['>= 1.0.2', '< 2.0']) - gem.add_development_dependency(%q, ["~> 1.7.0"]) - - ignores = File.read(".gitignore").split(/\r?\n/).reject{ |f| f =~ /^(#.+|\s*)$/ }.map {|f| Dir[f] }.flatten - gem.files = (Dir['**/*','.gitignore'] - ignores).reject {|f| !File.file?(f) } - gem.test_files = (Dir['spec/**/*','features/**/*','.gitignore'] - ignores).reject {|f| !File.file?(f) } + gem.add_development_dependency('webrick', ['~> 1.7.0']) + gem.add_development_dependency('standard', ['~> 1.21']) + ignores = File.read('.gitignore').split(/\r?\n/).reject { |f| f =~ /^(#.+|\s*)$/ }.map { |f| Dir[f] }.flatten + gem.files = (Dir['**/*', '.gitignore'] - ignores).reject { |f| !File.file?(f) } end From 86d0f0cb94655bae2a32eb588fae0d155eb2dd00 Mon Sep 17 00:00:00 2001 From: 0x1eef <0x1eef@protonmail.com> Date: Sat, 14 Jan 2023 09:14:45 -0300 Subject: [PATCH 095/122] Apply rubocop rules (auto and manual fixes) --- lib/webmachine/adapter.rb | 3 --- lib/webmachine/adapters/lazy_request_body.rb | 2 +- lib/webmachine/adapters/rack_mapped.rb | 1 - lib/webmachine/application.rb | 4 ++-- lib/webmachine/chunked_body.rb | 2 +- lib/webmachine/decision/falsey.rb | 1 - lib/webmachine/dispatcher.rb | 5 +++-- lib/webmachine/dispatcher/route.rb | 15 +++++++++++++++ lib/webmachine/etags.rb | 3 ++- lib/webmachine/header_negotiation.rb | 11 +++++------ lib/webmachine/headers.rb | 10 +++++----- lib/webmachine/rescueable_exception.rb | 6 +++--- lib/webmachine/resource.rb | 2 +- lib/webmachine/resource/callbacks.rb | 6 +++--- lib/webmachine/spec/adapter_lint.rb | 14 ++++++-------- lib/webmachine/streaming/encoder.rb | 1 + lib/webmachine/trace.rb | 13 +++++++------ lib/webmachine/trace/resource_proxy.rb | 17 +++++++++-------- lib/webmachine/translation.rb | 4 ++-- spec/webmachine/adapter_spec.rb | 7 +++---- spec/webmachine/decision/falsey_spec.rb | 8 ++++---- 21 files changed, 73 insertions(+), 62 deletions(-) diff --git a/lib/webmachine/adapter.rb b/lib/webmachine/adapter.rb index c11aad52..2896a8cc 100644 --- a/lib/webmachine/adapter.rb +++ b/lib/webmachine/adapter.rb @@ -1,10 +1,8 @@ module Webmachine - # The abstract class for definining a Webmachine adapter. # # @abstract Subclass and override {#run} to implement a custom adapter. class Adapter - # @return [Webmachine::Application] returns the application attr_reader :application @@ -25,6 +23,5 @@ def self.run(application) def run raise NotImplementedError end - end end diff --git a/lib/webmachine/adapters/lazy_request_body.rb b/lib/webmachine/adapters/lazy_request_body.rb index 694f56c5..8fd2c069 100644 --- a/lib/webmachine/adapters/lazy_request_body.rb +++ b/lib/webmachine/adapters/lazy_request_body.rb @@ -24,7 +24,7 @@ def empty? # @yield [chunk] # @yieldparam [String] chunk a chunk of the request body def each - @request.body {|chunk| yield chunk } + @request.body { |chunk| yield chunk } end end # class RequestBody end # module Adapters diff --git a/lib/webmachine/adapters/rack_mapped.rb b/lib/webmachine/adapters/rack_mapped.rb index c924c867..dc87a732 100644 --- a/lib/webmachine/adapters/rack_mapped.rb +++ b/lib/webmachine/adapters/rack_mapped.rb @@ -21,7 +21,6 @@ module Adapters # end # end class RackMapped < Rack - protected def routing_tokens(rack_req) diff --git a/lib/webmachine/application.rb b/lib/webmachine/application.rb index 9cc3a5b7..314f2e8b 100644 --- a/lib/webmachine/application.rb +++ b/lib/webmachine/application.rb @@ -43,7 +43,7 @@ class Application # the Application instance being initialized def initialize(configuration = Configuration.default, dispatcher = Dispatcher.new) @configuration = configuration - @dispatcher = dispatcher + @dispatcher = dispatcher yield self if block_given? end @@ -73,7 +73,7 @@ def adapter_class # # @see Webmachine::Dispatcher#add_route def routes(&block) - if block_given? + if block dispatcher.instance_eval(&block) self else diff --git a/lib/webmachine/chunked_body.rb b/lib/webmachine/chunked_body.rb index ac65a26c..8942ac7f 100644 --- a/lib/webmachine/chunked_body.rb +++ b/lib/webmachine/chunked_body.rb @@ -29,7 +29,7 @@ def initialize(body) # parameter. # Returns an {Enumerator} if no block is given. def each - return self.to_enum unless block_given? + return to_enum unless block_given? @body.each do |chunk| size = chunk.bytesize diff --git a/lib/webmachine/decision/falsey.rb b/lib/webmachine/decision/falsey.rb index 30a15f56..06d5fe75 100644 --- a/lib/webmachine/decision/falsey.rb +++ b/lib/webmachine/decision/falsey.rb @@ -7,4 +7,3 @@ def Falsey.===(other) end end end - diff --git a/lib/webmachine/dispatcher.rb b/lib/webmachine/dispatcher.rb index 273cf85d..c405369e 100644 --- a/lib/webmachine/dispatcher.rb +++ b/lib/webmachine/dispatcher.rb @@ -33,7 +33,7 @@ def add_route(*args, &block) @routes << route route end - alias :add :add_route + alias_method :add, :add_route # Dispatches a request to the appropriate {Resource} in the # dispatch list. If a matching resource is not found, a "404 Not @@ -72,10 +72,11 @@ def find_resource(request, response) # Find the first route that matches an incoming request # @param [Request] request the request to match def find_route(request) - @routes.find {|r| r.match?(request) } + @routes.find { |r| r.match?(request) } end private + def prepare_resource(route, request, response) route.apply(request) @resource_creator.call(route, request, response) diff --git a/lib/webmachine/dispatcher/route.rb b/lib/webmachine/dispatcher/route.rb index b7a27ce3..e288bfed 100644 --- a/lib/webmachine/dispatcher/route.rb +++ b/lib/webmachine/dispatcher/route.rb @@ -43,6 +43,21 @@ def self.rfc3986_percent_decode(value) result end + # Decode a string using the scheme described in RFC 3986 2.1. Percent-Encoding (https://www.ietf.org/rfc/rfc3986.txt) + def self.rfc3986_percent_decode(value) + s = StringScanner.new(value) + result = "" + until s.eos? + encoded_val = s.scan(/%([0-9a-fA-F]){2}/) + result << if encoded_val.nil? + s.getch + else + [encoded_val[1..-1]].pack("H*") + end + end + result + end + # Creates a new Route that will associate a pattern to a # {Resource}. # diff --git a/lib/webmachine/etags.rb b/lib/webmachine/etags.rb index b5ae2b72..ed438420 100644 --- a/lib/webmachine/etags.rb +++ b/lib/webmachine/etags.rb @@ -10,7 +10,7 @@ class ETag def self.new(etag) return etag if ETag === etag - klass = etag =~ WEAK_ETAG ? WeakETag : self + klass = WEAK_ETAG.match?(etag) ? WeakETag : self klass.send(:allocate).tap do |obj| obj.send(:initialize, etag) end @@ -53,6 +53,7 @@ def to_s end private + def unquote(str) if str =~ WEAK_ETAG unescape_quotes $1 diff --git a/lib/webmachine/header_negotiation.rb b/lib/webmachine/header_negotiation.rb index 2ad6a118..6243e199 100644 --- a/lib/webmachine/header_negotiation.rb +++ b/lib/webmachine/header_negotiation.rb @@ -3,19 +3,18 @@ module Webmachine module HeaderNegotiation def ensure_date_header(res) - if (200..499).include?(res.code) + if (200..499).cover?(res.code) res.headers[DATE] ||= Time.now.httpdate end end def ensure_content_length(res) body = res.body - case - when res.headers[TRANSFER_ENCODING] - return - when [204, 205, 304].include?(res.code) + if res.headers[TRANSFER_ENCODING] + nil + elsif [204, 205, 304].include?(res.code) res.headers.delete CONTENT_LENGTH - when body != nil + elsif !body.nil? res.headers[CONTENT_LENGTH] = body.respond_to?(:bytesize) ? body.bytesize.to_s : body.length.to_s else res.headers[CONTENT_LENGTH] = '0' diff --git a/lib/webmachine/headers.rb b/lib/webmachine/headers.rb index 44954166..747afe21 100644 --- a/lib/webmachine/headers.rb +++ b/lib/webmachine/headers.rb @@ -10,11 +10,10 @@ class Headers < ::Hash # @param [Hash] env a hash of CGI-style env/headers # @return [Webmachine::Headers] def self.from_cgi(env) - env.inject(new) do |h,(k,v)| + env.each_with_object(new) do |(k, v), h| if k =~ CGI_HTTP_MATCH || k =~ CONTENT_TYPE_LENGTH_MATCH h[$1.tr(UNDERSCORE, DASH)] = v end - h end end @@ -33,7 +32,7 @@ def self.from_cgi(env) # @param [Object] # @return [Webmachine::Headers] def self.[](*args) - super(super(*args).map {|k, v| [k.to_s.downcase, v]}) + super(super(*args).map { |k, v| [k.to_s.downcase, v] }) end # Fetch a header @@ -42,7 +41,7 @@ def [](key) end # Set a header - def []=(key,value) + def []=(key, value) super transform_key(key), value end @@ -76,10 +75,11 @@ def delete(key) # Select matching headers def grep(pattern) - self.class[select { |k,_| pattern === k }] + self.class[select { |k, _| pattern === k }] end private + def transform_key(key) key.to_s.downcase end diff --git a/lib/webmachine/rescueable_exception.rb b/lib/webmachine/rescueable_exception.rb index 297ac7d6..0e7d9907 100644 --- a/lib/webmachine/rescueable_exception.rb +++ b/lib/webmachine/rescueable_exception.rb @@ -2,7 +2,7 @@ module Webmachine::RescuableException require_relative 'errors' require 'set' - UNRESCUABLE_DEFAULTS = [ + UNRESCUABLE_DEFAULTS = [ Webmachine::MalformedRequest, NoMemoryError, SystemExit, SignalException ].freeze @@ -45,7 +45,7 @@ def self.UNRESCUABLEs # @param (see #remove) # def self.add(*exceptions) - exceptions.each{|e| UNRESCUABLE.delete(e)} + exceptions.each { |e| UNRESCUABLE.delete(e) } end # @@ -57,6 +57,6 @@ def self.add(*exceptions) # A subclass of Exception. # def self.remove(*exceptions) - exceptions.each{|e| UNRESCUABLE.add(e)} + exceptions.each { |e| UNRESCUABLE.add(e) } end end diff --git a/lib/webmachine/resource.rb b/lib/webmachine/resource.rb index 1f4b3cb1..c8fdbd22 100644 --- a/lib/webmachine/resource.rb +++ b/lib/webmachine/resource.rb @@ -59,11 +59,11 @@ def self.run end private + # When no specific charsets are provided, this acts as an identity # on the response body. Probably deserves some refactoring. def charset_nop(x) x end - end # class Resource end # module Webmachine diff --git a/lib/webmachine/resource/callbacks.rb b/lib/webmachine/resource/callbacks.rb index cf87eb4d..6780de42 100644 --- a/lib/webmachine/resource/callbacks.rb +++ b/lib/webmachine/resource/callbacks.rb @@ -265,7 +265,7 @@ def language_chosen(lang) # @api callback # @see Encodings def encodings_provided - {IDENTITY => :encode_identity } + {IDENTITY => :encode_identity} end # If this method is implemented, it should return a list of @@ -360,7 +360,8 @@ def generate_etag # constructed and sent. The return value is ignored, so any effect # of this method must be by modifying the response. # @api callback - def finish_request; end + def finish_request + end # # This method is called when an error is raised within a subclass of @@ -389,7 +390,6 @@ def handle_exception(e) def validate_content_checksum nil end - end # module Callbacks end # class Resource end # module Webmachine diff --git a/lib/webmachine/spec/adapter_lint.rb b/lib/webmachine/spec/adapter_lint.rb index 8a32b809..2cbed74f 100644 --- a/lib/webmachine/spec/adapter_lint.rb +++ b/lib/webmachine/spec/adapter_lint.rb @@ -12,7 +12,7 @@ def find_free_port temp_server = TCPServer.new(ADDRESS, 0) port = temp_server.addr[1] temp_server.close # only frees Ruby resource, socket is in TIME_WAIT at OS level - # so we can't have our adapter use it too quickly + # so we can't have our adapter use it too quickly sleep(0.1) # 'Wait' for temp_server to *really* close, not just TIME_WAIT port @@ -23,7 +23,7 @@ def create_test_application(port) application.dispatcher.add_route ['test'], Test::Resource application.configure do |c| - c.ip = ADDRESS + c.ip = ADDRESS c.port = port end end @@ -37,12 +37,10 @@ def run_application(adapter_class, application) def wait_until_server_responds_to(client) Timeout.timeout(5, TestApplicationNotResponsive) do - begin - client.start - rescue Errno::ECONNREFUSED - sleep(0.01) - retry - end + client.start + rescue Errno::ECONNREFUSED + sleep(0.01) + retry end end diff --git a/lib/webmachine/streaming/encoder.rb b/lib/webmachine/streaming/encoder.rb index da7f139f..90322ede 100644 --- a/lib/webmachine/streaming/encoder.rb +++ b/lib/webmachine/streaming/encoder.rb @@ -12,6 +12,7 @@ def initialize(resource, encoder, charsetter, body) end protected + # @return [true, false] whether the stream will be modified by # the encoder and/or charsetter. Only returns true if using the # built-in "encode_identity" and "charset_nop" methods. diff --git a/lib/webmachine/trace.rb b/lib/webmachine/trace.rb index f6aa142b..6481db9b 100644 --- a/lib/webmachine/trace.rb +++ b/lib/webmachine/trace.rb @@ -9,10 +9,11 @@ module Webmachine # Contains means to enable the Webmachine visual debugger. module Trace module_function + # Classes that implement storage for visual debugger traces. TRACE_STORES = { - :memory => Hash, - :pstore => PStoreTraceStore + memory: Hash, + pstore: PStoreTraceStore } DEFAULT_TRACE_SUBSCRIBER = Webmachine::Events.subscribe( @@ -71,10 +72,10 @@ def trace_store=(*args) def trace_store @trace_store ||= begin - opts = Array(@trace_store_opts).dup - type = opts.shift - TRACE_STORES[type].new(*opts) - end + opts = Array(@trace_store_opts).dup + type = opts.shift + TRACE_STORES[type].new(*opts) + end end private :trace_store diff --git a/lib/webmachine/trace/resource_proxy.rb b/lib/webmachine/trace/resource_proxy.rb index bc9b02bf..bd6e7de4 100644 --- a/lib/webmachine/trace/resource_proxy.rb +++ b/lib/webmachine/trace/resource_proxy.rb @@ -14,7 +14,7 @@ class ResourceProxy # including body-producing or accepting methods, encoders and # charsetters. CALLBACK_REFERRERS = [:content_types_accepted, :content_types_provided, - :encodings_provided, :charsets_provided] + :encodings_provided, :charsets_provided] # Creates a {ResourceProxy} that decorates the passed # {Webmachine::Resource} such that callbacks invoked by the @@ -46,6 +46,7 @@ def finish_request(*args) end private + # Proxy a given callback to the inner resource, decorating with traces def proxy_callback(callback, *args) # Log inputs and attempt @@ -56,14 +57,14 @@ def proxy_callback(callback, *args) resource.response.trace << result(_result) _result rescue => exc - exc.backtrace.reject! {|s| s.include?(__FILE__) } + exc.backtrace.reject! { |s| s.include?(__FILE__) } resource.response.trace << exception(exc) raise end # Creates a log entry for the entry to a resource callback. def attempt(callback, args) - log = {:type => :attempt} + log = {type: :attempt} method = resource.method(callback) if method.owner == ::Webmachine::Resource::Callbacks log[:name] = "(default)##{method.name}" @@ -79,15 +80,15 @@ def attempt(callback, args) # Creates a log entry for the result of a resource callback def result(result) - {:type => :result, :value => result} + {type: :result, value: result} end # Creates a log entry for an exception that was raised from a callback def exception(e) - {:type => :exception, - :class => e.class.name, - :backtrace => e.backtrace, - :message => e.message } + {type: :exception, + class: e.class.name, + backtrace: e.backtrace, + message: e.message} end # Adds proxy methods for callbacks that are dynamically referred to. diff --git a/lib/webmachine/translation.rb b/lib/webmachine/translation.rb index 2c437ba7..f55ed682 100644 --- a/lib/webmachine/translation.rb +++ b/lib/webmachine/translation.rb @@ -12,8 +12,8 @@ module Translation # @param [Hash] options options to pass to I18n, including # variables to interpolate. # @return [String] the interpolated string - def t(key, options={}) - ::I18n.t(key, **options.merge(:scope => :webmachine)) + def t(key, options = {}) + ::I18n.t(key, **options.merge(scope: :webmachine)) end end end diff --git a/spec/webmachine/adapter_spec.rb b/spec/webmachine/adapter_spec.rb index b366d3cc..e949919b 100644 --- a/spec/webmachine/adapter_spec.rb +++ b/spec/webmachine/adapter_spec.rb @@ -20,9 +20,9 @@ it 'creates a new adapter and runs it' do adapter = double(described_class) - expect(described_class).to receive(:new). - with(application). - and_return(adapter) + expect(described_class).to receive(:new) + .with(application) + .and_return(adapter) expect(adapter).to receive(:run) @@ -35,5 +35,4 @@ expect { adapter.run }.to raise_exception(NotImplementedError) end end - end diff --git a/spec/webmachine/decision/falsey_spec.rb b/spec/webmachine/decision/falsey_spec.rb index 2a8bd210..52a4e337 100644 --- a/spec/webmachine/decision/falsey_spec.rb +++ b/spec/webmachine/decision/falsey_spec.rb @@ -1,8 +1,8 @@ require 'spec_helper' describe Webmachine::Decision::Falsey do - specify { expect(described_class.=== false).to be(true) } - specify { expect(described_class.=== nil).to be(true) } - specify { expect(described_class.=== true).to be(false) } - specify { expect(described_class.=== []).to be(false) } + specify { expect(described_class === false).to be(true) } + specify { expect(described_class === nil).to be(true) } + specify { expect(described_class === true).to be(false) } + specify { expect(described_class === []).to be(false) } end From df0f947ecf65b8b52aa07918986d9e204fa50c13 Mon Sep 17 00:00:00 2001 From: 0x1eef <0x1eef@protonmail.com> Date: Sat, 14 Jan 2023 10:05:39 -0300 Subject: [PATCH 096/122] Add linter to CI --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d7d31f00..4e7ef897 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,4 +21,5 @@ jobs: with: ruby-version: ${{ matrix.ruby_version }} bundler-cache: true + - run: "bundle exec rubocop lib/ spec/" - run: "bundle exec rspec spec/ -b" From 20a7f15178329f7136920764909570294efbe8fa Mon Sep 17 00:00:00 2001 From: 0x1eef <0x1eef@protonmail.com> Date: Tue, 17 Jan 2023 14:25:50 -0300 Subject: [PATCH 097/122] Drop 2.3, 2.4, and 2.5 from test build These version of Ruby have reached EOL. --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4e7ef897..8019f413 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,7 +9,7 @@ jobs: strategy: fail-fast: false matrix: - ruby_version: ["2.3", "2.4", "2.5", "2.6", "2.7", "3.0", "3.1", "3.2"] + ruby_version: ["2.6", "2.7", "3.0", "3.1", "3.2"] experimental: [false] include: - ruby_version: "ruby-head" From 3f2e2aa30c69d7dca0d7dacdce5d319b8610b610 Mon Sep 17 00:00:00 2001 From: 0x1eef <0x1eef@protonmail.com> Date: Tue, 17 Jan 2023 14:44:06 -0300 Subject: [PATCH 098/122] Remove duplicate 'rfc3986_percent_decode' method --- lib/webmachine/dispatcher/route.rb | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/lib/webmachine/dispatcher/route.rb b/lib/webmachine/dispatcher/route.rb index e288bfed..b7a27ce3 100644 --- a/lib/webmachine/dispatcher/route.rb +++ b/lib/webmachine/dispatcher/route.rb @@ -43,21 +43,6 @@ def self.rfc3986_percent_decode(value) result end - # Decode a string using the scheme described in RFC 3986 2.1. Percent-Encoding (https://www.ietf.org/rfc/rfc3986.txt) - def self.rfc3986_percent_decode(value) - s = StringScanner.new(value) - result = "" - until s.eos? - encoded_val = s.scan(/%([0-9a-fA-F]){2}/) - result << if encoded_val.nil? - s.getch - else - [encoded_val[1..-1]].pack("H*") - end - end - result - end - # Creates a new Route that will associate a pattern to a # {Resource}. # From faba784105377453e32e9fd6c0a113555c95147d Mon Sep 17 00:00:00 2001 From: 0x1eef <0x1eef@protonmail.com> Date: Tue, 17 Jan 2023 21:38:18 -0300 Subject: [PATCH 099/122] gemspec: require ruby 2.6 or greater. --- webmachine.gemspec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/webmachine.gemspec b/webmachine.gemspec index d134fa3c..cf288866 100644 --- a/webmachine.gemspec +++ b/webmachine.gemspec @@ -22,6 +22,8 @@ Gem::Specification.new do |gem| gem.metadata['source_code_uri'] = gem.homepage gem.metadata['wiki_uri'] = "#{gem.homepage}/wiki" + gem.required_ruby_version = '>= 2.6.0' + gem.add_runtime_dependency('i18n', ['>= 0.4.0']) gem.add_runtime_dependency('multi_json') gem.add_runtime_dependency('as-notifications', ['>= 1.0.2', '< 2.0']) From 48125b18b1930935801a0df81c9eb075e5f076ec Mon Sep 17 00:00:00 2001 From: 0x1eef <0x1eef@protonmail.com> Date: Thu, 19 Jan 2023 14:22:57 -0300 Subject: [PATCH 100/122] Remove the 'guard' dependency --- Gemfile | 13 ------------- Guardfile | 11 ----------- 2 files changed, 24 deletions(-) delete mode 100644 Guardfile diff --git a/Gemfile b/Gemfile index 013e857b..e1702ca0 100644 --- a/Gemfile +++ b/Gemfile @@ -15,19 +15,6 @@ group :test do gem 'websocket_parser', '~>1.0' end -group :guard do - gem 'guard-rspec', '~> 4.7' - case RbConfig::CONFIG['host_os'] - when /darwin/ - gem 'rb-fsevent', '~> 0.10' - # gem 'growl_notify' - gem 'growl', '~> 1.0' - when /linux/ - gem 'rb-inotify' - gem 'libnotify' - end -end - group :docs do platform :mri_19, :mri_20 do gem 'redcarpet', '~> 3.4' diff --git a/Guardfile b/Guardfile deleted file mode 100644 index 1d7af7b7..00000000 --- a/Guardfile +++ /dev/null @@ -1,11 +0,0 @@ -gemset = ENV['RVM_GEMSET'] || 'webmachine' -gemset = "@#{gemset}" unless gemset.to_s == '' - -rvms = %W[1.8.7 1.9.2 1.9.3 jruby rbx].map { |v| "#{v}#{gemset}" } - -guard 'rspec', cli: '--color --profile', growl: true, rvm: rvms do - watch(%r{^lib/webmachine/locale/.+$}) { 'spec' } - watch(%r{^spec/.+_spec\.rb$}) - watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } - watch('spec/spec_helper.rb') { 'spec' } -end From 126c0bcfde7fa66e975a9479610d08423200be94 Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Sun, 29 Jan 2023 10:51:11 +1100 Subject: [PATCH 101/122] Fix flaky test: ensure the json gem is loaded It seems there are some tests that result in the json gem being loaded. If the spec/webmachine/adapters/rack_spec.rb:57 test happens to run before these tests, the json gem will not be loaded and the test fails. This is reproducible with the following command. rspec --seed 34885 --- spec/webmachine/adapters/rack_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/webmachine/adapters/rack_spec.rb b/spec/webmachine/adapters/rack_spec.rb index 837a1e03..e76f3ca0 100644 --- a/spec/webmachine/adapters/rack_spec.rb +++ b/spec/webmachine/adapters/rack_spec.rb @@ -3,6 +3,7 @@ require 'spec_helper' require 'webmachine/spec/adapter_lint' require 'rack/test' +require 'json' describe Webmachine::Adapters::Rack do it_should_behave_like :adapter_lint do From 1fe507da1c31c805fe392187860b88458dd35ec8 Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Thu, 2 Feb 2023 23:18:54 +1100 Subject: [PATCH 102/122] Reduce http-headers-status-v3.png size Running the image through ImageOptim reduces the size from 403K to 248K! --- .../trace/static/http-headers-status-v3.png | Bin 412634 -> 254419 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/lib/webmachine/trace/static/http-headers-status-v3.png b/lib/webmachine/trace/static/http-headers-status-v3.png index 231316066863c9f786ab5f251c37cd0a17eb3940..18e754f1b97ab297df8f4899bd2ec6c20689c1b3 100644 GIT binary patch literal 254419 zcmeFZXIxWF*Efp20!k4=Riq;&^bSfV0VJV!2^|52(5sE!Yv>9jfCxyJt^x@i=^do^ z4xz&vulqvrexKj@aL$+W;h8Vl*_l1FW|jY}wPx)EJXMy%ze#Zu4-XGtL0%eyhj;r4 z9^Q5T>lbl%W_DC=5k?qwEX3?{GBU5^eb~K$~qzi5;mpu-6OUXG#E1jpGmfflbYu9k6S@-}^=ZeK4eyT@AzlLS(e5Z`Px*@0umPgo-t-(| zC+0oG`!(0C0xNpqmcfHi*K$3y`Gp)%(X3i1ZI021RVlMBuxz_1x;ycd%6F=+uaJ^Y z)iHZ3sx#F5=RjmkYh^O#G+29bf4|(xeMHPR-d-QtbNbq=Y^#UV<$&f7agj$^9*}DH zg+13VCel`mglGgr!eD>v9T4^C;jP3v;Q||74TL(MHc}kjBO#;I@4SF)0rEtPHGN*H z;JvQ zhIf97tk3;B{~ef4?2NEN>!e6Mf|Z&G6OK8$m?DJkIou?N9x#$P2G6$MjZNi2tL0N9 zNN~k59k?2U2fsS%7xn1zen{J3P4^zCyfwfd$$b0kL`EwqX}w2lYwLr8(D?ZHi>79_ ztzWFoFisSH4$f(T<*#ASHf(0Miv?8Wgvh9pPgNdX5iOn~J$2*R@wuyF{{aRT4L7{X zqk0(>2vjh9dr)k-smRtC-7>RUbGTZHE$!=z?JL!=vN2ncwNAB|^xFusFeARC0J09U z$S6m;CI}2|T_O}+Unv_u!4BJHUU<)arqBN@_C9)hQd`fTJZi5I{KzDavi_Y-GbwDc zWr5@wb$g#byrt6{T94Sf&~_}d&)i_Y_+SwpAzd)nWekSg4z(MBe)>)t?7|+p)A)gI zKk~8TS9#^{`d`S2^S@{2&Z|T)9wZ+uRd9&;PZnD$1HETlCf<>ySa^yi-FCZV>)lA^ zzxY9#IU$gqI{+-M&paDccPy3uMhYfXHzk{HcvUXY^U}NL526|wjTbBg@7_dT)EQXA zcNt0Oo+ug?)yNs{niBMA^a>w(JpAfX-?3~FxMZblIsL?s+RuWMeJetJ&@XW&X8(JUk9wJys?pO1kvTtzP+wu+0XQZefYGre*~@OhHMxw6tX2mLOBx)6=8pv~RlReI(wH$oz_4 zNlPc4yqkwpv@Tz1@b6{f-AC8&CtA|LCNDne=0Vpxk13FKbSBM&02S`0rZaj(8QlOr z1nRvch_bgwVh}wgm5j9y^wbo@NK;GUilpSQW)jE;X@73;!kEdp(X$uuuf|KR+XZsg z*48dDO9TFkr#DA|Zn${SsHsQNPH4_YMdQ7|@${(2d!t;G024NvVmq#DL z@sc>6ytyx$3N|SL3IjIXr4`bre-}9a)=@u`GdZ6+gK35-vR!*awv*oDIvpp{9~krb z=ESYT%U)7@Tu7CL%Osg?lvB2(X*rc_{iz|xQO_1B4^81Kz9noLpRy7@TXd$0;D~-h zDE_|eoxzQ=;o}A}LtX&^=(T2kRX^9Q+3M}hpzN{fukygCj{2gFr*v6zyn)xsc{4}N zi`-769y6w+BUg+-x;$-F9{Za+OZ}(EyW`$R8`nIcm{4kwmy?%mehyjZBbj?+G!4sL z=gfjCuK^kVX2M>oWN?7>99RsUu_SCG8!;uM&w5vCVxTREaXZt${6&R~vGT3>00-h) zP)2kZ{CnVoC=t*z3QNbG6w+@LCt+?mN3;#B+qY=nM;oOVjA&PJk!Y!EDnqUXTL_Np z$}wL^m%kNL9OyB0I9Uki#&z>Vh@Y(V%eBmkkvzVB@1i2w%xe}r*b$4DM;pZfzLgx`$gLd9c9+W z3<6T2_Rr2_UsY)qDKNEKMG6#xM6Vl4UQ_4(1dr-I?|SjlPxnKhex&gwg;+H@e5!<} z{w=nmg7u^L&H&*Iwe@FfAg98zb_4nF_0zU%O*N_Yi=MNt(5dl+-SN$@24e2Aa&k*L zx%!nFjKoaJJ+-1vq-JILYr1`cMyByj+J+z6jt=JD$xB_M=JaSah<1|h z7hN~R_lMuN0gRNCl$QF!-X~S7gbD(XwXy0Mx4{$aH$Pgne)SpBIot7Sc6Z&rQ&Mir zN#iKvy#7ZF9>*B>8I$CZxrx-{V_NUEE@Y4}^L(Yl96YyJXXRm-=;Yj7rZx2G)1S-B z%RlEod+gYk2c0(&AM$P`-zW6h4--p+MR%@krAFSO*Mc1#Wy**XHSbS#Xm|+}hOkuk z=6X16vt(5!Wdzx(c*&o>T79(tN|7Sl!Gq-4QL6NAz}NR*3l}#x7YjeN#j8kc6{j)B z#>SqUoCr^4WMphF_JUS7y&4aflnga{)mNIw%N^%pTXO-~+C$UZ^ekEx2943=)hu39 zv=~HW7xB33DYa`40tm~~D^Ig_+?Z^r^CJ`x5Lg?pHN4llF!V{U9FiBk<6uwrm!bn1 zizT!dkYVZ<%F5x2&0pcWsgjQGx4C+GH8}MT0@9dKD3rLkI6FJLaJuJCucn5EhW#3% z0A@w;aVv0Z=w^HuAAqHQx7jjyh>a;A?M4(P5rMdT<;w9k=k=776r8ux7!ZD}yT`?`SgqNO9 zp>m3->;C49;cb;vanGGa_4p)VN2{Z~4g35`Kg>bnshV2cO6zceshl!;7H)$=f7Y~x zPNFH%2(;4n$`Eo%MF1o#EzNAhsGMYhh>MAFb#)Wln1&_aKd+#8IL_1~UK3DDkQ|t1 z=?jQt8z+c+R(N^M|9CLCK2T<7C?HUVp>cmiPe0un&r>+QQb#DU+?^Sgld}~5Kq@UQ zZM#|t2n5c~&c?F#ifoN#+kG5Pu3a*BpDErbXaaWLNDK}D4vJe)Qd1vye`G?2OgIoT zFfinCQp8Y&=@`i~De1uJ$l@cVRb# zJCYbO1%ny~YqJViF76Okz!$nwOF0z$6@A;=+a+u)6_u25XhX^Ud|iz8PY{HMhuhup zvih@BQiLXIdkj^h;a2aW-Z3ObH|d`X&+vY6?&nw- z(9>Zu%CsK_uJgr@@`$|MpKr*?X_~AjE9;xr=8I2hGQYZNOHSc|+ZXJrcVd$~cS0LPq` zLr4m*d3%y>FmT~k{5=ls`?r=eu$DWEy^*0^Yhmuw5pqXIN7KikI1XfHrn|c(gK?1mzVJyj&eA_dM8+D6tiD+YX=D zUg$OzbjLn#5^BI;T6X*hX}zXG1g3jh@@qW0K{M0gMK7BQie}r33ko!}KW0p1mzHYq z_azHC$T|%x)GHP$VMmwQA3aKOJsI4g>~FcWw*NnAuhZgub1xfmJj=R24^mEFS7hGd zwf^neCPbAaO5+ztw6q2y89>jUKff)d%|%8=#?&7d8!LV=pUzFY#8YZ%2(z77wW%yM zvuOdhC`XY)pICW3R}2OM8HJ`35E=8Xv{g$#=Z!2avmx0ByK53w(^+>P%E}iiUIaUh zE~EE?4a%M+dnJz?6Q9>&NlQyhp*>wV-jBQtr}>}xRAO#w{m)+aJU$Ft4jUq$Sy;$s zZhm`%*yLqmYwa<1*x f|eUD*g%I+#w91`o^EU8>M%r+8G5MtLWbbE>S}7yBi1%B zG4F|^A>Rc3{mRnSp~!N+hkT&Kq?G9QAz@0P0m@vg=!`X!$R(*h-@UzqFJCI)Q76b% zto`=l=+Zt}D&cj4@T8~{A!n7~8+ay!W^$)fbiWbuedFotq5Xd-PDn^_I#EdFq)*45FX3OLPong(* zr(hYdksx@31~7;=k>_6E9J@nFN=lq9G3_a2>e8rBibLWkCY7;i369^%k6#vb2L{Pk z?O(GAr|&jTy{4q47y8A|gs#OXsPcj-YEZJuxw{j4Go_%2AuZ_`L1((f*cI$xv4p#CCtT z_B19XUc&&2YWpE;8>~lJ&hMeGC0|dL`p%Prs?e-$Zt=a!rArd{;ScY-?2J0R&BF%> znN26!)wtflvsJROVLwO1NC7z%bIB((1gMlG*xArvYWlS~!PiPjrXPO zy%!0JgV#>g2N2_SZq^t@j@7{;^B)Oc(bf2r#{9Rbcz;aCvPe90+3$ujuE+sZ4P0kp zlBqA@!GDVv4>W`KS*;yG9+k#i?Y47ZQto}6a&vwtO9rH_%2T3pQ( z+10_o!;7=5celuJuHLoFm-h}1uxsPvPXneG769)F1{~gNM}2UeEjN#L;>JM?&V>mK z4CJiY``+8@I8b>gsV(+yc z8l}8Re-jfEv#I;&(WB+c;acEkNY8f9!EA-J%_L8UM0#;5&Y71G5ZE<5J%~$9P1VWe z=i|eHlbMCZyslj}DGiOSnVIb0`ZVH4LX8K9NQ3|bQmWlJu)4(}-kP4!73}D+gwFcL z*T{@#!NX|8qCEV@yqzWKxbRy(~llRjiwQc+)ZA=^b0~$+_4Wr| z_?k>tIV`$HXlrXrKtQm%x>}0>`7R8VSXYd1)-ETr`z{UHDIjTuICcmF0c%+14t>Sjg_npVBLu1?BMC-5%z&=clV zsV}CYqEg+;QYJPd^qLZoo?lQG7|a;Ng5Z7NB8C<)i* z>r%D+aKvD47W4WUwvlCvL^vNkj> zniUBhPmgT41naSY=HprYtX}*~$*iBcv6M7+74BVoBu}N7%xHJ}^IM<Cr$EXsvv=V8ysyhtUWW78BaU!aXW=T z;mdHF_CPOdfsFL|77YyWZ!FK}vRM zMKxL>lN;r6l>@@`TFOMh1#JU<^lV%MEuE>yr*?o83U&lQQ&d#y>Aji}i*~IW$xVRu!QFV~MFSX^GO>NF$hFbn$9dYo^WhGFXkrO)%{UI=o+0*fY7jvU>s9XW4E zS zfOItQ@wV(;rWL13@*U|swKuv6g%odkU5Gq9kbubt5d+2aobb<6u1v5dR^$N@+0Q0Z1@4rK`iTF4>m9)o0^Q z6G_XFq}f$W_e-PJC-kNM{*3~Gf9!x6_5`+#3obqO)+fRwPQJQIMPj=%Rj$K7@(Q=$ zZVb>6g>5d_pPa_1&RB2wvfP)zwB$~J?WGIy0ZdPry?zWoObcE(#Hj|S6eqJ{!`PEz zf->R&e}9kjK*kI^sMVwcPcUXYc%l<0nY(xQhji+;J+SulLvbX z2s6_T@K~l`P%J%db?g0HtREl_gIXjbJ|@yJzje&2_KL7}mnA>9qB6wdi z9u)#;necz8Kc|Osc|}K)`$3h+#d-{+aEgbM(D}yAXgm0rm{>%SM4D$nwfH{X#U5on zJrWqRQRKaV*1Zb7d_H5o4jiR}7jG0rB>MSOE2Z34`{2jllnV+DxWmfp9UQYDdpk}O z{|aGJVA6L>8UD!!J|TP%F{gP>nR58+#rfreBF`j`nWyO*>Q8~qi-KFHuM&%`E)&(@ zakv3249F(yvL9@be=-QGZsO zPx&l8w{7-#y(6KXrWJP`G_0?Hzg^$!l(-;9LQo`z2gy|K>_iLUF^MXtT;lXlc_CRR z$?tXRKQ9jzoWuk)k(ezJnHI4N1|xQ6a^ z*)aQbP%(N*~#fLw_6zn%p;<;c^gzz`DF6!&&pq z!;*`rnZmyM>&#~f5?}NonmT>Onq>7s;cj_u@WKnh=VilwetsAXCN3XSS62e)62H3a zlzN(HUg;@Blds}nBLNeZw_8|eOF5kgFBe4SzZ9f;{TJOhLymsqW_B!2&&%=E8FRn~ zB;lD3&SG#&kd@tmsJ6%__M6eXMv#XPW`8e{`g(mn1QI$8tY{Wg*qo^IGeJ!(TQywm zH;A{b&sag?!*139`rX5+Nk0*zCHOGd7_NCS7Sleemhs&JmQ-h1wh|s9`Sp%I zP)9V0U(CNT*92^V!1-pYYikc-L(lnf=|Jy&#gS2^4oq0L7E?9sGuvX)k^Uv2)YQz+ zH#%mjKG2$dAohX3KD{@08e8rpqHH-MS2a2@a&pHg*F3gH|1Z0V28Jv-+)rsVw%5GF z9eqb+F}6tHfqEKA1b#MMP&WT{6?O3dg(2Z=QWqu3UY;9L*>z%)=@))3*#U=m)S0P= zo~2|eVZBh~YKEyCvIcTxb-qBETUY2_N#*&l=yr`+Qf_P!za__K93F&)sTSNdfBmiC zsXsxdU2d=x&nw$YmO>1_B*n6bv_QCo1Y6dQ_j`H0LmmJ_F)&!TR6{!twi)XPP=c7r zU4m&6Lv3!hlW*W*ZR51L2GmVkM@SRO>1|GKwg(f5bi|?n7ww-{lV@L8p)wXAKN#{d z@^lZ2(nf^7eR$QoD0liAS{f~V)##of%=$3@&J_~sR@$XPuXQ!K2EC~}dn_2D zU|8l{q3DX)eZs5zfB6y9!hmk?3*uLuMI!M@l}UuMoNBbCr2)jo-$u~U9Zer3pLD=a z6@!^$>Er{yK@8Hp1MlL}r-fp&Vy+>^+4+f@td<7@OV%2u;2Qyf4CrnsMNmY)o*T*3 zR?$$zbdVQw3YIdx9x!qJYGndf`}5_?+97wnMW@h=L_|?OE;< z12`{w67x-puCkh&!t7Z^>zJ8fpcDCKaMbg;%}ahsK0p_DL5W*ir5XWD!B9F0S^sa? z&W@u3j-|}(gXKJo+>rlhnvF{c@rM7U>-hJ_rGp0i6QgWXgsgnx)~?~!!@CVu zrB?Tg2E{CX@>%#4%z`8Cv81Tvfbg^=MPW2hed@_=DuUinqqnZzL{Ers7F0w7@7Cps z2jCpS4=)*1k_xskPQsae_Up4AyBx|V%-`U-V?^rOGlVjCPwpk`mkm3SzWKo18FIwn z)lL*!*`@AA34$B=5(Oc;y<#Q$7>>E_t1Fjnd&q(fa=r-XDwkhg-Ze?gtmc4G{H=k~ zfGGb)861wzW^BHABBnk1oIkDwVIKv(_yf*Zh-Nnd1G8RdWGl_C)oaB7ceMEv>s0{6 z5iWhE;A%U|toLqs&s(E3`c1+3SEGU8{*CVaFCp1B>*Zp;6#HQqG-lplb3490z_1;+ z>WwOS^xM>yB;`Zx6Ro&ysqeQ#uMNnk+ExTcE%GUrC~b=>yX&KQH_v+`|7n z)vBD}z_F~G8Fdq%$JeG>-+}epc-r04tO9{1;Qb0cq_QhoSqrHQJg6?8+CWU7YM^^W z>?=rA<&S_gwB0<-55y%jR|u|F#x|4NK2ZF4FGN-4YBm!k+xq}7q#?5iC#>13K{9)I zW#cl%s*_nZQO@x+pL-nl!`GE!LJEy=(mt*yDLCJ0K#VQ{u>U|vD9U#tKvkwE$+Q^( zfq(R9UieAAW1dALBla0*6bqS{u`LxY8ZYaFiBeYXYx9=Qn$O(~Quu4HAH!LIZ2z|u za2^pK9Z%qWmVWLTKxI2~{3gX0O_qd=D%lVc6%z&5LXycf)^D9W5$i+%;)57}cZ$UA zYBA=nJ9#Y4kmszkrP`Y0z?#Up=m^@}C* zM*A@RE|s6PX+q`sY$^$_G?*TQ`|0Dvl}K-suY17uX)f-xz!~%9<%|}Iq-K_*%Z;H| zWbd!ITnJ5ehX@E;2&#Y7Qn>ayJ>iyEYlB>Y_WGC0Ae&TT@>+|{jSaTypZ`fX_;@=9 z#9f#JkK+tvbled7F#HBy>SP08X!{? z`ELqmy|NyW@KhlUshT3rq{35>s8GzSAN|eIjImfJN&v&oNFH61{Q``Zj#B9iZ(Auk zT3hZ_FR{K)80GrWaeUT`@kz1B-u$;=-HJsAmHym0G>QPbgN0Ylb}K-n_XltCJY%o4 zHiC0)F|8M$s18ZOOp;$<{Z{w#9^F67WZ}eELga19#V|XTerWEnrVJHPs0L?cJv=T) z#Zj~^+%tFPbDSM5>Wi<3h-gd6$5Hx+YVO+bm`_!{(d1OOirN>7Vw#HCYIn&;=vYfIuXg8ylGfk3{YLa(Y%6kLka z3?0=Ni!>f}S;#%6X}h??YhcL28drVj~=GZ?kE6 z$}v}YQDq@rSP;sj$r!QEoR;B-jm>rwR_y1zC z+c%XuHewS6HxzAR;y1J>O{!8ck|#=RkyKotyD3q;qd_8j(32@YN{AQ}fB35Jb0-B1 zM*&q((+!=CdZv)aTi^YyUa#+4h5_RccP~YB zeCtz?sg46z@?b_gFf>YNl=*S0Yyvv()x1OQAy#kH)Op>4uzPsO;l!FcshZ;U;(}9~ zN|YzliUZVXSd!1H$FtI;v}J2KMR}<1-HpUT34*=Dwc69bhBCWx<=V3vt$Kvl&4b*E z{@*7X#^C9iv@zKBuS(N@8m{0Y(>&9V=%{DETP;wkqC2?;CXZ_My2bZ^iOEVtJVC;}QR@u@wiAfDQ)?C&qNMHaUJNj$*Y* z>Y^}<;JD(Fkz0#Po?HThtKf+pE7%WTtydy8VPi*+MWk)|!<=HyQjJZ?txWkq^QyHM zo^?E9H!z?W^ldC@?pl#|gwXfp%9^A>j*fW#%=T6+f6mywGfL_ak#7_#7+e!jHWZr8 z`r_0{@%WcaPcr;BJz9B8O}_Jrw2f!DOv#PXDI~`(Ze32HP;TCOR9;@*9eNi4XqzT^&coyK9K~6Fh;7S9R@m{k4HebO%i3cd?G2U7tY;oA z8?J1Zo>6cgU3@u=B6OidY>Q_j*~~}wp^~e7BV$MP-du6Ssf|6exM<=)+jjU(jK9iB z@^l+XDvjCfNL^1#zfwOW#6~H*yxSsHV7^;Wm5@6@OlNmR`=Cq1p{ZN6?0XVY&icM3 ztMdzEFlI6YvSOfIM(Lmmg(}$*oXu_w#&4$LOLhQ1;#27UHihZ=sG6zHFO0U<;d+pG zr1?1*VrD zWfvs6+Jfi4WJt^nW$-&x^=9`$R`!>@&G!?)I>eenLxVNd+w(4q2Ajn}?@FFP^|tsa zIua5*WkB!R2Wyg)SB+|&1S+c@{F#mKW;bW_%s9$PSkN*N40@6IMrj!SBzAl0xphkR zt*D>`cxOUqe6H^L-e@uG(o$r5eu)~*kb&ap$Ow3FEVV}-TBm!1D48KD)DD(%C{wNx zS_E}=Eq>0QpuRuIr5)E{6c#@xi|TTW^M|XJ31vhtItw}@hHveJK7uAo4402wJbPA`RklU zQ=gre_>hGFtJR}EYF~@`XsMMsm`rx{j5eI@iXLK?B4(A}y9%B`4-P&g3~L%<$)V!! zoPOiaxf6T?ma}aU4_93HyJ+eh0G+%113>3s=~r>azwO-Rxv|b&o*V1e<*Df!!L#A3 zSUdth2O1KBC!jjh?4-AEP zpVg*8_t3sL7g8S-x$R+oIyq(dFA?0o%jqQ1+cD>zmH2qY&QO;Gk5`aG^iy)dyGXlwd)hFhV{^D90qwm5#<5;n$rM&OsdsoCz}{Wd*6M^xI$P%%q>OvUL2R1 z#Q+F4TBC1W-pDVxkxo@tr_F|peg-xHMEn=S}glG0U5xqvGi| zK|Pf__4hrdw-R0Y#qdJ`#FDKw6||8GEXnQ9A_N_TKLy`d8=xs-0Yqg-FTGEH0DE1> zHa=tTV)oQ5_lxc;K>NgmNJ_|N>&W=HfD%vNO~9@7)fq1G8vx=DREE{L`t&CXMY}1kU_Uoq=Q5f#4nc!$s@B-~ajZ&c+%Z7RV%4%^*bg@A`Sx|$Ac$haQu4V_!nP*!} z0!ykqCOn2bcD*}FPOSGt3cXE%J8wb1g-w3?QJ6HX-Se{u@=G~j35pHG5amk1pb0oQ zSZcz)9Ly3!z*rLv#E1I?dVG++Z6?UgsJ!kVjg)E=^T8c;4T3Yfo7U3I1J_y*22CLz zi?2lqlitDiiCQNXBhnsC8!M%JL)rWD6=YM%!C>R7p6!NW&sqI~0}f+@7YZtYy+QTu zps;}88-Cvl4dtww5Ld+{V{&I&UsQB};|J7iHF*^8{XBjZY*{(l=W98%7>nZw8A*4- zs^jtIhcr=>dtDm|I+l{myOMdgVoce#jxI9*WnOv_1Bh{SY6uaaYxx+Q1sDOujR;>l zq}si9eo{AMR??10COLF{BaWp?Jf>hN+V=^lfLr-9rVK>W+yyUR;r;4=^1MW+*McPy zwWqwyEHD^^;YP*P>IRUzHkwf@*FD}9of=GGXznEUOGE{fEBc!Ai-a2zn}D;LZsB)l zj|N$50f@&6{N_}$(#vdEQV@#e1Xjl}m@9tYv&1G}HX)kdyov)PxS7S z3*1^ikwnA2yu@uBgOKtGjJf_vID-|9BD;Z$-2}&&Oz=MYU&Z4pyATdk+9eRlXfOua z$b9V?)mi@!OFBoj=G7;4o2MTXn^NW$&d+n)SXkNi^Q-`oP}mNg#-v?k3TR!heO$Y z@<9!0x_roJCzT=FvK>ExM5T^D=oAi&p~$u+6tHZY+qxz}`~gy~4~+}XmN;8UIM9*( zUXTu_5{>}}0U>jN(Oo8M2L~12fA)b!gkrdwOfh^wsP~jrzyLQ%i7RWF?PBU#gn@_0 zjdH6+P97b3>{fmmgdD%Zm6mgsrbYek@U=D)n5&V~WT0s2d|wA?TcH+(TIF{*<~fhk zxPZKOZ1v^Rj#~{`SlRH(>N$`#0n0I*XG--MpYhH^J^lGEXDjpxRyeQ3#&(4+oBpj#lHg39IX4)$Y5vjYE|C?6>+D&av7BB0Z`c3j!2f3sfbD<37IXi9GKaqm=C`l+pROmEF@64i#}s#}cDZ?1{n<+s zCV?NgrHIH@-p9wcm3Oj7@7pX+jTCP>CaMzmK!4; zc5-=cMx{Onq16lx4K+2L8%Q;ah5q!JA1UAZq+K)=31l!o2UGu})vX)+g)IFB?zrQ( zk>9@HAM^YwbdHKYEBb$8=s%YI|ElXbJ@|`HXISyyEcMy_Pa@%eG3NiD96%{0Iw^f< zY3a&O!qt3e>b-2>d)N0#+u@_^A1n2roh|eJlJjzKsMr_Tru!wMnD#gW>X!=F`D~)J zbuT~OaI8uu2j)=3XQs=SX<9_7m`JKSPmM%t<#B#WY>y$B1Av-|8vuR)x9j!^5*jJbhqDiR`#Qun$71J6@drk

T&arW|x?QRUc6c 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

>0Ogt|(?Y4FcfbNQJpEZWWvT3&~6dm-2F= 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

Ef!UlYthQUMeoJxbF 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 OH{4hs;Y(XmfI?`=yvFf+Hah9KE1C zU5UoU)Dju0#Rf*5an$dhu7e4{^ESLm8B@~ADtoux)6Rm9vFvWI2++FDYerB{OtH{h z8i!}a`BbA$`@3S)GZ(WaC@N0 z=|RZgZ`89R<8L2D^Jb|$y4KFdT=wT(KaQNp`Us?TsD7{B4ZN$*k)R6p-YFniQSGYy zDI0b1rv@|JD@RY(cE7o&BEgz`)^n9GHuU^6JM!my<{CkZgYQfQ6Sh{rS2CZxCE0oh z8Z4|~c)lz9Ey+_`rhY#Z+#g<`dBG1w322o4ULzme^ME{p{oe0DoGQ4E@n(ON0KNEe zidVr$E)P#WMk7B3jNqpx+Z#cw$WMLq|KoAwBJku)nIDe>V~#nSY#`ya)yG!51BuOM zPepz4O=`9VZ3_sm{0&?>BH|y;VL(0L?_w@v`+k7U7PRqK8hyxR#vxfskK)B96ED#W2ZLI5`lHcDwMpebhS&lwgF@0n}NM!tYjFplr@1oY;Cr~ngi z0Cth;P1TiOyb$7&Ao*Yvyma9YNycAopt9uueVfq#m)qF?pT3QTc;~~TgXJ6kvd&|5 zFAn{7uy7sY}JCnLw+zelqKb;flMfT2w zs&`T5Uum-*oC}_H%aM&YLc@10KxF9HzWZXo8uXDSA&AL248(qG2AM&@cD>G1Te5Fr=JGt|>`{EdHq#yQ`jy+!Eyo z614q(tns&lGvQ>wDXX&d+-*~Xgi*b#-8j!++kW@OQiN5#(0TxV>96T!)wJj(I0?Tb z#2!O9EuPR7b~3eHg;b-{B`&uNaX2~Pyk5D%mpiRpebu)-+@R+U0v4Cqr;xYmog3W0 z5R1Y24N=P=ThKzux_!F=apVkXm#|`$mEAfXA@7-9chRh)V79Fwzga61uFQ7Q^#N1R zo^JY~p6jqe5W6k=D$R9xc)-L93U|9SHe#|M?sA^;qxiPkmmF{Dl*0sYFZ%iiz7ghh2@|k1GW4S2HF;qej7tKiO;iW@nU0`X960|3!_^0`o zIF5(s8_KH0^_K@{n8-Lz_N><}#5J^o% zHLDMoavLqt6;QrUk9;1XUeUh6-mJ`HZAl1g!N=AoIz!E#O4MPi_(D~86%Ay}hUS0( zj?&3bz3_eSnQ(?u5~^^YUSt5iNu4v&4VG164#{utv~$gt__U-?18ICWLx)srjpPc0 z$8qdwzkjB1guv0*UR(AqaX-8{l=OH?;c#c5o_A}gx_~ka#VP06Pz0eGqE48mSxnX? z+9#YbYrk1~<+g#|P;%IH5)|mS@Lu1Xz9Z!IU~5(jWa*7bw1bdN&DfSDz!D4BZc;YvCKp45e{AFAyoQH+Ja3-rJ zjtv<{LWXnWxGyS0&CeI!G)ZvQsM4{v(;Wy`&2C1DgAjnDDmJMNo8zc@dtKDK*Rz_l zC$+|UHc}c%;er@7Lp@rHjfN?wh{b_ysiFFXTNe!_4AU3mtOy!IobSGF@kSAZq`%J< z&Vk{xM9V$fm<2=g@yo!z{6m&9Gu@|7;tsR8ZXkEx+^h7NpcyhyzYh1@T*;f=7@-Pc zGOU~5j`wC_)Dtc87^r*q>P3pxs@`n`&QUpPOQ^UbeuCR0@`s)&dR?Pd>g(Ws#p}wd z&%~qSymw|B{2ds+klRFke^2$tF&IJcciyW1g`&)2JV9nN#Rn4OLo+Bsu2qo;wuEuIvBkyi+% zzUeVEJx=14V3dm$MAsK3pC7>SO5Mle{-CUwGpmT-&oo$oR?J)_Bpd7InB7~uR-s{g zX|qVS&$1|b3FWp`Jw3+UJUu4zZ99F}bgF*W(?;+=A7p3s$9#d9S6Qb;49WFbrVo@L{^3suhn^r!S$!JR9P(2 zGJYU#JaeEPdp2vZ)Tm=oYndYo217aE_vD{o2BAaLFACcqqeG@$PQtdJ!CSvO^b-+I zc8KscSFs4`_2;z-n^P@|LDmd(L=ZgAyO}v;nCF_@iC{CL@3rTb!_F`?VmqxFy7)=m zVEKuFr5wDnHTAj6&W6bj>$8#@2(mtwJOpqc0JR}|w|9XjVO2I^aZWpTs`UFbv|Osk zf{@Tvf61Bv4hp0a?o0pA5Tg&QtviY$leeWAgBW~y-AK!<&4mGm+Z~3bo;!&vZXC7G zi|d$T%SY;0JthvPOVZ<-jFkxY5{-L{O${gUp+eALHa}0~FoQ^?<{Uo-Z%cJ8URidaN&PNxL_p-pQr6Cg zJey_pQvd$a$F%|=5^sJ zCcU#|ZyZ;5XJzI_80^Y=?t$2}XHpfE3WQv+W*ig>>&+p$a*&QE{qx-+@K>g8ciwa& z#6iA;>w#hcCprmlTg;Bm{7aB0SbUaJ5s4DzJnP2eX7kuwk6q{n?qXy>1v8RQ3&1uzHl z9iRsb`1l^^XbN49;w@Zi>toUO$}mXVM=ZDir5NjaXBaD02$dOI0s%RDAB`=F0C^D# zUk0V}L5S!xsm~O^@yfmXGK3kL4b>VE>ON1GrFsZ)(d-mYMvVS_T|xikd%=`*zq#JI*`Yg#GjBG;*(48Wjyq zryy1mizD^I-SE<&0xotkhpr_o*!4XlX&LyUWS8{2Z$#cLfz5tSp=pu*VB5+Ayv-40 z&;YWJKfJgm5D^K2Ss^2(Tn$4S#psRvWzpZ>TV`6c6VEnH&f&-{7`$Q2Nsj}8?$;*1 zaw#-6k6IGiMf)Rt@TukO3gV8WNiIj&ak5hSmxEyn-7O1)x(4!GCZ7AC?SYO?p+J^C z)!RtEhnQxKb`Tg)KkJ%y!nh%7q2Z@P|F`|E!+zf4h{`IpvZuf{oWwm%$GtHIs*k)r zKxd-AW!H$Bjo9JL%efC3bZ`%H{MC^M?L5%nF-0ijA~rJMw5Q_#29ZDuklYB!^Ef$G z;9veF;33fvAVmN1!NKkemuI>W4nprYWm7;Z!oT)Z`-lz3gGx&ixO)?+$Qw(Ra|OWgl4?ndl_MWraERJh(=hQYtq5f1F{C}jq$S?(Bkaufo* zL$HI4)&1*JrqCMzAIXU>tGMiR&;~^~aYW(De#^-7`-ndfBjPZ?o$yn@>oThX8^`~$ zY*)ItwA{kh21{v;CcU1L5}xtck7ERIP<@q$EkJAjbBFy#zX~sFq(BIVXfPsosoL99 zVv3uZlZ2OQvO4Rz;i)rrxhkqnigb`<)|&Cv4zT{$Z7Ns|DhX)FOf4okw*F0uTWVoD z!c{vuRb7&VVum>>4U;jL|4@Ecf|`>}i!(nEfzb#8s65xRlAS+XzNJgDIlP3!m<)6MhqMn9H=@E$tcNLTH6PAW$kD#ts& zmAgFy@pJ#ar@VnE|3;tf-+STDoiABSf5>Rrleq4Lqf|1}lD`uapb383AF`?a@%TLy zcWYXiC{|{y3Ep4KpavDoVlsxOAcS z#Z;Gp%e&p9L*>ik(Tg%{4~&%vF0d>9_^<2rXK1Ra$k)H$f9KPGuebl>`pXf|Yp?h0#@@_3)U}tH z?DvH>{f;sU(noklW;I(_FB-bsD!n0MttkM`Znl0wpp9ID7Iq zqsc?OTeqb31T;Hc>lQwI?sh2uv0B|4tG+KeHk*NgQ%;$ulw05#NH@h^F zY?tHWg7vWmzB03EF1c+IjJDa4<{p zj|YMr?c;Ed?60ybTgR=~o!@Sztu3Y({^Krqd&}NL1O9-fe1}15k+k&o z2!eNcjpbC4vS+1leNL-5`$dTlB=_#N&AXPDky2C~u$Uqq3^xnpU{7NMOYWtpK91xb zHN_OZjqoC3FLm58PQ>#mi9BRL3tlw%8csn=(DA7!gvJx^qoh);<1Zx*ykk!spvoA$ zM-mooOQ2EfAH7mkC+*A1SNu(2y8Or=BofJapxAnOvSV~~v^Rn3kJG7YZ=b)v>Vdt- z<1%!B>qeyGf!-ojTj}vKWHfJ!23jOs7LIxmu!jJ#m(HQ6xNlFK6wWP0KlFV@zd$P=DAy~d5Qyr%Ow(&D#g)@z%p)lu zC>$Kg^KBU8uh1ONx*H_DwcKUMce{|X%3O`iv5Gxgy~i}b#3zEd&B)AeOz|`;cP*5Q zeG6#yJe zpYknmk~`?Lo>%!n>fLqG$c!&vG^mc`q~FV_Yw!|4YJW;F#u^M-Y#^g%f=$tU>yL+5 z*-B+1-rLuHm{oEsGMr6`}~w;t+54rtYH#Q zp_oFUIC-Ur^E`=KgW=|MSx9E;iarxwgvlw^z|rAD{WMN9ruU9RoQ^*3v<@#`3#(^f zde<@B|BJwJ|FNe|g9mBLS6%nzok8CUZ%5W%)L#*V0hV2JMp(9oTyGx>@BFmCi#?xC zIGI{FnNHZD_w|&-Qr7$Hc|xgNPbWh(lYF?3GPgdxX!9t^M2ct` zsWypU=dKwOhB;!X1JOG4L=kyPBD!?lGk<|&P}0ME*QLH$Y0YMT8}{s=_JfZ)CGFUf zim}W`k0c<5%V&+cr!wNSPj)H511H|4=y6w6Ae87aM?wgvxrH6m4+P@Xjr^SI9enX6 zr;)UTOTxGcZ0uJTEG4m4Hpgwr;GhTv80^&>DC!?2vM)Rlf}x?*xVOZ2u<+%GkZV^s zpK|okJJsif96yLFID&D;GE=zMJALL4)b>N0OQnEHyxVJ|3EOV^9JqAQ_F#IFf4V%p z?NE-Vi_v_@&W@qd+H;C7?46k}c5*?Bd^@~8TF1mjCLeo{YMik9eUDa2LUDcvJuIRK zV>SC7ZPJBd7n0#uo}Gw@?s-U9l9^TdvLBQ$dl%U+#)#Y1(DWR=i%{NFhaSQe1CQ!@ z8$klh@!GxuL8p zN@C^CZ7T2)nHH<26$+NNq3uPSpxdnX+6#r=X75(%)g|BVcp7$ulF|xGExtvu94q%HKHstO}pqM}4L4qWgn|upgLhC0D-nVB(+Kd>elMSkM~n zl9MS{Js@{3{^-A@0LLqg6Wzi)UN9aPJgLjyT~Qxy;ozgF z8Ro(YD(chQzKN@P(ziQs()z~bNT3dcU_Xjap9CvxQXM6+91s_Vc{l&(;n2%OgfEXL zwL8KIoCEXqJey9rNgjji!}@VI&mz&gSnMj3GZQR3v<2U?lwUkbJXo-biQ2lvFFmbRnA7L0=cFw(W|1h} zj8n%!MCQdGtMPUOCF_3YxY0)`u#;FZ%G#na?*sY*GiDKrdJ zF;zl?6+RaZH(U3~twz^GJg8wftM&&?#xy%ZV|lNTSS9C|C7 zRD1_Ne5bIzS{{2*zl{-B5UKZ-Us%i2aTqQP6NIssOW?&J6qWTk2mZ;wjH+%NU=EgN ztuQ%C#A=_TmYooszdSHo@auLlLzO9DGr{oVnqBA%Il@3Tn89~s(zsD9!+o3ZY9kcxXwQOaeAZ-<_3EB0+z zw47(Ca5(A^Zx{BPmeo*N4vf9HF^X0`u#`QuYD z#kKoWj814?x#FCf!pbnkA4LfBKiG!779a$ZqWz%$xO;P8*41!Wz3P)W9?e}Tl*rqI zi`45bY^xl#!zo9wmyy{U{!qEx#%NRsc0>GQ=s7fh?hzrF6=$R+H0QN8d!-NK*Dlr| z?L#NKrgvQ94y(QHrkibW490z~@JrbEK@Qi)Ewtl-b6L{{-$L~Ld)B1I1!d}*34-Fm z9oZMp9y|6QwMi+AGx*GIeEzuuapVFb;VvUpGTSWAdahCyuZ~wrTxoTHKcdL`L4`*5 zjUZN@%CHm*6W{0IJiI%f&fARU2m^lJPpcYZ#O0cNc%EyrkEQLyVx7fFssX;8w%9oo z7Y(9j-fn51^(9zEH)qi2J8^{SEknIPe1efe)bM6oh&F0Osv*HC9jx;@!)GEbg>#bU zYODMnE8OluFm9qA;_*k29|zFiC}|9}?YzhTLNzb}dw=mdJ})Vo1-^Rp=!lnK!N0s5JbsJU)Vg73NIADz+?QlB}ANb=nMPV2T|#!PQ31yh*-U_8rOxMwdFMu&q`Ik z`U%*c!}UM+BZSaiO1RfBAq~4>NkH95>@T>>-x;pQS;MZuZ_9Ht^4PbOH(TnjDm41# zTi%r$pTd>AVDzEIaw~$QvN7~axF_i1!RC{nK)BS7$Z9h_#&uTvJrz}N>yC$K>|9Pi zgJwxdc;7Q+(p{ci%ktNF#zo_8C+)xo3{DiYcguR~0p|t^?q2pj)BB+6-pbRV=R*&i zT5P*HmWOW`Sz1rGrwRC#*5DeMU>Mt1@a>g%HT}k+gi9vLaAWw<2>R;5XB9(D>Qyg9 z&3Hlf(?y8Um{t5Z_O>{rXIb`EJ`F>lM52rYr}xL)M7{g#DVcj?OSbHSrwp|5@TlB- zttY>YZ)HS0Nm{wG9=mnZz$$Kl`^M* zB1IvL%ZAIb1}a)3e4lg4&F~9ra$^m=`@J?&%`r!(d`%A{Wha9%AaWkMe=^31W8J#fbr&1eABKcEBg@(oSK`FSJmE?a`ouVW~xO>otz4N zTV<*ok^h&Ix+8XSKf_MGKANFhEb#fUps0`CFJ+tW{Q2rB5j)3a@=60$Dc&9oJyAlP zS#);@Jeu&#CMJ*};9YlOP@4!}>-d<4Sd`jH5&i@0wTEV3tD`FGk7T*9mYnUIxS&$0 z`ZiiMT>W$sUwnWK*>`{9l0#2(R>n#V?fqxfLEZnEp2VkwOM&&`inb+$L7l%8oB+tV z%-1zk>NPNFQv{^522YDuuOS5=e*IZv^pW|+JFx}qG$hy+D~?wV0|R`!f;o085>4XG z*Lu}^X5G3n>|kF*7N>(<6LLf^C@J?1pH$+wl+9!JmF|$PukGTp0%F#70n=cMETtn}f&J_W(6L0?6)+Y|I}2If4RQ!r9^Rezu!<2jf*U;iI60N8hm%f^E zB)j_OKe5TV!k**pS=)IR{vZaG<{9H3Z3&d07T9jtpJoKw*`0; z#!Nqwoc=$|z4s$r+xI@6o*+mNofL-Xy|*-k8HCY0qePG1OC*RMZH%5^hS7Vk(R=hx zbfZS^e2(Pa_r1BV?;r5>gUrO4z0X?v*=z5;&aCGleywfoA$9Tb)U=ATGZ$qQc^-Bb z#u?ORpuc*@BrEV63?l7V@PM%jUA?$g>o5frG}1-18T|DRX@8<&8hAMVe7#3R?1mrh zBXVmEE`k@4D?<&;!tQoIm$rH=%TL?Q;w|8o6&7O~eYda_Ei3HD3{|uNe&?GcM0^kg z`}0~mAg!=K!sFBvWcw97L*L?z8!B{g8tCL^s`kj`@oK_J>$Ptm)?Ljkt4sox9^IAm zlKO_Q(sC&72hR;L)uodCJoU-vr^#K3i`I6(Rrj$c{>eeBH|g3f1Z|oc2XzpJ{=<9x zurnc9&usv2=xWb5Hlo4m3*VAr-jutzmO`{<0xGRd@@2K0*L+Zztq1*cjEhz#rW=mB zkms!IBDI3dfWh?=iuj$!ZB{3ucVHPNB5S}&9tYm6OE2*`GRpJ(rp^~U{qLZf%;DO| z8D_V3!bXw87?l@qwA!aXgtGKWJ7OLT&l3+-0@Udx)UL!Cb@G#m+Qf2X?ncm9%|{Bu z>2|VSZ6ad~u8v(z(c*7fbCS5p?vnUo;&)i}&qk6}h24ya+SM|0U!-4SQT67K5&`fx z58$s+cDB6dlYp!3wFC2#`C0h46!5I}=(|NW&9W!&vr%K7@!7sj*LO%}!MUG4Px>}h zNs{OjKZYVk4Oq*Cy+7+ z=4mKT$WmW>}M@AJ@gT^fr3QD&1(q+Bk)Rk}8UIOD!hV=l*3)my`4Db1( zS)8N@_7)Ut+aA!9#NJ5Klrbrvxh@u=2f0TuLTGdimSHKdriR-j#}-^K8{{=x%u*Y< zxs=*j1$cT+BlgLN^{$BN^lX%WpfX*%qmz^cpHk>U%0B(iB-ZfUkJ9w7-{WwcB67`N`M`EWN3RB%zdPEA9y#li#&H}1* zY@fdL=JUk*Ld_cxwY$f}{Qok)igWQ9-aO%OmLL$o-8$TS*>)v)H( z{m{=qJ*|6Ecs>08V%4vZr3VQpEYqU{G+-nKHc~&{LuQmubMe=|D#T4va6_kJxE#z)rsMl=Ft*w5GLX& z4Dlpq=K$BVJMDd@g!{Z3AY|n3KVA_qF8iJX!!N*&x`H#ZbB+rRIN*+-?~Ayhs35m3 zoAX6cXYlp4OME7>6Ouxez_pb`8A;j%AByi}puN6SI8JbdZl|$Cr`xr&+_$NX50ezf znX&5;x=4oTVCCYZfyGls-V?o9OP#{1er1wkE)aH&Jehx-ZJpIBEqyEUzRlwYxL%k+ z3m+042Oh2HRR2eNfyL~QrFh4gNVP)bhesre6JzsMw>ro|!&BrE1>$(lr)}9FZD{`M z73)Ck3;GrNo>T^;{fd1Prr+@O9eB9yrwOhUHIDGVkC`{RQWE=RF25jrjmrhUZntvr z-A9M1D|x0bu}|(&gnS26A_{R#Kb}0q)7{=Up!1lnXBRj+mrwGW78%%&i$=N6FX`za zEMvypXHU96;ClAA8a8b&n(2sibAisGRV=3_CQUb*X{#9K=9f9J8n``e`)5@&Zg!s| z@OkL~x6zq35%r;Duh2FI1_j}8DYD*xdF#!l`P^mZ`(p(KuuBNDX@Iz?+8Q?6QL7e;^7PGpOMexF>HVMEHwZMTO`bphGTwI( zGS5WIWb=W)oOy!4g!SMPVbRY!b+2NXb_vvQ0x!T5uP2`DD!lCZ0-)GhEvD?N2*0pw zfi^G)aN~CgaIkd0MAQ1th}uwN)SutAy?7}nR`XQ3fwUemFf0=bA$@sV2~_6x)z5nN zRDRZ7?DgSLWv4UI-+Hkqdd+__s+zW5csqcWyR-{&_OriN*2~14G=fm~*gzjb2Sbd! z8*`B>P;t5jA=rD*0kT|O>?79vFp}&3c5JS1p7#nJo{P64E8JR^ zTRRypo;~&ySHAAufwJA&gbFx#F5pe-GxWqD1@t-gqHvWitS`s54ng^VMT0Sx`#y6z z>NCg9sA8gm&Qr#_?o3K|H?ucVK1LPSv>84)(Ii-A2`%l3XHk5w3kk_j8(~Lrv>TB2 zLs=gw9FS@D4zyrtmPF5d1qt_AqF&-oT|tbPeu=)J6`n0|1(oKltW02b0>bNz3%B)N zAia1t#>P1z|N3Q&Lp+FtIUB}K~Ra?EUDC98eOtNRF9@sVmA=cuTrONX5$>(=`-x=!$DZd0RUc&BH(F_hN+Sp0J`yF>F9onU zSRx5rBB5t>h;?AZWYSpnI(JU5b%kcwT4UVZCoR!gYxWddy{~ahhq# zIsxBP)E-Y?V~^=dQazaDnQ8xIrr|0lSbASZ17r|2qxL)q4YtN*r_)1(2ZnTcUTW1i<=crX=5F~Add9R96CfoNjBQbl{tL_r1ENQOs8Y6elaB>#P_Mt{*dYWlnREZ zxPt0WHgw{_l8n(Q$?iH=>9kccyhI@it*Ia1a|j6CQTSG*o{zGAM4a(s!&wfrq`2&3 zL>gh@#u>!mLi)MO_^!O+>)PLv_h3z{^|+hJyjgPgqC1RYnm-B*`X z%27}HX8H0qodfB9%!Gm%j*h>Wa2@Ub4Me;QLc)`p*b6gfJy(P^JoOGboWJSw)8JI& z=Wvjwdglq-W_i_kyfOC5?bLeOyM!`8eeT7cmtHcM(2B@2a5b6;*Ea8{ec{63b{ziX zktEw;2Ovv1WjH1JXAEJBx2keWFy9}EB}R&ugM2Yrkcp>XUIN>SGElGvdl&qMmcDsB z`@Jk@q9FefuSOL?rF(VvcBN|r7QbLQ+JaBXkFlHQDgB-=gLhXuVWhNvSY9Uj&o{uQ zR~kOXJd`BJl3^a8t)DL2WyGTAMQ*ykbtCN;UrIWeyH0UYa4J@P@m0lhFUylKwo6RM zRcro%4%<_UK9N_PDmM|=KFs@$J;>VGYe#k!L)Pg1P0W>z&6WLVQz&*$s7EJM*|aFV zx9G!+TYU%x&h&M9w2--S%&s(j=E|F5)@b9;UdR&wem=jF;WaveRnh4<%Vw}%~CwFox)Y%z3Ys$J_ufQ!s2hADQ}B^1%7gs zUlwc(oirUXhcxXvMP&O@TV?X4wlk0ehkdTXD-f1%(~#KsGSQn}{_YZj?AE$Q>-=2! z`0RRCURa^oLKysx{tF`a!~fe)reoVEz|G;p#eiRPxdivK&`gLZ5-l$`2wVRA<5DnXf-Fu{@>K z?8UMU_PYi8ep6AskR$ku&$H+~R3xQ#?xrZicY^XjT}b%m3kIyB#_Bm{gC94`adLJ0 zNWu{-A@9xowY`@WzEu!iL)ho88FbA8hq}l&?_-2gIb$1j6{dEpq;X;Fxxxp1c-y4Z z^@y@;O+nSqS37=|nbBBVMKvYu%BYf~Yqddrb1Y}mej1FXB7>qtdy{!Zss#P1-%>g?&>JpE znVjE)8FCMT&`guYnmmqELMm_l4?IsRYtOs9{AUbaF5J*Pp40JQeYsFH?|kgv)GNmv z;6VKR8OTeESXkja^^U^!VY9EQz7t`fB}qnR*Uf~FtfW`hkKa}`dVfvVylEILd3aUW zn?t_aE;%D037YDUL5Vt&e<6!8dseotnwK}?S?FD6?&ZL9a&dz|);+^Un8*KE(H$j`O zKQUZaP@6%?*9obYoJnyycf*qWfCKHCb>8UsF7Faq1$e`R)X8M}{tz0}a`y72jUK|Q z5LrKe+9eZj`XheGe6xIWlw4@UEk5~}qIn(;?D-lH2CS5XGpU6HNpU_ch#zo|vsE24 zLb_#8b6fqh1l|~kp5ea|C=G}kx&&Cwc6-I-0ZwE=n2A1L?KW`UiSp)krG!3>7hO>8 zf$|5Yw;Jqm?}JYmg`QX?KFP<1-yl(z`VL|~@QFY_V-Cw*PUrswVt(Ec@DX=A5=E4H zjcJxoS4#7aI<58NX^?e{%M#@*v89VPbtyF=#m~quJ~?3KPxtT!_I4E4m@FemB~ZHa zM8#nzLrJ5qCdPW1^Be@tRiDc*fRjaTf|Jm4-#VAEmDu+eSAt5Z-j=&Jn|qU;uD6b3 z>Kf;U+`DcNe5}vf@=h;yIwd7kMqqN8&imQv`swA!4|xQ+RNB}yoZVJw)WRMj8cz$?A{x>5~Tf@8Edli3o5Srnpc4ZqoD{0k~rDQ$m^<58w4?Y-p$hasJ>lse*A` z2kNUJFgc#BQ}dCb$4!Kttl_s~qGeaSo^R5#(ie4oBldz~mO3&IPaw|Y8e<+(nnJ{0 zCTmN2?_*CiWy8q-!P^~tS zyrQdKeReS_lnD|Fp}i~C%(Z zN_+@|VP=YAxT{?a8>j59UFm2Vq^d%plYtrQn=Sq z!IvgeQET~xylp~MGgKx;22ewHwMfMcw@Qh{|?~SL+Ce*yaJxgDy zrU*vI>2jW(!F!J*@91E!Y2G{o2>XEI|2CxV{Isz%%!3?$1z$ZYe_=%d0sIFr%##TlX3D0heUqe$L1Rg&tPNx2;QlhlJo=R+uG)6 zc|&F%i*=BW#VnF;I*Pd$A4dSb(WHdp`>ivPjmM%5*5|8jK-8HH&V{1+45}Iv}AHaGUMseqY2d%WpmM^Zjml zTFJCmG_dRq0;`aWq|fo_haApTZ-;qFpRSbST9*c?BnzgwT55T=cqL@A#mOo;%_h z2{||~jqi&>kg=SF@^cr@MSQV5A>)mh40YSZwIen*t*xaCe71WCH|6JQeo`-SRu&uE zS(wDO`sMDPy4K}*vTt42x;P!_xo|j{Uc2d<>U^u>&EEcg#`%?C%wlyvuH{BMu85NG z8+LBELd3Jd4d#J5`cG+JBUP}!BffCIg)s5mmAI8EU0o{p)2w75of95=SDq8GJLK=d zU%T#X?iM(y_DCQ>D2bbQpH0}*9JNCc=R^)2$7@MkQC9-!#x9vjq0xWCoErrS^Dsc( zTR@3G!y<^DO20=E-DcD#%+Dv11}meBh+M$y1IV`R6@>#Hx+^{oMl?r0D5BSjeLl&e z?u?~SFJmb7#&J*2UaPlAb(UCafIkE!c4pOj)>NMBwmu&lrWObW3qocOZCiLU0XjUS zd%!`W>w*BtS+u$?aZLDn;4$;X2MTRi0Sg;rKO(lY_BzN2yZQFl;|*fjm;Rx)3Wn?Y zZy^g;xl!5;3MoFXsSbG8|PH1@^e5UocV)4EE!Xi8wd^+wk0#U4XbXumIYOn}w z$R43hhaiNEDr7?ymO?Tx|BJ8lA5zw5D%>bJPY-{?$MV%n)ejG+6Wdf@n^LC@Oeta8 zg9cR0s6u?>uz4}-5DDS#fGR2;~=#s2cjKEilXQB zHC6jQ#qV}ksOZF4x><=fF)zf_Thj_v?Cu156s7lUEQg6QU5;CACEW+yt&b~atGt;2 zP?<30EHd7@p>d`utT)GjadW)Fjk2${3)@oI%*GQ|HEw6)$tX!<@$0gcJeirb2%Q=@ zTP(EeGLWW-J9-Rx4vSb~H?-sDjgWHebQrUlCjPIb0nNMU9u|Ls`%FGhFGii2tHp*2 zj2ir%}ci0Dw9}M7!GtIJNAssW0IhX>DBiAvgHIV!9?lrAdsAQ4i_lM;Do(@!jysrjT zhAotj=n%O}&2-O&Wxi+ExFrD`m4esEBeH4b(ZJFo>QEgWI}(2PRolivL(_O-OLOV+ z%}UrJw6JYAu9PC~YivwH@5l{2sD~d-R<%6FXfU^`3D8sKg;TjuYS%Y#rlH$AJAcV4 zb73*50%YXPYmI8n?+VyE?~xj@LPG5mxTYw2)GGG`+XfFX7upQTbz4ejtNFjgbWtYQ z03JSbAg8HJ%se*?soWonOAoznd&OX$9`c64Jnvi+_zG4{Z+Mvr!$TIC!b|z(d;`I= z@EqwnqD{uPrVWw4L70NL6Vtu2D9s-lV#ivlXKZempf8ExU%G*^2B5G5;cEcd`sg3n z(u$<2wpj16n3cCR+X;!4?P=Ka2SMHP{HMpe>9`?Hpx@68BesG9c~t{J1qFo4V? zaf5nfYWs>sffABlPEORjaEPehENeMBo&(e!qfE)ORkS61`Y;-j2GnzZ2=={HMFgr) zfUdoQFnd0828day}+-hZhw zU*SaUR?_rfll9|H&ftb?21MQor^{8ebw|HJ7fj7A0pirJBO%$AKrfTuxdiTiI%&S_ zXE;!o@S7$XRPQkio4#%SCEdn1ii!q8C#|JUZedel{4{{n=^usWD}7|pW2!J?k&|+g ziSJbBQl{>=HI3IrrI3IfE?|^0FHn*9Lge$?ceUpqrhSpxSNn6__YzJyQL}(Tp76nw&g4q!-?@xAHL7zc`z|*vS~K2Ay{d zOc``d+a_Ivr-_`Y`Lj7SnN88clIuYIaZ}qRa309dfFC?o(p7yvrfKT}Jv&cG55z7` zJZFU9hu%M_PR?}B83BqIqMLryE^pH#2_$8l_VGM5yJO0hs(&IwkA+W@qpQr1#qh00 z%C@LBT|)nboM!>ym=MO{i8mF??I9}(Zj0hG7vqZS6W|$A6|S}6*cIvK4#xSqvfo%G~eHh)&HGu zzI$VoYu34p`vi!oc&32P%ip9xZ=!$d9I%m(3eFjEqOQ>p;i~~GT**xi8|SV-5o-j% zdLs?KU8#&%nxS%S=^;O!?iNqN60-(|3;j!2@Y125IbwpaevxWL1eq*82j;`Ju-iq3 zj-SqEUh%kJ1HKl3Rz_fs{HAj-03K1i0D8I9uzAtU{h<{hjBl*MVMqow*-CqvPvo)j z@6qa91Cs7QUGODS-DUl%5iwcB(u~ssXvv^OnTPGz3<{HOU>j{+}^%?Ck<}(`iYaU~Av8EL^hiG8! zqj`poPWE8)-qw=5LpF=inge|PU3zBtqTplE3MB@8basJqiO>#x(u{+D?Bk?U|59|=&%=c>jLVtiyZMKgAHi%M_eW|1axK3X z0l;sUj*h^IK^-#wiG)^!W-Ire%5QO}-~PR$Ad<8lcDUXpOioGJZx zY|1~I1mx=f(uMhFeA;{<{m1{)Rn6JD)k8%)IWw{JpBrU!cz;;bIS_=o{_wC)Y1lC& zXS&>T)gdIZlxCcRKJna#&C`8wj7pEGVd$fU&izuClWl(%ifOooNlCs1m~p(qz;1Qc zpM@N4KGO>K$!yoSS8CI7y3Om?r6E5$k+-nWrB;KkGK@2lTbn`ZQ8ZAuml(`_uny!C zX3w7ykHYm~(R|2@u&6(N-#)b0GhJKb9JSZ2F)mbEmFREZ(^j&0o;SKM8NEKkb0AtJ zI4**}K0S%=8|*jvVE>u3qwHG9Oul)kA8wSRhI2|OZpf5izQ(O~oTxsQ>oi(tQBmIj zvJz%1r4dQ7b06Ct5tTo@%Eb?>*skc#QVq~}P*PF=lYMFo2_;}(AV=l5WaweXxqk^V zkx~U-b&#X%fJ$~TUWi^X1qvXrsifybRni$l8kETTzo!^Ow5}`RLRn!eQGYRn0iyvF zLU#5ba>`1$nBcR@MjFtm-j*a{K(e|zvhqDT#|v$b+uwXU*8V|%)va88Y}cpJ9KkAv zkhV-j0q#&7M^h%k2%vZQyOgmN@#P9x|H5!L_As+gc6xD2h}im$&har#AJVOQz^RT1 zj*TEl0u7(~ntZ9yi=BSfFc1s06om0gdOFPXZ!CJhFn~mBab;#Gw6k;|YKU!+iWQN$ z(c2FnN7uY(u*ZUys9%L17tY5{v-50Q+vuq^5W&q5eJUK2v|I@_BAWU+m z;5YhuCEjqIWtiwmQ|>|_GEWKD5j?s$1Z7*u(P?-8sM&B8su}Es-U1^``5=x<$u#?)L#s;G@1x>iV5rdb3X=zuJz68Ff%imhClN+l*fMIVCxWA671(&hbdUMi z^soc3LUZ)Usiz;Z4(Rk{h$yPmH{?vD#)(9jWpWdIhJ{t>>sXAL1FnjX*` zNQP`Ap1?|EkK0V9T2dr4e0IB6Ax9&YsuF2e5t$R+9=NBla*Wih8#qw~TIJ9+JtaVm zu$S$RF5zvo!_z&&J4pvsO(WCJQx}6l43%ZwnUL*xRYQpF*&zMi0OJuW zoSV;O1zuIcs#Y;@vVp7_0w=CUb5HFlJiJa9Y+N^R0fNMCfD!S2^N}2CIj@>;oW^mX zCMG6A#m+~%4>l&p3k*8~9xw?4)Sm|wzXR*#Z%#UZST!?U`F?n=zdN7%qUJ^7OHhwK zdTwnJnfb!F2OlEvdGi&x!rAzAAoA>Jh-I)y3&A7yCgp>1sp6!I$MPqRnaYTGOZ49E z`eT}A#gce{e`jJ}%YWPf#HeK|=-jb_}R;=D#-4(cs#5H!y*0H&U>XP63;2S(- z9uQFKWwK&^@vQCcy& zWKetiy+F1ar>$A>goQyB9T_mVUyf>5^5Eo>B4hPtY~ju2@#uvz8`uih0+@CgJ9l_=+o$14;d_b)3vuX z$g^BbzJKra3s86QcwuSy)+zTYR7X2(=Pe>j;R%eK|CzaYmNcyplU85(m<%Y~V?UAu zts2W?20u?UgebFNepqji{B6hOE(eH`Vcz88uWRV&7%ZAKJ;9OG-AhxpT_VPoZkhUR z-Fk73Z^vY(OO&N-pVlq{7U@rQ#S5@~uRt~hcsbBBs25l=)F!*P{^W>VgqE7GhM#q2 zznxCf$nG6N20D5cyGZHC7|9Ms$cd2@)jwdzWZId?=}S16n0@zcWf3A^)=~gmnX0s> z;G(=RwijkLB)%1De2wM{Pr!u#pLCyiHz?* zNAL?Ps0|=+R`KT470UY&rdOd-9Z?S+kMpQKpwH6AzHn{d{;{q%uJ4MA;2xp}v>~s* zCJT39Q)@Pmim)&$DBO+Yz+efuyBk9GllK2Lz?aCC5{hs$l!|=|%#&05pNT!(wd0!W zy!o4k8QOgj@6_{BKZt`J@J5SX!aCqDc*RX3nMUW!xlrOvFXD%1r^xvXTYvTnELe1J zfPlddgmY^}*N_Xl**U0Xmat-`k^$t(4jm)C4C}3efCCHM5W?bbA|Ob~U^1HUIcE}_ z-2OQ^5sI_(-UGbIGyB%3QIMHlh6tlW!+Bm`i$LdvF8}J= z5CcfvvqFM4mFCoM=(M0V)#my5y&hmHM@jC9{i3=2jTT^K1z6jp!oShz5GEja-9wUc z#gyU)+-0>+=>7S0rPyYTBbp)*+u{ z+w+3jl0mNQvgP3=tR~ap5_{pvpz(^-liR%tnIaTvh03gI)v0zSP{k@d7hc(=0h$MZ z3m2r@5fx(8Y08*qdW9>X;BI9$`*KINsABEjQBJyb?LL*w7L#2kO@}7`g~#LcUArBv zW{Rb$E+$jS#p>Tu6B(R!Omwc%aiZSeb`oKXUghn`wjzsYtiWwevH52<0H+R4)CXrC z(@?iAZ9_=mSrsdr80DT+D5-IAxI3HsXrjC*u68D#_GVs|JZfCd=MM3EAgYE zA%xmJJoIRUr;FZ-L9t*^deeAu^a!1n1kF$FHAU7fJU+3>n4;ussz8$2UgxyU=$<|s z9AaLGEayboI(kf2aOoY#U+EG!ps{v&-0csK&jyh|-C6-dS(2mibgeLGqDpr;JR2Qif7b#45GBQVu6GgWQCt_J=dwV?o zSzbDtd$Up}(5&{f+6H6~J|0RueC0QbVp6Y7odl274cPP+J4sO>xLv1&Y|2i{R*)Gv zp-P<2zmQxj4C|w?#YU`Uku2;AYEE;~Wm_p!ry``H$JXp>r~h#YKwN47Vf^gYwQ)FL zQh26FbA-@&7*YvQNKWOK5`stGtBwxKq(Fizu*OIYh2ZA(;jBC#w0is4cp2dZV2uYX z42l^-4lgf+X)+azU1?cGG8On%02?r0EKRzOUk6tp`KDro?MpnzkJ#*T?SLtP3FEg1 z?<>Yn1qmq*D7@AvtHVmx4x5&f?#FZ#hguY{#&Lw>9gn&;r|!u(uqRjw?*0oRml4mzQ#MMUMkgi6 zWF^Z-a94OK!J18JEDoX96fQ9yB~8(@A=Q~K=FwmSk}*<7DoJZYH9ecPKS3)}Wx%n? z$NeSd==6;u?N6EORXHEvENG3sbdA2Zqrf~LRmoOppTS;*n;$56tTT*PD2{q41xDi$ z@oH40Vzv?6LrfXbqWr4LLoQ8GtXfBp)3#HANnL0ib0h-;YMM z@Udx#BBfl93BQ7eCN8wlwahNi65fjDobo2Z@>cWc{@`Kg^*v+8=kSj{3z$ zD$Uljyq|`o<;l| zcJ^0Z0!X1|jelPkJ>`S7*N7%eY$m#|tVtELJUrRY+>oF2>!x;jdDN`Z2#V(p6iap}?edkbY1nfb;#DcX!?lCL@GRGt1l zxL&^c%%MeTW%s%gkBW&5S_z4j&WxOwmdYOpf$JZ%pWA~qN~mhK4{e87q9zkPDu_-5 zQ?*@`i7|bOE1*9%i>-*2Im^*YZrz=?sjrVb>^J4tUQRJClq;-xaH$7O2J=)RN3vD8 zOL6WZAWmJA4Ig{MvG77HvejDzUN&%V-Oz@RtRq15p$m;2o z!W4^)m{#o3%zyiqjep3NFJD4+J2YpMJJwKYT@-yrs+q`yY*L_Rk*U?F*wT;1^kq?L z|K}`@IV{hY@F=P_fKW)DCxLhz*|4J8H%e@gRjTbNNQ@&G$JYMOojWHAX52!4vv2>p zq>2?K20vWis`3E#&N1Q*dP6pmX`xBM#RR?4T$dx4rg1DtLVwAE2`p>pd5${u)>_8i zEoVi}2lhLn*|y#O-J=2V8A|U;qUb`eFKD6&T4KTt7ha7i5=#ZP2VJqfhDCRi-L#qZ zwc)sGNa3c(vXxVbeXr$pqO!NU=N|Uhw$>-fgGG4!7@g^_JeT0POhlj_YKr9=zK^`$ z7tK~i%ZVy`TUs)pVs$e3kf|dze^DB#O1_YaBw(?B_vabn8gO$#zAsJx3r5qGE|zh9%M%!q+KZ3Sl>Yz@BNp?Aj8V$yO56Y9rp9%U%0fEDq~Eya;t;y+vMZwyCyLf)z>50MO&{;{B$0sn ze^wMU3GNYk?p5&Bar_VR=s9aW(5)Vh&=Ja2{A6(3|)Ozpt zG}bnDcl|rL0U&EG>EF4NUs4j6!2auw|7I}z_4X2nKwtr``Tgf#FaHxQeqHnX&%a*& z#{?ib_phAnWoq=#*8aHs-9epDDdn;9&B;IR@#?P(>hC^)WbMsRW>P1cFMqZSiCoe- zKE?i{Id*x}lpqf$ii+79T)1dzjyb{CB4%)z={hN5Pf{>WcEo-@I&;UCeMKiQz<(lNjTm!BqQB;u+v)O z^qXK|98CenMp+2?Uk?6#?*Lg@Gnfc$t*faWc?1!7kG`uHklV{8UQNWrs{aal^N%S> z%C>M?7S3Uq6G`8`kU0tz4af75gf++GM55EdVQWpL zv-3mX59|Kz#?y*u^ONvNH!s*O_BZzwiB73lAi-bZxw13Db$- zU3V+6`q5@c;lLEL><#Fh0O;7aY)9~lZa1p^BWMNmCYW)_g*;s%B4^drO2dVcSjx9+ z*ch&w$)-5wRbuz2K$YiLgMkdmfv;Z@|4wfA+1POHzad-qkq=^4Dq3N&*YQbjFXXF1tf2kM4#li~dn5x6F>|^)W_302c82n;Tep0DeKTNe zVj8Yo_;s&$JTQ;8(pg%tZweR z^pKbKTLyZeF2)cVC25LZ0B=QP_Z%PIgK5Fp}x=RvLyi6^j=J$&FzUSvPM%K!; zg6$7>ZVkJTIBB+$gR$Ew2C=-y;S9VlM@y-S$$ZHrjwr^C$N)L>M@;!;mSiSJO_9LE zn!h4u1qz_Ybv9^@3~Py{3T4p*Xp!>`AxM^1%EzqVicI=V$@1_CQd-WQPR266XY2G9TwgvjM2ntlDanEG_W{h#L zzNtK>3D47fFQi3uheVAtSO6AaL0Oqz5^NU7;z8?qU%w-2U1dBuAH7Yr9iu=#IF))N zE3C#-o~75w_QHJ};CmK+*dCF8VcQcers$jrPfC00dFr%ts=Lsmv5~55rE&3r?*ep> zZ6ViqqRlv#tMLxvR9|-XAN+mMb7_b}WsM)dwVjuzXd2+oT+D9;Bo4&vE>_;F)Utvv ztp=$CU_Z{`in`-0rt$G9b;0LWA;Wv%b;*q6L9m)YWDt!|>f#ocn!sJ2M)6K-|J!3# z8WU~wbCa<bZ*GH1cxCKc>3`Z@4^laNfA)@riOSvzdYdW!urZG zG%)q@_3!SPx3r@G2`Mhrq55p-Q|j3Y1BkO&R8ew8~rA^}9hL}82?NINcPt|&SN zW4b2$b6xW$g0sf6cwWVg#!SOI(9w9BX`Hh{Lp{OgM$ z`Qn~_=8gGrcn|}3t%m7QNwJty9FRNB>f<_Uif{a9?X6R@+4DtP%y0D+nm*Ycad>+) z^x+_j888ShiV6Kjz5@~PHWZj5y+AL66i23bU;TxUBqk9Y#Yg4~lkN8BcOsB_?Q`?` z7N#NrXaShuNaey0`kuCM6GgxFg`tcWnHKT*uPh>pp&M=LMT+`gPSIgJJ*|8UWKc}9 z!m7^4lrDtyt0)-!g~$2W68fx#KxfWK1lI1zq+Y$g%!PV$i(jdpZISk0n-y|YF$)Ds zSk}^De(Oi!lh6eXy#4)$Rjy4mxt-xAL}bvRTVV|I;$#GbWUr)rr0ef3NS53odl_^J z3((_*xxA3WsES=LF)QJ~lo-PeUU?#-FgeK{itO{seuVml%l z_G32xQ20nPeUc%qbx>4}CAi(uEQzDoZ5&PpHBvZIXqD4wZ#}FB9tCrvY;p`vgnq;8 z*==6P_@?rb!_Jp#WLE&P)Hkmlb z7g1w|kUa~XbB3d~Il)MFCRX)HhNQf6XH$EXqfw^|UNY$0i`!P`;72+EI(>({VxAt` zW&J$;z>^#Hk?+T{CqWDs%Ff~%FiAO@ZPfxyot%qw z8#gbl`Z%Bl|QeFwfS0h8nkVlZ%O|u9wwz5oZ`m^k5m1QcQ+(JeLSY zV;3I+8}RiD!B1}mr=DtbA6Aa&RQ@*Tdp&M{je^swsr##aN8@}CV;Xk5YXisTYWQVY zpM=IZng>4Tx$hkRbMWNJ_9tJH?qn^F08G&4zQ^j~`AjQp=iPjMnbpOqA%67}FdhG` zoDJ8h`0NX`dnXZYf93SAoxsy^*VT=*w4NzaA>r86k*Qur@#KS}4i&zVgYc0lpgB0Q zQucJkox^0Ub8}DoXNnB)e^sOINk_7BA^N7~o7V$*H!eohEWoI{2+I@mJ(Y_L;t?wCqN-zc2o(dHuJg3H|KZ8`HyX zoytVi{l*qSB`|1;UWLI_iLDW9Xb=P5`0?@HYRa$B@V2XJ!4-&>z5KEpEjW(U7g4Tp zG@(8e2R&NHKbW*_vo5zL`D2X$wLCx#Zoa9?@sYthl|~XIN@m>LWE28K7uV>y`B_;- z7Y;v$(1<{)^ZnX0sSy2kX*P$$>lFK*yPZAaZ3C>j0j36aGp%o4HrZ0gz1`K_E>oWw<|NZR?JM)I!3O-r2!CJPR5SxGrDVV}mNk!%y8IEbbeV(&fx4WedkJ?k{Kwvx{dMs*fp8QoSLx;3}PsC)PayQjaQ-#Ov%_6Dt;;rYW1_2 z%|-|Lw=u|m44i#hk-}jN8D(th;iH#XK=K>q{Ix}*8#75u*v}5kwaAIqU-%T;ir7%C zS!xM%Xr@F3ZjSKogjmQsy;=&xg+kB*XWyCtivJOpr-}YS4A`Nnh2&&VmhGpj9VA-k z?T%+BOhXqPcVw7X5jm^87nvPa=ertH=ZWxfp=+pCg#LAWK0w!k55i%@9P&9(OTEOA z8xl-!g?3=QpX`ncvW|3ebQSysq{FDAcAm^> zmh)@n0NFc>${+?h{w6|q+#_P7pWs{&m(8oczSF~=KiireAt!p|H#}K_X4rh2HFLeh za&wZf9xF34 zgAeG9nP=Y!crE3mrO`{L9*zyOb8~a^^OJ%UG(VPovH~{`xO{@%pH#pz2zU$_-~8sU z#cC-M60Pm1(I&JVlr1dIiXGacRkD&o!V(fuVyRuRN<+e0W3?_;bGEq=WQoq=H(%A@ zJ9v1p;2LU{85!#9y1ke?!q*N+W;8mP z5VG?`Lt5lSSV|nT3aW=6j!ucGmFJdJ!?NE_O`YWf#FnmX8{;~3!NrycKvQ#-Y?0jGg2=j8Zz^f>jCfp z{rAx6a)bK)LWJ}d2TKj6!e~rmu|thz&Ex(0xzm0t&jY`ePw(k(qbAr5 z>uGRiE3ER^YMbAoR2SY?ky4TeMQ@MGdo$(MY?MXFb*yXQBh*1Id%h-fBjhO6TK>~G zY~Z_gzq@;92kJk_twP4Xjxa9aIF2(gH{? zDk73ZkRrVZp-K~wUcJ(*K!8J6F#$wCq=qI6gbvb$2uSa}_y2Ic1n&F4nZM6_^Zu6^ zGMhO&d#}FtS$plZoCFYqpGadQ_S?o=)S;|dDJFpzD`Vrv`KvP)ZQ z^lDTbNmrOcC2Cd48)kG;xegdI?||Fz%ZCSDq@m=kj$Bl7)B0j}Jr+Eh=4zb=e9scF zxE|}_ge+UQuKX02tzSP0b57I7As{C)MX_uk9ReQOaCF&Og9T*Ve^x2iuW?HQu(#cJ zNT~<}eFR=YLkk&KsPKs6dU@}RMFsQ&k_be_(njA(cD%bEM~w# z$iSbUig%FM;$m>Xj?KRT<-Q=zBC%{Y@4D|-@(Fyr61twaf$J_UPGLAGsPNa1dDM2D zdZ+jLLi>GmdU(H(vTTr-@i$M+9HY-i7ghVUWirdDNifpez;%CU%kDTMFMxr%w_Dz% zdiMB`QdO-b?WUVX9e-}?ACZoyXQ!P=CzE8{zZD49C?T*9c+$WljQm2U?6F2pl)oLH zoow?uJ5?7%4^SbKg3^jP*I33pW<|wo{0(F8fJYEM%maz{lus>{qY+Z>J0E=mf1b8;`i;Vdr$6xb0ptb@hGis;am~ zNxor!G3OC*HC(imq-&`HU7zS>_g^Gy;eyDP$oUKlrQYRuv$cTR&r{K_4zi);kl-;Axv88k(55!q$TAfjk z?~nvpGP;U6I?a9mKAr>fRx5B6k8P>hT^fOcTwwP5Xbk5y$#(cW~=(}d~QJ0 zaNJOAQDpX5BonjqZL8tNd0W4lq%c*8FRzie+S)TgHyi#j!O_GYn>7c8RevFKnI4lS z`f1I7x>0yYv=Uuo(72&)I(m%27L{hEifVHV z7cEQU81{f8oCF*ngjbO&KMp2$6}U0sXzm@wL$H zO(ih$w9Iue?IOU(- z_g}x;kecabQzgDlUDL|dn#1KLrceGTeS>(x|D9QpG%hi;q-2_5PJ-uQ!g83@pFo4c zLcr%wFX*B4fC&B1KAY!ncfaJIt@F6`@wkoMwipLR_g?cXpmn2pTt~-a+g5N->Nf&? zJ_>tuIf%RG`%w936)enrZNcq#AE`p3U+qinyAn~%1TviY=Ik$CE7lRDG5Pmy!FS8N zqL>LR__G^#N0912bep+b_UIqG33LQ0|3kN6X>iht&rOHAgT-Q3-uCzRuaKN~6tsLC z{Z8s97mMvu=fwOxId6x8aQu2tt+KlH=6-(uEjTg3`a!l=yl&p1IQ2x>NwBLR6DOJw zFE6h4W2z%G#Oa3K@Ci?mmhN?-fnxU%iP8{haPPQ%cy+9h|oh%&8@ z0Um+ExgopB4ptLd;-=)Sld{)C!HZPCM0(?W>zQt2%2SVMPc&4Ne0_6GAmxPU<*$i$ z>spSE0h-!=Uw94n+_;mwb=_|k`4)HDFF)&epVcC+`8+YxJ@0C$_w7iLiC6B4Oe&LuyZa?s5 z)lYdVh-%uzU}zoi7(5fAz(~(B`eIS?+hV4IUiw;ZyI|q^97|k_4ry}nl(OGmt|R%! zE+&0yUnGN!1w;PDodRUZxuDktv%Vou@dcK6tIu}h^Tm;6V+fN0cL#=2h4Swl)85v` z0~gjOwuKbt%64h8!3t~e*sk-{^H_(?jOYP0#>y1{e=eF3?_ zdy%f)?e~Z&w*1RB$!;uk?Q(W>k#}D`xc!v0on%Vt!_LPU=`VhK7^|tpt(Z&BX$z0~ z70-!@Pu4PE?&4MyIgm>(to95^&_3`#7DL3eP|ZE}jAC`$_c0h^gkWD@KP5eTl(T03 zEkv(_G)~15XzSJDXSW81lq%I)fVsRR9`l0$YOu&MVVOVS<#Q4=98I!tbc{vUhj>Fo zwU-=e9hXuu3ve@=%}9%%c>*rlvG*NTx_YvjG1{F zf)Phfd5FWY_YDyyiFSiD13MqKx3={(dMkn1|C>o}GvsUg+OzUMpXUE71@ERSS#G!@CrZthOz9)ispX zvmy$fg=mWvrfXHKfUk6uMxRj7i&7l2xT8HhNQ>LbxOW{XPB&SRN~qzu zL$a36M1naG%Ou|k<9$JzfyG(_Z-LR3O@G7G5CJI|rqC`G zD(>Ep#C)c60L~mhSzSkdYN-o}2UVb&EQqQT%~oTOsorLlsRhOn3TkJ@45{#JzH=o( zi2e@bElaXQ+!REtt1@6pF7@(4ke_@5g45{;OCE?P7>AuLQM#j!HEz#IO+fZVpy8@K zq~`$LhO1$d&NZxwzUi-?t2aVF=ohapt{3)sL_m8o_=k-_@N=ZOa-DJvePFtrX2nrf z5O_>^z0iy`&+3O5O}!`dw7jePuM%bl_D|Xkwj4LzCaxr^T;TNam6*mRa$(yc3~)jX2#>vb=^PwB98s%tIOS1JVKw=RZ5H7W%h z4m6N6UASBQQz5KeD>;jJhGC5k576lHY;uek)AIJrkhnd_>gDZ=m{T-DY{|ZYuKtb1 zmytKhv)%;-PXdw6kSG?t$L;9y)d=^yS@gX55?>8Tl~IgIHsYNr`n@2VmtWmN{KC4@ zC6*e_Jp$`AkelXu4j)yE5!ZQ|9dlzKY}tpL9C*I!RmY;=ruTC|>Y5{b&8!;O1#j(n zfpn+*JKg2dWpg&wb6kd7ITCg1B#AxD;4M6>c`yZ1`_9I(Qv z(YW`zQUMzPzMRsv56mQ_*cj54P=ARHntd(T==a8m*q%#8 z#uk;0m0Lu+c|zsRy`8RN#-alWJIZ+e?%ikuu6mQVy?vOP&N7+`gQxe_d~Bs+c3skFE1RdFlKhm~lrN;wey(Ya zmTzi(pgptYRR@DsEX&1yn{f%*eaFRxt$iV`72@Kdx+MlL@OS)un=^fd-KrJ1eI<7 z&d_R<)(xp33g9G}a$3bb?I(O_1+dz~P#1E(zpRYvgWhM!4Q2^Q8E$1Li03LVlY|RO zDmg03h-dTu`hcetkMku$3jSZ^A+CaTF!aCrVPQ?JfMjqg(|Zk-g5L^Lwi+ERI`b^> zr>)J@I-UEUI8iV=s3s=seHv`#NS1iM#Gn#($+85onf7glEji73H4`_o8-T6zt=W7> zWjlGAeO+XWEQCwFyzexISQbDa1BI{A&?arpwRrBzwiZuiwgFjK9Q7?stVwaAAZ%k6#sU^f#bUcL^r7Rh293-2QveLruOA zh>PoFrx1hvoJcKo+0NT@hL~5I=#c^*?VOZ>k2(4$+sn6_=J~G)W?N{vynrkPGRhTa zTnEb#*aUrvyMUwYr);ByU4TWF$;u76(}x6MwEsue*9D%t^;{gr9z%7`Ugot0kin_ z1XYWLoLlkWqRk%P53(gi@H;drK10trmvU0dEkT3np{BjdXvlq@&#kp6vT{ZdZa*Hm zNnhAfnAn{2L{2KaOKs?xfK|^Vx_f|C@T-9PUL1{{YglRbTjcx~I{jt-FN1Vuh;BIY zZfelCh%*n@+Aw1(59~9`(!V@@TS4n2P9cD43zWz%>jO^47ki^sl*;4zOc3?cy{^2t z2)vW3+0%qg{oii1?G5XtaFa4ZlOD}uGQg7_YrWrW`Z9~I!)_Y$v^v1#hk|Zi z-%PU+p|Tqi*cq%ziUpWzbcbS-6lz0}JcF|ub>lIXh0S3tfy-?BH!E~+=sHfYIR4oE zmZHFuA>6TW78^tZ9Mm(gk`vw=8~^#~!h)BtcM?h$3G21`B&DsT)nMWcR@5O>F8S3G zU`K`ezlIu(Rj2rnhp~L`RdjCdV2e*ncV!mo_lqG**q}!eSwoz3GT_-?_Tzw{;+0ye z7V1lnFFR0EKYpfZJ|CXF#<&^i7qTtCoO&s{S25~i4EyL9tHbN(mmNl$bpzX8w0toc zR!w{*VrzVH(2`fC-SI)A8yNz;gUERblg=OXP57Dco<~ie4_ZrzX=mk&Z1S8BuH#k3 z2w5bY0TkvSQ1?@UV37=;P^E>F_-TmLBg{@3N|$3$DoTa0{NrfWmwD?m1Dp{n=c_pwNz_rDY2|(hgpzbLYim zbT?Q9<||mo;a>5Xkh6647~uSWFV^?W5w(nzW?jXs^i)=|z`|f^{+YE4E+pMU&mjCG~cY5vkD$e`+ot>;pC)+E-r0fPg7&qxMh|raPv?%6m zcT|Q+G@Xp>YvT*4R4|3!ZFhZe-tQ$);az69cHg3YM)xJ(kNyXjfFJl*xaYe9>@KuA zDshaN*JY+*Nyycgm4>(rx5^h57}9f5U2{XkZ+o0f5&b3^0`9uS#vIl6!Fz0JT=A9RHrzJlP51qznX@SMX{QJ-DGz5JEHjr`$ z^(zi*5*=EEx3@5+ohcd_p)4cSO^*X9B)_NXr}?&Pg3ASQCz}=~$3&dGk-Q_sbNu2) zkMNqAKPk_kGf-SLukU&`=j8@x(@>N>J(Ypq=?o(KI#g)6w48<3>NtY?irozBS@cUP zO$>Av8e;a0GyJ^LBLlG9SFz%w(u*N=vmv}M3V zlko6UW@c+|ZGB_9W+i3t>T3uc|t&;U=*5oVKM{P#N*yVN1JUrEA8@hJ@5__oS@1u z8_pKctB}X1eOXq|%{N|t!SBR?=m5qQheg(>Z(0j}U3e1fd)Yz2vh(bVfLxn|_D{3u zm;qA(6C05v5=oLTx>Mhf6uuFQ8soxL&Z{^9L@^uv4BrCM_@4S;eIqb3-j==El`k zGBTcrjR9JfvriaLQZ=!N2>K1O-7SL)s_>QGYwS!}b8F_o`kOpM*QMlnX$ql~gJkL;S2*%b$h!WgI9Gnd7IG6Bx$>a*A!Wn&ulu^7&r#-1~b zZc95~Gv>?j34`&$XI@Men}d~84#ZD7ZigWtE33wy?RT-R0CiXm&t2sE%uEUTpWspHqTZ6pKWeU0IJoO@5HRccEd+vCUEqZe zFXo`1L|h{mdq0|vsPa89C*mZvkR_^~WPg@0yyhwv!gQ(=RLO$-xh33E-^oIfzx6)* z+5Yon(;B!VYXhukLjsuZ)7*Mnw|{mvvrs6%qJMD2;)f%9dSkjfdsI?IztYRTH5b=P z#hB8Oe!HO6AIQfFH%cA*%{?jcaL|(oT4aAb!}FAs-zXw?VmA0*Lv=*{aRvOv@Re}6 z9=p4b!zl2qnd6iOPVdxW9=wFrFh>AyA)I}_Es6?b8`8rYV6v}kA(Qtzfww_%9V3;O zcr2gWr-&u|7q`GI76$$;>JkXHRf$47UIUk)bYJV}PEf^ZLx@E0>iCao9+B zJKCY|9kx2-|#Xfl{}oxR$Pu9WqOf3;osYsjG4{Quh|)@PtP4M39soIZBDrl$7)R_b9Z)| z`r;VH_(S2Fn{0ILBgP1>)S%5)W1NcA`I5}(Oa?Nn5|f>Ow99k2kb?t!lVo@+6>h&N z(iaK+trlRW244`tk0C;2(v+^fj=W`cUfgyhyac`dAm(XVM}WxFx^M2 zH|G%pu%vj*u(jFf^K`pOrnsGxA;D(v`7padH!Wiadn3e3ENO<{xfqo>*V(t^tH004 z!Z%A@j7iqMk*O;m!!Cv-ob7?j~N8?q1*!2M^x($GQf{5C3 zsMTO=nYPo)eDrxsNgJPpajWHXAuF#^mJaXFtYhAcg}AQ#X3bAkU^`s4SJS(S5}jcwAvfr$MQu-iBkQ7D#% zj9E%zLJcyiZMHJda*zS1mu&gba>TOBaIn}LC95dgER-MD5o16`$1rYd;_?J1RG1P! zrsOdVLgF+zS3S)RlDj+=Ym{z+XSHV%HS;$k=L%pcBVZyY0@$^HZC%d%=F1Fomd^Jn zzD%o3aW)b%te^(wGmX9RW%G=hSNi@ec5y$?knZU0#t^~t*@5#%WQoJPvrE=;U90QB zV2U4esOw5j4NZ(5sh*QT_gsz%h`D%o%r)!(l1f?PuIUu0HpZg=ZIJY2L1E8 z7Tb=(_OAUE#(3gH(PH71pZdwcu&=#ojL-J?h9nwq^OM&CKY&SxYSe6|_<>a&*I zsW68S`V+5>pfa(`;Y=hyg?AdOWDp;G)zf@L{a;>B`-9g11-&}a%_rOf+Sk?Ctxtrm zd(9I?uYHbGTwn#~t=P{(MJUAy-5gCwZm0#iq&S39(BprFPMkRLamfxV3%AoSMvy~s zn$s?XQ(tw{OdpDV&W7Mg@fKPn#3<*GyeB>|)lecWGRw3)xTaF~uzQo$N29620-#Cb zSoMBm#1-!ZyOLm{Fr(9lzkJjtvf;oMn?&hD~BiqYs~-D6k9?5*Z%{ z)9y(T(isr+@W2I2=y}BBe<$7X`V6L0JH(N2V*URC;{VSL+`oV&c%MI((6U_0gGSBI z&l8fERG8EoJ(smh&)<_oZf$MBAhX-dNb%5Nsh|jgBy8L}qmM7>VQNB8H{3vqw%B>R z%@=H54>sf69?kzNObWDcc5~RaGBMFmBsUb-)ysv{^iYJEm9HhGvoO<$x}Q0etIKE= zSZsEF*Qg~zC^Mhpu0qUQp@9AF;40l=4=<(q;OMdGofk!V(~(!aZOq&IY#5grx(}a& zdg^*f7CEr)9t92gVb)*S!J-6P4#X%N8DX#ISiQF>JLVSG!dk#3kNPfcrm|3IHSKn# zDS*>I9LQ^6@9K}eY|UxY$WXZFL<2rJeczhJicVQ-AXyorgC_xM<2Cn|AJjWpX83|l*-^3vE#@T;^Vz%vGqS_kUQeY2hdzy0 zB1TLXj}1P>sRYG``p9p7*K8Q@Pb--G>rxU3JoNrOl}gn6JM{xj8Jo#Gq{{QVb{_5w z1ni!WE8h!-dPp`FLXC!~IWqI@z`GCwgpCVl!v&5`u7`Y>ee%PpkFoOKeh+cX#{4^N zjsEFqc@2Om9`)Ad($;Jk&-{E=2l&WQzl3<-r3JpQ+@bWoeHOTV=G1K~lw!t|1AfI) zp>SaRQOJ*LXFTW+H~)WQ$8P4Ka2~_#m{I<}x_)Rzqt_*I-^uX>eJlq31WhSluv720 zmkNf?k%K4qt1gzAP0QNmWqnpQ7wjNtW|w(_PFBP!)eAh-xN20Vq8AJWH}{Kr;^B7G z3L>)KQLF90-cSzkahY%B9TjKcv)Ecy!Y-5NcYS&h$b+-?n06&#o0(s#nbk#ar%UCS z1RcGBQG%7m;(?)j;Q$50E32f3{k+ZqOG-u1`~APuB(b%RF2|!$dOQ(9?;+iyiG)SA zR_mvS)^(XS6kU7j7G#~*#}dE9jh%T@UU&4S(5vsM9?jPKF2Qwvu^S%@S?7`=y2Uay zDI6S0Ya6BPLD(1lT)AJgsV`DhH~Yw(30c|%47G|#@L??C4XiRp?Vle4b|RIoJ%O1{ zc}%YT3Ihhbj&bmflfEgMgCx|LufuvVr{O;)pd z!AbC)-+4(8Nsr9yvTaTswp-lZsvv9)78FNdEe!)>(g}v~sPOgz%UEb4fPv^X0}wTl zQME%2J5e4}5_9$b(@Y)m7Wg1{DpaL3K`a&q!G1|+ayabdHJ>LvX9&J*F=I+~=B^37R4BVgN!O?DC@!j}VoOR56 zLUFq?;8BC=q`geL5y7{yk#b}m{_ z1?`zT6hH;Vnct{*Pb4Q7#@22yThDBk`(@5#uoh~yvHbPoS#@OFjy0i2j<%!b z?IX9vu_ndg4V@Dwjx~>sb*ya>581hxONi0TJS64sL*VxdhMIb2XFr%H<(JN}w z5dnT(gPP{&3jisBHG_`R{Ezqel_Qk+o_zlz-U5G7FQTU^8Kf|({ERD`UJ9TrL8as7 zITef{VPnu>AZ0HCLDRQY_DZn>AC?-e_68 za9BF{ER-F}p4owae+5?+@crbxktJh|@CKGCjSbIR~6bBB*c&sn5^M)s3()ZWt)gz)8 z@By^SpW7F(S3U&5N1s{k8+GpAUMPB&&S-!zKxn2HJ%@yH#bVMy@@Q;OcWK645DG;? zWP&HZoxYJd_golOIQ&$;_LSSr%eZ@)_O!k&?LR|aGfdZ15Pz(tg+UZuSx8?*I45PA zOL0NjtANXMZ-DWh`rbi*=oQ>O2pf83^#sw#Uw1bjqXS?s)@5k&J{@ ze*lYt?7Lm3KPUL0gh5G`HIGC+WL@To%+6hc1m`P5yXSx%ttP>55*P5lR#{UpKAH&mY$(!99`jJvH6q(t{x0t)yulSTq(fOz93#AG; zgt<9U^~T<|#jFs!9>zM-ib7wh&Fn3GowWBCBa~{C?mQA zql^|rZ};at=lt*aa9_#!cE7}sncwWa_S(;S*0a{$!Ov9{Zd|*2jfjZohT=0h4I-lJ zkBNw`1YIEp{(}GP)(!kP=d7Xdn5eLaZV~w9g5@KXM?^%$ktBzv7lGgJ!JcWT5D|H? z5)r+6OGLB}{OQ#K5s@oD5fQ=;hP-|g)M6+rf5(yN5uDbX<~{tC zX`tya&87GBPtBushc8f)2^sClXsYdu<*I3FuNf-)FKzlI4&?T1G)y_8Y8LmqH>H2B zw=qt&zactDeBsKid$O<2eql%vL>+zk@7{Z%hW)cTRqx8+-#i$2&y{l^*2;5#_iV#E zw_t>gi!Z(YYSb6z)Wa4l#_VnCCvCnLrVOg^kF2n{zN97p<9vZ(A<~Ei>0lvw-?qmb z8a>vhwYmuq@6~Ec+o7Li3JZ0QEIwjJbIQ+uH}?0nHCWPgL)z6LS0-LIox8kTvsAdb z`4nXRSA#5NxiJsDcQTm&W_Dfr0jn(t)OZxrU9LT- zaA=+S*x@&wCD@DyAw7@*#gKltFoaI?=_l6Pu#g!!EN4ZsUl_++R_I%;-<)^Me&E$> zPf%)jCrrh3pRfzA##hx(TSD1BPA$B=v#RJV7;(|W&ab|Bf4rtaJb7rK)wI)ObA*sc zDgd9+Yny(7t4F!Z2Ywk+g;s=RmNUqFA5?uf)LJlcNN@jU*lBMApH6SAUwij_hp5S< zI)3|wGKFtwcw2py@L#N(i?Rtn3>>wRHy6$Hi!3<%qjU#Y!zcW(tqPPg%ynLkj3wA* z@F5!1x=NGT@kx{6^I!}%>7KLU9@NwP5)0R}@<}fIbNE3XJ!KM}+XGKgoeWG$Igl3A z%b*a{uO-G~!hmv4gLO(exIU+65-NrlBx>spJj!vA0HHJ6uU-oUmyf}2RJdhGT1?95 zuAFvO7+io3tG=uqT%Vj#)U1e4^Xodx@MUBUU z0#pJvbFGRfXb$$icV3a+42*wOFjgj|9aw7qt57_o?uim9a-7F=c0u1xu3%K`7sph+ z+k-y=$%QLjsHXfD1QV1@F=CWCQ@;GM1gN6xc6nhDsRT)H+2b<9w8anBlPvoX!X?d{ z0#Vcu*8?jI!fZ!_3?-Bgc`ZQC^vEy_1V^TivIId@5;6*%o7mlw-%vvg7J`oDw9!Hz z^q$D;V)L4pP`GM3b1fJc{{wH4=Oz$pf=|>7LmC8?`0B4zz1}RiH^35au%UMHTg}0D zOuus6DU@fXQ@_&3W^28o5(9CtsW?<~P9J$Hbyord3+1V#w$`^@kK>u_pW)d*-2dKq z9BOV}7Lu;p^) z+J}Q;ZB;B@OxtWlNw@_8UW!{O^??QsWGe<5T32e@1fpqO7Mw?Hr$IS-*LmH#V)W-r z%`aw38gj?9=-B+q6YelsB0=J+AN;fs!a#fawQ5JvK@VH0VFy*cozKwct?-%-9Hf_C3##h6^&>5L4c&ScEmQsH#5#MW{ag3Acg{e46)9G0PPHIhuK1iIseany%Z1VlI!E>EiT^ zn)GT_bcEF0+ck!I5A`znHb&P$M+M>0VsbkL25&jrlL_*Oh#BY@NV$Pl!A4Tz=M&fA zjh2D9<0&n`tbnv=pD| z?3n4u7K=7h$-N6HNL05`&HgR;NQsk+N}Ni{y4y(;VgPzu5sk&Es*h!Fiz6BCi$k`% zb-;nr@iSe|!mPLxM3u{R)XR^x#yBR$-B|-6^+if7sDyA(xNDpv3=EpAx(1pZ7AW$w z3u&r2-=(-Shm-gb-?)Ky)=u`_AIVMeoTLf=-7i01Q020ht!?DA<%%wB@WaW+8+Z(f zS*BJj4-WK*uKX6H<+;-%>OHbSNhMcjwH1y|^2{OOtJ*zu)_%AF?(7j;85C3#^BhrR zOKmV;N48m}E>@98ip{mGJtgKaQzW-mj)Qn5+MpymEU4E~LjooYj1!r|tFnJf5& zPHS-auCk3Pi-w#oI8THvHk35b+_XzTwYB0&S|=}gBnW5rvK6(dE8rTlhcf7aR9=cK z5zrbmzq=%_&vgKuaI%1baV7e=(z0++tItc^Ya?8b0wUinx)K-R7=GZjI3Q9|Tyqp# z-{|x+o60BjkaRnLI zj@?c}v3=6H+M)MP{=lJ*c=>mMU3;A4^~H-51HE=-%OZ?pz7E~3sVyL77zu*6?iemy91>$x2aoc{1849vx= z&p_TG|9sZ(>o$8NP9~;~CQf!4PiC&Fd3?<&nshli zzZ1!<_J9KCnFQ$(-K!sK&<;aR`KvC;ob7FM!A-B)5E)-p0-0o;X<(>}D%Q?r@K67UA*4VCn*8ZKGd=?Xa+9#{D#%dc^-}w4>e%O%?d@OXH+pV-KT(5 z$68&6Wr>*@Z}pjqdMd7}J`=nxw*swO2=}N6VI$T8sY2y(fD&Pk!A@+ihW+whz{y z&Wcvu@3NHMjH|3;5e~A2*#4?*Jg8;d{juH2*YE>CO>Kjk>AKJ!iOoa7j0#B08&yfW zj_K?+M)!>e*93&Dx#=5UgjP1NL>%T@N-ZrJpX{Hm7~{!qn`7gI`;>3vKCUR^JfHVS zCzI0Fbff2bz?Ar};pm(s^V_hyb^4=0XLEV}CgSr9FzbR8NPQgOJyFkt%M=3XdSlk! z6XYzSSUZAyH^`>q_<;aq9citXw-06Y)2l4P83#|;jC>-kEweXxpKO}A!QQs~ZN9|8 z=5vnSV9wSuTqUryCEeO8>!V4is@4JB`lpYkAr0jP$%A6Cl(q4mOVjPR>TRdb1y<=C z$t)2NT;b&Xb*So1?RtOfO1S>maCTf(;zsv4pTz1>d3`4Fz(#0Kqb)ug?NG%k0PgkL zE@hJcJ^^{ zT3Ek6N*QnDG5Kyj)p4=}(re(=zsUA9Ap7Z~9F{g8_w~LM7#IkvvoI3rJAqzfW0Tv) zCtJoN0jEy{Hr`I6kd1xg(Kf=Q@V9kQ{dNcsY`=O~In3%cRj0)txXHJ*(@c`!9x<}& z4_?IG*Ag1DbU*aux|Lqceo6Rd;7Pe};~iH-VI#hV&u^WC?D~HA)NZ(Y-3rsUBbo^ZnJU;SUCMkeTdZ zzf*VW4^A;y`d}H-!{Bg*)}e0Q|G?p7Wf4G>N0;fLLutO-BWivd4vo{AMM3o~2v)yh zTg5-bFkhZ~n8EMyYV%ibEj;+#+hDBk+*Y6*pR&K>f3g#vq2zx&KcC`mw0a8{IaHue zRbC}*JN&ED__(BEqv2rn09WKk$+cF$GwI%VFj2ggc07_s@7Cg8SZ$Ac7tbx@zBdAp z9N$Hn++>f@kFDLF_=eiq1%P3#je4P{d`H)`EaN19e|s|1zBlZ(RM7cMt3Yq-Fg)#K zqj5|wtm8=K52N2ykPWjsHn3r4;a|J3J>s5LJ2c_??f&JXW5z?j7_(9P+Lez#3TszG zXc$fiMaKlsUhhfPBwME+0hgtJHJt}Fj_uzW6EqbVJk5vf#J7iG z{!5j9ONxL&+uV+aRVpVv`m(v6c5_v_tUI#Ndv{%((T0Uk4?s>1AOK@SIMHMbLV`iD z4XveI+J%SF^T!=iA)xMB+M!oxV-0`N#TLZe7GA`I_zlnJwT6TIT8EYR?L)JycYY^3 z{xW7yK$Fk7RlD*kh@wJpVGS&lW$@m8WX3iEJyC%2F6?37(rQx;e^*;h?X z*OqIi8fY1GPWJfxq%$7-uT%Lu_Q_MVK35aN$K)0MJ|!}YM+*wDjjDD^yK1{WNS*sK`@gHhOxmnN)(iA$)N*jz?chScZ_7X@*ZbUQE-{o-2)%+-Q%GSf%c5 zSnPJFTj>b`84A3khRi0DN=<*zK50hJh@Qd}qxW*LAxXU_~632r~r`E8mqrNK*^U=Ri5qH99p)ubO5rpg=j=4I8nQQ-0pd{w-t* za!%|y(Gu$|xzz8A?Xe0pPsFHJjI&cnrUeJ?aT0A6#)WqS0JN-XntQ$yZ{ zWR&%fY830Q^D+)MSo&(@y5qDXf?5DpD;t zSV1`*6I>OnXA27f_9Q_d*Mn=K0IMuz<$s7Ar;?_+pEWOYvNxaXteQ+%F75RrK+^8o znDJKY+gIb88IOM%ALETNW%j)u7(p{UkP1_A$^1^gDc@tYKHXY;1kkOcQyP~#x~!6< z;;B)6g_6GBqi>y!e&@?g{~sJ`dns%(iyi7e7vIy`2hl7sc>D-JjPWvQMcH}nGfEx> ztNBbX8J+Y7()$j(tBHDvXCqn=7AqA_CV#L!f)cR3uBq#D;tO7nOn}g%>%AuB?dw{U z=kWWKO{zO_cx`=qa&x7mlXuyf<5OI|B10o3_J$EhJQ@mQPy(G~h}~(b znBqRNn9%Dr7oGYWAp3hAd_F%(D#y(_{dWWXgUmHAApA~l`kmOVc`Q{%?r%TLjqbEZ zKntntAN!uY>xlxcUbFrEtNG^C$SUZ|k=@f*r+<+fNgonPI+a*o*Q%M8`fg9mZ!?bj z&GsqS*R5lso_GOhOio_e>ge}7labzQAzdA|c*DV?xps1^u(U^S51K>RE#C){g)&Mo~zz$yPX2}u3?KM+kG0)ngL3?DZ+(C
v_z=AYVskk+8WZ=pRz5inhqIp9=4n+n(!G@>EtsyuBdF} z$#@1#cr%XIP#ifh;n+rB)l8TfT_B#Jp5t}rjZGW(TKAbCsZ*-*)1A z-aOsK#orx{haBuHkK8K#PUg4@8>ahXA>EuYkr7J+KO9`!$aU|a!gGy0_1D|>2lZ>dYu>-UTyFFA zJ{sxus{n$jG?4X&7#eMt#HadUth9|AtrttO73h3hDkFA>L>hg61qAX+{`gU}=KsU* zz!x^<+i+Z7)O!znx$ZdSL4@P+^CwvBr73$3fwB_ztCq^zmkrvR6 zB`L>SrNS3psSPiLJNV3W83`x==9MKw%oU}(v7Ldl&nfwl$p-;M0b+nFDB_tg6j#$_ zj%Q?!zcQpXE_#dbNIR~F8gER8-8dRaI~qAYSYu>)njtWd87aLFq_W~UAG{aR1BVI? zYk_i#cHJ~(^~lLCAQcFv9sS-}Ygnlbjhviy5J9qj$f-L7WEcD%;7=q*zh39c94$J2 zm^wL{ie#AUOWhyLl?F1CgpH`N)fXDoVl|B^@0(;v5K#M1d_`aWopE@{%Z4Gf3*Y+P zqV@=|Z$&VTZvw*60s6pi3$r%i(%&C#bhJ|hFk%rbcPq2N6Mg$){A%r*Ul*ut8Q`q? z0P7$z-u zYszulo*2PYvh^Iq#kHpMHK6JbMJBwO zFH#wPUdol;3sEs%U!IqiU{VQhD@_GPF0~}@f0VHzQ+33Vo8mK2AYxQa2zk=rya4WI z(XJuGM`hd{z{YZA-i378#V@%7a&@+H{L?Hei&Gri+NMXj|A}@n-NVe<-;*^lxo8c_ zY5y$=@b~f&+LM(9SfsQ=Yqhq4Z>y__k$ZD@Ut!~V9BszL%g(LuQ!W!IoOVH#`JSS( z+TpJV#^WQI-8VG7l)eC&uA2_w0)`de@H-pWKD3^Ph~d@z(w@Y1=U~u{=e=_$o^my*-tybs(PK= zUA%ve7(xNm8tKI^ze)YJ3Zm7`7zF_o`!vsS+$fQj5SYmYGSB0cQyB^}TS|MjXa^wI z6JT~?EpD8|7v{9?&DoE6_(`Vj)Xht6CiET-$Q%ufzGQCx4WL0y!T#5GBqDawW~SEh z@T2`L$XM}m`QF^t`IslFzlO(b1zp}6wAY)-Lg)wbj$1(A^AqN7mUic+ydLqG*|+Mv&*rf_y1lo;;Qes)H)E3h{w_*0laxHLpdg`LH)jYK ziGKKk;_sK@ky*mS)p=_;A`5g|h z`wh|?&tP!w7OWHEwz^)~ix+JM?B1=HqB^nlN@CfP>Sdx9spzd&ppxNxk#~~hpRs?R zrGcr4wnoA3R|He2FM5*l_v+M8CE+WJm3g!%Yqc*MP1GYL1mfmgY1TW=&k3_&C|r}A ze36fE+q-zq7}Gdv$QO>WLCo#T+?I>SD}|TOocQ%TVBW8cbefrDO{A{^^QK78?&8ET zsAq7bh3II=#V{38T+Py}d(uyG)3jU?S>S`vY z%+;D+@>*TU0XoL2p+IZ*(4}mgYiL#xc0Yn9Qist7C}Q72*_b8ikmvT;YHg`sN*$X$ z=e#4TYLTV!DU3I+R8TQWR4k6p*0f9Ls(yrV55wi&nU+iC0rL=!aq&1hhh?EJk99W} zw=DC|v_e-HV1+JG@oRt+*0A#(U=-Gs8syQjs zBO2RCw?hIFE!Eqt^qTV~H3&JXgPI911v|6W_Ef&LJX4K8^a7l0bB{nPagO*r6ELlT z*B40uoDE{UC?^ECP3-iTkDLI90GLbO_FKj6=D}r#fw#_sfvjSdDj4;lfioLBu7R_0EvlL)U zSo+eyV(kh#c|V@a(8K5X!Iq^V8p|588)56VWnId##k1?BlA3qkp-4H^)O(UhXlhUq z*neq6w^Yh2YUzl}2kKMAxy z&b?mxyRL>ccN-nfQek^TMl;eX;ooV)sTL*(M8Aj3VWf`%(6PUEy7}nCKdZ;7guH9# z$Du&2m)31BeKfnz`Z4r|(?K4Ff+Wg0#Lld3m~}3xGko*8dL{BMEQH5-rXtdMl(ke; zx0^lsVbo}cfP67)9PCZkRn1V!SclDBV2Olsg6_b1GPn&WB1>2!;wIX;)t6IkoVLpZ z>h*#_@K+opRITTf&t;8^e4oWQ7QVpQO^+oL6$)8Eg(GGj+Q4pvXU9lmJLa&rh=pL_ zzFs=LZOO{DTQIEYoFnRdFY^P{C7l*T&EAHa{aJ9o`PAe+46JSBiJxu_wNzUJ#1QNo zWB;Qq^?T;|M&{t!z?IPc>$%1HC%ycOAssv}< zthmolO&kprCi9pbD1K&nFo(aB3#!u4WJW#IoU)i1(IKZ*u;*a#e4A{@%TWA0uJclH zL(RC7;p4~Mr8lM0xH2KxKb}i!P6)&cE37G2SBV;(pTchT#{!_8MpJ>p7=kF70Edx7=HeZRA34~Z* zMz!&s?_KF^+Por`yz%VNDUZOfFvZGTtHX2#c?THe!;2OGl+t9b076b_x3GS#+seaQ zoZF7*GN5@Ts>vU+L_f7-JWas2?^p13 zqle|UG-y;Wq+>6ptow=I3-Dy&2NWseUGp#L)t=@78Oiv9LD{=YgE)em^MI7){j*2b zMA8M6cVEphzvi&xy6@T}98M{WDvbOFo{eVpQ#@riNW2HD(A#1!Bc3-8qu6meV`UL$ zb%hR zVw+3v%$-(O;gH9$Xj`nOUU}APvEDAO=vk5UdKWX+2C@lA9X0Zt5PU@$ zxnRdom&|f!ntP<9KR_n|myYso#foYtgS=@w?G)mVI?iD%`f$T6@vsAeuMWL@exzk5 z%|QBgp53j9_8TY!i(t%UKHnD;0%T^(*=Wt^vTz0N81#qTy%#H{cA^*WAAHCSEkcq- zDrOJO;g`ODx_bTUb?dN>i+@tk_L%u$pqyvP=5g72f*c#-pf-b^<2&U(dN#~>Nta^X z5Ctcec;<5uChn+Kj=pT43h3`(=h!S&U0#xGuJT%W3S~uTFeBX^fsh@wlD^(oJ1y5NWWl!#;5F(z8J1`T1V-;Ipe?TmZiDM%_5O zASL^$?V<%MCPvdufSkOOW+7N%$P|lzR#r9_xPff{67yA_28v=e+4xKo)v=%w< z!%$aK`|GXSk>&*(VK^mdbxzHr5m2ZkTx3HD|D|+X-StwF)^^>U?5EJEB22ndlBh?{ zrwutzE4?SrvbD<(?ti!ZgrZBoi$)m=Ox?csobndTN#@Kj1!V1wBwb*jb?72mx<6ab zDDSQVr#0NDG`Tt-x^Hzu5^oEyh84)FugKwcRmIeoX%$|K1!{oVMR?agImIpO_$4{_ zwpxt*B&-Y4Yj&%a(;M0)Rp_D#hMFq$n#>BgLx{aG>IuG5vnxL@CenJ4W9czm4?Xwc zGBT$PwNWszhxd71u29~LGir6((u*mL={UeTTB{eJ!r;UgLS9ivCk31xpf2ninp`pi zXZxt@&6e4SCF#5m1em5alm)G|&ruzxm&*EB*s+Un=vcm>CiD|Z46}9ia|mCE9kOibf;1`8nrNb9rWnf~#2s4%E&QF=fs2(GEZVghiQvkvj<6Fe@N4 zA)(?Oheb-=;n90I=DYOrP-+{o+M&FIo(Te5DfiVQlVAM&+Q#T<&M7gpo#5v`YLva8 zf0`Cp?H3tOy-dyNf9RMK$xknP0LVfAUZLVIB_0R|!P#@QTrBgwo)wf<$9lFo2^VWP zAn63np6GJ1r-uAcW_3WRr*mJ>j4-&-(gI=ei;4act2m7c5__90!lSB9no6=~tLjR1 zdBnD~TOcKxKB9gjtlE+1_kf!V&JINxJgOCf4bq9o=%R^tjYP@EI*GP&9%zNgQ>Mwa zXT~y{GofNWVwH7CHIr%zL!#-qNQ<=>?Y2Jyy=3&NJkxQ_9MM?K1O8I?x=b?aXQ#x7 zskv+&L(8Z0`JNeg4ERzYB^~974i_m*^W5wX9Ey3@!N?Rw@D_VBPwF z>YB2cdNTU=XLijZ4_8rK57b+qR6nJ($Zc#ljwm3pDa#BTWdt6v-6gw3eupZ4+%VQr} z`AD<-%8c^QSR$zQ(siPBqi;6^$I`HOyerXW;Mc-LBsd0J!tM{XB@TtCcs7-&*xs_) z7_8RL56+awWOKLdFMAetNVj}J+e{<-H}zceMw?(e!vgNT(C0MDG=^bP5)gK!`x!cn zTqLmDnx<$GwMRXsLoXBK3%hl&9-9Vx&pHw{#Qb#gw%LRuNDO^l8gyV=Z0Q>|M$kf7~yJxNJ#y8{c@WfbJF{KT7ff>cTo;!#yDyR!7%oIcY4G2U}pIBN>~hx%JaJb;*oF?CTywllOQz9XTEyRD*Ih_nks+LB9H zT;ptbn#B=u$JiO1;F;LITLLs@n0>##KRCyXR;3xz8_0|K$w9)B0qy79gXZ%sCUliU zBjc=634lHj;|{5>*7>w*`t>`4EX|8qD-J*{$j;#cr z>4#OsZx~@AVtq`u4~JZwW{6z@b%f69)goQXsg8qaXfg--hQroL?;ta~?#ruZ8vvWU z0+iDw*~)AN#@V-R(}bX&W@6~I#hwPgFT)^|Fxht*gP9dxu$FSb@5kwL@xZ@jjgEBf z1OJB_n>E^V^{5L!0i=`i9wC)N*P>eY%Y5Bqjb4li6~@z23MMEdZ!5c7P9E0QY(qO3&ZAO*W2n>?9K>8fWzpV zTE}VSw2bnLI64HR$;I{#{2&_3oX&)!Aa7Oynw?^knJ`d+6msrX3bw>&VaOIGCSQ#d zGVT%y-O^m{mJJL_K zy~kXzr($seHPn6_9MA#`Ab1I=pZ=W3>OE4oW{0U2Kc~0Y=5L4-wNDi%)uC6u!6urQAO#NW`Ybfuh^(%WK@H1`m0(9+b=E@=?f@2^$?91vkn9%fyeQ zv=7Wa9zhGyKv1_@(>Jn;KkOw1J;f&`r*f-OSOE|fkThfsUblT8FkM&eofE1Q=)B`G zt7DclEO0G&_jQj{lUY?;L}xGkua6|SyfZAi0UR`##Nb9EW{dEHf>>qRzO6fgF; zOzQaCy`+EwNmVfb@F7&mL&Z=Iv!dY!&8pFCOp>#^*b1r};cp6GXp7UkM+9DfnQ9NvJKGS8x#vL?b8yg(S2{l#2`w|UJkW=5`K z4FHkkGTqCju-bgXS~sAnrEvqxHM5I*quo1J9Vj@NJt<~lkkT_ZWB*M8)<;f!o|!)n zkmqLM&M%9ZIw(rt$ajt`iA$PwI#wpUA>HZZcs=-s!(}tqy3E3mc8aMLT+G7Il^0p& z;!s%4O2rrxY|zaFMtSaTrRej5^B@}y8zrRIWOHKV!V|l;Wn5KmsF`Z^3HiB%QA~kv zlAeQ&cljOUUH3N?RA@U(OuaDxZnB#9SnX>o_H?S9@b9RMs;qIS!_!*nMfS7Qqf-g@ zn=!E6Rg0=EORWqm9_^?&&&L)%qhPtQ zTTGXos&|lVid=q4^K4o3(#Nkr2Je#r7eh;`+K+61wv%|yf>obS?-z>`0f_ak@DenZ zv~1#@s-DUl%DkcG3L`2TAW{W20i_JO#q1#kAuh3~nc??;NVu-J7@AlBr1LokdAR(K z9BzeFR+tD*PB|-7X%txl53VyW&ep?a>m&r{4Ob3YW6i;mN*f%)?DvzdUxnY|^up== zL=NEq<>E!RB(6ta;AyerT-qpUomW8S`D}-gc>ya!8bdMHtXo(tr^5)^Za$NZOz_&a zr~|`&iEm!R#p2IbUM{Da1}#`F$s^tF!OY9iTD&fHzDuUH#{%EZ5&Loi9frA7s+DKU zGP0jEPZP%|Ud}HuqK~*0@>n(=uD91n6bn2NB-7)>#X70DDwXR!XH~uikKClFHn^?K zGEWi6+>b}6bcm`m@Z7=X!O|1+vGi!)Jo|)B z_!ZAXjalSfqL4S{?N<3ck?*u>3`xh*&*Sukxt_%)EKiSW=GJtYVuXu7ETL(kZTc%Z zwptRlk&Vw>B4vAlD7dwp-3R)^Zb9TXT?dX4ZkFQ&WXZk+yQqS}TEvRgk2oGdYm!<6 zrpGkC<|Zz4xP}3eWe0)~2j{I2b>Nr-*5PNa6GrcLo(nJu> zXAr^--G89Hs!5=YeW#-v!XJ*?yPI6WoU{x=ELh$S>=-s5-#CCS+?LxrqvFDdtBl6v98Skwpq+1T|3q2}*D^vkgIguYAW z{pGHzx+&@ANkjmX7Xz~KqeywOj}`^s@Z zufGcFxFC=oeLkCw#Sg04J(H!zJ%6#A1gaHL{)nM^#S~4|DsYaNoXTT1N}i6qYzw$Drelr?4YT)`t96WQjw*6lZM9c%+L(2EO+__x6Vsz?iVb8xe zgZwXJB0d7extQTO>s$n!kHOhhc>Zj;`oBm2jUFg-xX9C}w!~6|TJpi13mPwh^-U)xMdcoI%@M1tr^}*Ziap&Ge zy7ZNX+SQsRyUGb+NMN`elQ@CaV8E z0e*gB!CSBpIPIGVhi5Qf|A^D-RA&%>|joESmEmbmMaiiUnV-t0wYr^5)-#C&K z6aRVO+}p3bw=fjkn<)X2dGvTr=+mK7{J)+F+$e#b`PAC64_FDE{AUWNX=F7|j=gwl=N z>#lfHXU-ZOYLZ;9nsJuOWdn8_%$n-uKahxjAOgYm&us;tmEXU$eiyVc)-{r48+<&- zsvD~DgdTMaW%KGpsNeBNVeAE}Ae=m!?!i1WW86v56)=(jttFH{!S$=M+=sH-qa)Bl zjj?&S50=o!|v_v3xva|H; zg8Kge7~)X?O%NzH`FYRtxcgZGUvvw*s{5Hh(Rd#xxZ+sM4W@3OKqF|KWQnDRy{@>< z8C#~pg9j4(p4hE$rORg370P2H;~NxsWHK9XEmhzsAUJP)#_cPz^i!m8U;KdT$U;5U z?V-VAqinYFP{{mc&mm3hHML@GA6gPXr>dRD3Up~maGGS!dnRDBoXXLV$0lMmk|r1g zCUM*Tl7kX(+VIcrfp9q8jn_(os^ywkHh7~Z6u-28lQTnB2n@|*pRKg;!e^2lc!%0b z;nStoxD0}3aJ_&|bYGeW=QROMXPIJy&~vdJqe?G1-H<(zT2c;M1_gm3%;qx8L=?uQ zcc5F(i4Tf12b@Bcvj&87zWssdyq zF^CMT`W`eT43r*u}qzSwNfqgKwFj9Ma72>S3Uh6q4TkF{t^>0?B_C zhQE#YhzgbnyO#^}t^Nn$|NX`PYGVFFB>iXP)W9jB4j!Oo;xFd$e~i??O(#2l^H|_L z|Hqq7S`g#s|8Ct}bb&6|PO7HGKO|WHJ%6AGdGk*M4*08YS(UZe9B`cyn8^z^^5%)O*|iCl0(BDaHq|{%BrYLfDxHajmsiX z8cZyT0J@NWD^>o6-MWZcYhKr)6Z}m&%^r@dynr>-_Pe}LaJ;Azc@>bw7;xUKlSr@p zH#LIKiPszB93x}h*<|iqCJ@}{zy>=Wl^jVePFrJpGbUL_Ot;*ZQJU!e>`LeH-Vec* z>tfPYd})Q-@9+3q|5A8w)L>NFCsGtN^4ztnkYtu`1!v!K_oQ-oYe`^)v_;;a>ZR#O zr-P_w(}#|mSEkV?A_>a{@B;=ac7KoHF$spyJ3NGS(j|uf7Kd$#DkB*u{iIfwmh_I& z!h=AX{+26Cj*F53i&t9aE!X?m8IxL-n@{qf+n0`$yNd)lX(BiwH6wgBvsViiZ{A9TE)-e1(6cSSF^rrP&2k!CDcR$9G_; z4(QZ3A5!tLqV7q_hAB(0&6)+=!;5+{dp%`s4{zG+h}~)Tm%WXfvBxk@6wM8b6~(Ndh)z?AiT_`^R3VK1U-(V`UrP zrWx4Ry|45xq&mW{8F{>zpH*uHe~?g@urskz&`f{9`sDm-`IYICA#)$bfe z`ZB%Ghjz>^ds!^)PH>&1-lkHgE3o7Zjd0Ozx_oHZK(x91yZk`Kz$Df1Wc9kpYRw^@ zhtcBlY7cxNt#ocGr}GB6f8A1A!;)3n)m{4hUf$s_x5}>XA5KbSP83|9_Wm%rV4=~( zxG(V{1cZBuof`M4k%{K}+8`dM)^I>@T3nX9xS?QLT|aX|Gh-a!m6^nD+-n=J{rNCc zsqyD*tkps1_2krQJ6H2d7pDCpWJucz7$QA(3bo)#0htmP0vK)~2B-&s>j4tJH*A;l zd3GpIFHL%{(c|WFw{=R)gCngi2y-35ann+&GEBLYcS2wb{t8yKmW-axwY_KEPc; zNmS@3MH@Fbv83>zFAkzsESN!e_YzVytxx-FK>~r|Bh168vXLZRz!h7-tp{E`&Z(t+ z3ktIdW=9ks!9e$zyc&2f-7|25IqrPwPSjcVEYs)=Cp%~M&X%`C);rLmE2IwM$PlhVG| z`zx$GX&ADh+PYh6o_RVc;6f+t;fGF3vGwTsm0dW3EHEp_|~S)8qfs zDt8)(pfcZk{h@=c$D&(<7f>h6^xp?%5Qw{(^_Rf+Z0^OMs0Z(egL2N*wnzyjTYq|R zyg##+B<1RQsa((u{KgAzX=PvrF1@hyxqx`j`Lj<$65|f10Z7fB64)0`>6a}K(z7=8 zG3$X}4jC<@ui;*z8kOFCY^=M{b+=uGQlQzC+Etr(Z?p&yXrEbJ!DjeW0%9oV7EL=X`>; zb|d5EB*^@4Sg&PyFMeXIj6!pMls2*Vk>wWaa`&6>$0ukJ38eM~R<7rM6i-K)Pkg-( z&41sVVCx*-T0#4hVf~*@izGX#Pfzx!b^FME+oILHY+=x3-gerVThGc*1( zy8KJ>|4@>-f>%>^b1T^*FNrVg>zNQhIbhb-OrgNvqu(2Z(?W5)3(g8hct2K8EQ7wEMoi0a7l;tmIb(S$6Suib<-XP>z+6Ywh1$ z+jeV#BLE3p!4twI@0b%N(pu(NP@Lsa0kqBk1omK}i3_p@P&w2lo`|1Wqx&DyWs*n? zi3G_Pva?2ZwrIF+RP~g$%2#l>2P-W5ZI4)nf>btdkEZ<3yZ^)7{y$y-eQ01VOxez) z_xHKjP~F+lo`>2cN}v=23iFU*$jI`KH#bvlKLRuLYh3xA_E%5TG|@Y4B##{h);7dJ zSsJOAhO|>cc1ckw0Gt%^SE&NfpAPg?#Xi*Nx}~imB(Iy(^D|4Cw>nGildAY)mLf|6 z6qeXqnP2=jw!fa*)pP{Z+RbWw+_fjE}i@OI^o9Iv10FC696S|?P%Tp%L^4}~>J)oVxv z8g|=+g{e6}B-PkEEMevE%eEu_X2|T1$G&^M^=<_B6J;x(viqD4AuD=L>&7IfjKh#e{9ho>+!$-$TR>Ly0(rv#~w4*_a)e0u@ zA4ocX3c7X)xU<*cuX%qc2bjzR_3gc?1*IQ~>R*L`sNQGVeEMis<@>egZP08HlPjoH z|B*ZN^Yjf6&RwgZulS+#`v3Hjvk7A1K92E zpT6-oyBH*J#G0^u{1)h$eSfQufg`%`V}J2v1s~|*PEdSV`;m`5dG@(*`I+w?wcmgA z^gFN^D8XO5e(1Pe2aUjMKj5Ol9evdTUJqmt4<7!|+JQy({h`13(?5&+N0IKIMgGGZ z{Bx53unqs1i~rcwf6T={=HkD(!hg)gKjz}U1c3jTi~paS3!%>6hvos3Vb4Un^bZE& z{sM2eCzDH~Oz#0s6CsD&O``yV&*H(!8B@LZD`SrI6pgmkv!YKRu*2OW^3 z#+F-`T0OeLn=&=|znrxH@rifSC_wvN0(3``%p{6Z!8z-{&64ytxFPKKLWn`kNHss6-Sd>`=WunWLST)Zy0v z2s-}9tNzdL)UKVvUa?3zm|_0gd4fNElEW#9(I3isj|f8kUB3OX1kuYdqDk$KYw&l^ z|Nog*>OcMJKaR#fpn(4z+5aDc0{%J4|D5FiVtoHO$$z-te=tOU1TO!Wi~on_LTKdF z5dnIio8O+=YNvOy_xiUZ;$Fv!8Ek5Z-(;dq`zBM%78e_6Loo0Ue7`OD^ybgbDII|` zIS}MaE%Ld{lmv(6rpS%n(i*##(we!gxQ?p`u2gTsB4*!FhR&#_683?2ix*2X9_rFM zs2A50=eMks#mO_u7facqu& z`ea+>)Ri`CnOo$T{s*#K&*P{NB`1;{%!-L217=)-V{hZqnU_*uZ>%q-tbt!>heIbS z{C+i_om|~{kr^JiGZnb}Iy&&cE`$$Wa(Uxm^0Ca;vjPe7Xlad2NM7l%&(BV@7D@ad zqVA7%H~elP|CPx}fVT|A;HmcP=TAfEThFVAp{t_LV)D@vlekOdKr61cV8% zH~#kNZwO@neK23y9jCSki-mBMYLXz-raQlgR;(4CN(=MwJSQ}?+ZFSZ1_v?z7*?GD z3-nt=p>~W6SfvQKTkwo>+63wz3&`LIFpb!&lh6okTtHQ^aF@_0K+Mx4o zEzwEBNB_K+zAIS&=p*p-UEY_U3(xa4bmIrgO&)^(7U(>v`EK+dlz8bmeb+KqTF(W3 zaTh>DzzE;GSdRum5n1P zWD&*cVNl@=LvcXit5jZ;Ph+v7pIi(&mv5TB{TKiGpOEoiUtB=ntwTr2%(S-h59x82 zYg$KvH{u|yHO|k4Oh)Ilv+5j&TCtW-^0}~GZUR_-N##mjeGArd*fX3IYB1LlonPjC zi>R5VzAy}NERzfqvZ|b}u)WM*uNf+=r7CQMFNrsoE@H6oX&ERv{{pdFV6yL1yKt45 z_zSpq40Ueboh!ZjO7Ii_7qy1k3{qPmv-9*^xN`*Nx0Z*}72R;s-iCJDm{{X5>7#99 z*}F-CB>beY8#+Ggj;=oZgdaIHE9of}CyRGhZ<-e8WaNdOhxQ-cAtgJ55S(i;t`04L zs6&$hyF09$A|GD7%H&{#H0Ke<7J`kxVzJZT5!i#;40+HI3Kld)NaoxhM))rb#wX$t zNqwv+YrfcE0O>xT););KLX|zr>?7(=wNeb zpJN%g@08T0jJ!m*g=}|0zowQNkH<hCNvgZXQJ!HSjcX^cqwn-v|TZ!q{Pggb$$q z{?6mHMuOd~uC&y{#%Ir$xXZhy`&&*8rBhBIdk=193s~8WBj0ItL5LHmS&c?~vSL1s zS;fLe2xA`RtcEC2%6kt>hqGQKMDm){at3`8f84S@uV?w$iV-7&B?RTSNe$uqd7M zlYT+pGcDC6&`_ zEsjMnV-dkB5lwUU=Rr$V<8BefcXk)BOgsW6S9*5KipY&&QC7h90#+g7M_C3v45D&- zfkm8b)E}GyxqM$x5iHqHT~r@&wcU=iyVQUZz`TXEt_^-byD4kt< zb7Wj@AFS!C;{2HOFpWZrOb_^g#g$)2lC_Kw514ckrSgH%o2wq-By^|T%U2KJCinFJ z?&_3ygc9_|!9q3jxe$+Gfx#J5a3L~a?UY5J45kQRd49jHL)$t9GJ*ry?$o9{4A|$w zgzMSD%zpRg3|$h<0KFua)2i`e_cL>73z+Q#?V=Yim2*5Q2aPF#vp8?E#txVmj{)LD>H&=&Yh7Knx+U~VN>rf1n(k^AMbm} zENsjWXcyLS1kO7#hQGT@*JMR>x;SU7T?4wB{2a(&AXR--BH$~YBUJ+y>Z^qT`#a>u zkI}zZ;*NNvt^qL%fEX7rs&E@_Vi5ZN5t=@-SB05Y3IHVr-f~D>f1r*;>3N%Gen+(l z6C*WdzEWoG2%jnEO#=!?%&yI+sP&~c-z6XJI2~*dWe%s3M|Sc(or>hUjiuc>NnRcy zsUCr=$VHznps&^dZn*)2|sQUc&Ru8(l*ZI}WmTo~}@58@vWPges0Q(ec!&<7vgUGui-T9|7 z3p+u~o&*7yYR|_0Yja4?C)gx1dwxiLeY(gbw2tKYP+BenqWtk5TXDCpu^Y*o+DLk~ zZdG+2^ECRl6|mR};nT2q6X}&_t_CfF4uJMw(zivX^l&=U{ONBYX;+V7ZDgmsfhn+# z@trJ6EA2a`+@Ro6xU{&q{i!tS&ThfMj#Z2q*+2TX!k_&^3xKwYf+gB`o2p=B^AiW1 zVbQ^!l7Z(z&s;l`qXSoLI4d;KOnR=_*LcZX7<+EmP{K~|XW=(!{rsIl1q-Np7&k&1 z|3Fpw2Vg=#kP2uGMBc2Ae=Nm2c*bK-p;+G#CtgT1gUKp&YjdDdD#X|en;Al{>5w2` z+SATL3Ljd{W9|#qmnthnz`a(=TAV5t-z78thBDq7 zRTCgASKCrh$!wnz9AzWcLGrI1PU+< zxueZ#%Q>d<54ur6qHOWy6|2`EKD9W5ZVv?(^l}sBDYW)*Tvr3YyYJo^89Gq@73U5s zJ6Df3?*Jw_7FT)VvBwXb0{gQH5im5dNGG6Yy@Ccod!coVoi%zP6nPBD-}INAnCcO>FfQ-Cpm8>W#iDsFP8zy8 z>mjWBy>}HV0I8nabZ4f7g-VYEOq1IJifJHamBGM6hhkE=9Lw&!SVyLlU?peS33L83 zhF)z(PJ`w-9f1?CCR3cLs+KsC`6{P_t#}=Et7qFI1QZi7T>@1%jzg)9!f4|@*0(x? zw%vVM91a^4#rNLVfLRish+k9Npo|y zMz`zXB_^YplJ4aX@woteS`FmPs}oXeh7B)93;niNW?zB3P~U6y5X>HwF)oj7r1;^eA#jWJ6k42VnlGb0DKHGB!PEF*7+qAHnP$rvfu!G6@pwHb_U zH#wuX@eI19HolkWQcmu%${BEeA(PJ@D*F-Ld+Gk>`Lez z@JlfAyilIu00^Y~Pl0I7dmgF*!s{M((l{7axm`N+-E8#OaRM-oSf^|5ssr(`$+(hz z@Rq7@445dExTF&{NNSVk=L+S`OVn-dMf2zDyWkw$xK99@avpvXgwBXAPuO+v5r~f7 zDLUecDYPX4Kz@6SmEacOI$1{EbDp}0GGWZF75n;=MsT9>(kLo$;!8dLl3I_G=fPUF zllOpjY2LmHe*fE4&Fp^iFI1HrLSWj$(Y?j{2cF!O6Fm8mhbemoqlIO6!zv~YHW%MQ ziedWj+@sUW6N-8LiR4v|d7TYmPKU6~VCcjkI%L5KkeLm-=nb*`Y|) z9O~-f+MWhTwc66`9Nv64a=7ao1Z1ZbobWp;Jx-ul@Xq>8F)51?BJT{&hTB+{$4ulV zCB9kHnL$50!LV6s?ANql4U#PkICjDFbN8UNCzCP8dH2Ku-9FLVFoIRhWrL7KDd`Snvq>o55 z2!oF)=@>EEk;_U%Kh}eN$!A2YuaUIuI*iLVa+NB%$ZygiJ&~XS^o@2gWC2uwh*~7& z?>>a71c(!gmzLt}IO4NMsu$%c(j!&5wVtT9<-+ddi^Y5*-6vo?$}v7Ym>zl8hDdRT zL2uwD8-?8S32wdYc7k|pDyW~V2Bc(u1f{u5y5YCq-S;5YPtS#!Jysqwa*L{Dn5!)A zetBYxuTZr(m5^QwD`{AJoWL-uFAo9gU(I}x#bkTugh3Lz6QlYSM5)Bph z-u|=P#a{)7{|cr**&HQZUu3uvw$$f7_{x=C*LT=|qzb>8<>vGzUe$oQCm}n}D!5F^ z4en+O_kMsnv7qEI)Vtqn1SWAS z&3FEmPW5*u*jfw{yp8?d*w;xaIen6}N$1{>L>e>=^s1S!XfnRMB=AnvVN`Wp1fu7J zGq%T_afRT$r-6^1@%^-Xjn2a5@*ju=5DYI%wL^P@o0J@{8Tkjmr*9aJFD2uN>E!r={}wd z1YVU)Q}Z$P=zmXz{rzpaYkD8JDBr-VM3Vbiq=Vvbe&0RYca zHR4;W0SK6U%-p^|P&19J4cwpY!|$m@`}w|45@dOY$Y`k!ghsE~yc+@%-Ug*^CMm#< z2nxhK`2JOM<@%H?j1}J;46G9mq!-368gD*nnhf!=^cBXISBCB`fr(UquTHn`=w*O4 zN2>)5M+jSSW9|L*!7L$M!fBvdu7qA=#N^(Izu&5(%V@3r>I?|7X*3$pJH^-Ifac3^ z)(H=>qtVb;-xY`lv~fCL4)=HZfR?1&{0X_aPmUF<%AO-K?GmZcLO2`2>irz>(E_;@ zyIU&EX4;Ymplf3s_>nmFl6A$biy*PVVhH@~dqRoQ_e-i5p4Ao{j97%{`zrARCDche z%DOKXp47eogAE4Xk0Y;t>N?&xQfb0Zj2{`^UTV5C2U{$ zuvLW0FW7PdO}j)Ts1z2>%}swdJoyO>+27v#%%9WiFEP+R5(qLYeVO~Hd5t1b)vfwL12e#l*;2TvJ*9Q1h9A5Z+3 z3$Ydg#&!Y?xd}-C3ng^=<<&2#4>I*HVyy3Tf zZWql>juXIuT6c1vV!?Op_faL)Jt%E&6v*r5>2KnZnAxXGO= z#Qs$8q2;#e#g44WQm{sQ)dxyHG*9&E%+aa+!a9BY2TrY`>FSt7<~`E`FgNvsLH)?t zT>To=2%HmOrfPo%o(y_Z`tKUNS`sozdGJ#hz9N+)wS4DT9#id`@u)o}iiMUx`O0CmOVEtUY z*FLcuFw3|q6#8Zuj5IfUFGayhqM=~02E@^P=S9|g>DPj5*?}$LJZJ6t-530| zmXE?x9IM#JALa*>((+>hDYm*7ceYslj&7s42(-xWm#YB+;K?TM^-KN0X$Ox#eKaAr z@dFna#7_TbhPOVk9FIQe3-0QzvTl1CvZ?I39$RY(-hng2%HaDea(DA&z)H9bl^(t` z+dXaGm@Xx;)*hJgHe~MD_ct22YjDG@?=a_Oo}AQ)n6Y5l{j7BDB&Xn8pY_?7K0_t* zt$;HPPNy$j>OQ*e>3#ChOhOf8eZ2C+(~{K z-Ctdx{Cf2y`Fv{ueOIr66JbR1qTc404ki4VfD(_aI~9wP7rh5+YU}_iW7zfZ{t+fa zg6!WJz&O7^TG*d4O7NH>$PrwLZ2b$3CDomdEC{)B|DlJ~Ch*d{-6jXS5b|d4L0RVl zyjUEw|K(%pMLf&U&Qq2lm(BbC?xIC{bQw`m;bmB=3qfaZ>?_lP*Uf?TqfhD^I{5Tx z_kgM(uehgl|823IqwiAEA|*bjX45ny4_>S#KOdCi$PDLo@;9B}m!EGoxK_4;++~`d z+%3o|29@8M{)KQ4(60<3VCFtW9E|9r2aEt4;(e_btUtACHxfz{v;Ws4YNa4=9oSjs^k$ z!i_k6p=%vLK$tBmJcwb42>5z%lrUB)7znI^_Gxcw5rQ4i=|hRXf6v4my8Lt&lWbqH zRZPM5+@qdy&UoyjR^PCCYFWrhP%AD77ZosME(pJp;~3b~!k*|eJ^Od#+O;$%{lspc z602N8)$WB0Ge5qMCz0+O;t~zWQ*)sGO_+rtO&FPt0Q|sncp%o8F~3&qJu9?SD@+KV zL+rl!p&NTqqv&i`8)&EVx#bfDn~!nySG)Qbf~%rwhpHFR(N zvR)cvrcaH>v*uG%7q=9kEN2Tg%?PR9K}x|hPLg+A>+uurg?l_I*hEhcg}=V%K~k5O zI+s$^Wz^|TO&UeO(+UEM{8e#@T07*v8U|r($!koCTt1XZ60uUYv*#=vW9War9LR=1 zZ|LNJmUQTNLz9r2qd+-Q8tR&2mgL5bjhPuw=hR4iAV8ZW+8n77#?2YqqB0>JZ$7)M zG7%i`D7Bh();^(3$+BI5;5eUisDAFfKs8?4UGkI&(XCgp580>K8o^KyPN5xOqK0)e zrl0y7Z~!{{?wm4ln;IP*oXLZzxpoEZ38YPUtgho6!fi_Zb}N$-khAqj@+1;eSINpK zEYcXE5j3-qTf3H#4Eg{vnFi0eH3Tt6t^-fI(jbod?r6?bvm~Hc5o3mk6i&svI22K; zae*@k66T6;DJ%zDQ<&eYj=#~l9lVnMx^|^+r zCxubZ8DP#{Fkp)WD@wL2Y>_uB=R+pkoe!E9YqqQkblum*U3*!${x0ki0;EKg4=;aO z@MjlV1nKYMVVk}pX0~+s8`5cHHVV{l$UDlcIhy48Ikx=xc`kr@(YH(h7>>^0P{Gzw z;oD;i3<$f0?d3;D4%WV{TXHTCOyotONRwyqo;)_! zro5{4Af-x7XTE*$k^NDsOfODesPW4h^4wP2G@_kvczsl(6em+gdNfgPA_0U9{HAUp zP~O?qWK?NZ53m7z4(sD0(5XCq&xQMTC((eO1;EAfEz#`&(x4hKGkqDU6%Mbz)3r|L zeeg>E-M4h6q`1>a7__ZSY0SJ{vD|k3PQlK{zBHHFcPi^1KqBgh?X00qnJ-tbh||La zkI>3*N?3lLU{$ozeT^7>du(N*MRLfk%g-a(p`SI~2{Zf#)FsS;=>td!8ztS#nO&CYUf@#z=ebe!b=_Sp>O z6?$i-aeNrI;@<1idNE{0I;lTr()KT-5^$Na0>lP)s6V^OGDbZ_WrMBrQ&`s13OJdP zmRkSIsKrR{5K6!(iFZt+WUp1SB%&jOD}dFYT|UU0&SGaaU?jI87SXc&jn-)-J64PF ziVmokS^3}?A2&@bD%#>=4YJjkO0gC`IBFwCHiBlF+ycM@ma&oL`$sKypBGt%OBTG| z*k3*lB`Ts>4@5w(?ekuv+`x&%Q0}~wM_3Y%W7uQ^@W%|;*FPNrceH=yj)h)s6pDNa z$rnjA94H@eXao8fl=4jSx;KZQKgde5Z`hRIOzdffhpi+6c6Kx-Vuhdoi>llRKa9^nDa=Y2Fh? z@`~nDOGSU?71g>1d^KQ#vfkB)#7|UeA8o{_Z{QsayN2~vGliv+fWqKchrpb<$4g#P z#cHyV?l%iE7|LNsYMXx%|Dt_^F0xQg@!jd#vn^wf9A$gELcLT*jG%H|y_~=Ivv+Q^ z^Xjk5&aU=I7ALh?zA+Et=@Z;SR2I-PHs>%1UVMD@yOH+>RSr4&?wAz^J40MK7SyeH zi{pPo>AOPYw$y11vP(K=Fd;H(*ZPu-5iF*RS^+q#^W_^?(41FI0X`;D(=-eQ6$O}? zicUpzJ~OcDr}}c8lFhPd%=A6mvty*8HYRuppxFuFdfD!1AHdMI_sXY##L;K;U3mIU z9qT@Qn|4H7>b2YtO&*HMJ?{x@8%!X$_|@ zQ|p4phbs#uD%y7SX*TQ`>tUPU_8L#P&;*wu5Lgl4hU=^s6{SqE%PsMw{Wjqz>w0=x zVgKfl1*FzQB(6EUNg?TM+}YxH8pt*>gx|^$lg<~*ZY4c7$6eA7lNt-Q31{Le1txxR zmc}ToR<&q}G);zRKm;jKCKcFtld#`nRv>NXp$RLH#F19+aYRw0nn11C2}QK@L-x{x zy_`NpnF5lu4Lbd7mpX*02dx^6gR<)wP2&(ydAY21fG`bKZP&Dk&uLA$qLT@Nk#{DK zdxkDUMd~{u^f8GM3|89Q)st)i7ZZxRfKX5GsESo{x$aH5G}Q?105_`}@3)+F5w{XN zd&rt@`&*7V9YtKgO}GkFJC3_A@4rr@P4420YJM$=Ew`^0Xs>c>GdXNyw?>7_h?+2S zJVTW__bLI+p=#)gCw{AqZ(+a>qsjKDoHHPVcfAP#9`{XweOwJAGGoHUjWf_Q!f{*} z9JA{9(Sd0#evw6YF<;5oY=1pS2#RcN%0wbdkhttzT4;1|OHFIRM%7-5CXLJSQwZZQ+#PdO=r}t)N zH#y)@ULlP$CZ-OifI=i7R|Y_jCBp?0V^&erIV!q^NVavu=|zKvfEK_r2k4T;OZS(O zgh>$mPa6IQW$MSUlQb@!>9a75qPBI}P+#Mj3lDGfojo5f;RA3%`8A-2$m_7DH_mDD z3@0072w}#i++S!^ikL~X$*ao5pVd$iS$`0LJ9s)9)zBTJXTvKG@2PSSZRjpLDI93> zD6MoQU*}-ICI$GMb|>Ryiwy010QMl&`koT1M3kDk7I5R}kMvu!haPbWscE(~~*)?Jwm?zUgBrrv^FW0B3=EL0#pg`>|0L!7pL9Do_eOr|8)Xn zt!0|BLMyt~`55Tj%bI3eN3X2nR=Bm=377524QK@LI@Z8~&xLdrA*R3h^ZXt|%=NfA(W~xkb^3c(Jx$bbF zn|-hrCa$iI?S6y1R=zjh!s3K?5%=E-&KVFD_?ZEV>ILLp7c{2&6j%3c>fMLt1L)9!!dU-{ zJeLW0fp6sr>RIUvWE}KZd2yDTp3~!RbKq()LpqyLF5VS30CW zNf8a;j><1dAQ{*d#%}#`MK6-0C3q^*K<6!P0e?5q6E({toZ{X}O=I%^ZEUkWAl>~JT)TT(Vip0zoI2Zon&NBi%*-nX*U!*XIMx1 zzG}UylS6P*oEvw(oG6#CcRp)=&pGnKFC}&%!zyeKU*rLYuM-46eH;qXpf{+f=@5F2 z?O%E>5X5I)dPJc;NkOGz*u8N00b|^bc$}qP7`GPNd5_5}p4Fq`sn)2L(86Z66SNwj z`)|Dblt)8#`8kWa6iPeqSG95el@OELOcdqLiALfhEueR}<-4=j|IQMfT@b#qp*wlv z8c2r;0t>ta;e7RCYZYbI`=l$S06rvGvyz?j@p!Hl8*eD)Ed7L9a^V^;Sxq^#q9Dh|?-qAGO ziwxCGoBmMu7`;!g8@c7 zfSFojcb=DrSd1eB=+nATy;(9aa?+WRs)@>%`zcdL$jRN`2vkw#?9@g+Z2&&0*WqpK z2YmU_|H_H??RC}US6SVvaBJCTFp{2r9%llua-;pW$qt2Dmgeb4K$|cRJq1+K4CeEf zRD-~2Qe(3vlaViXm#D=lbTA2$cMRK;aU9yS0s*_c%RQcN?75H~+(uXeoKDN<*+xhSk=2 zyJX0wK1a@{S*FHo!Ly?>FVT$gO5d%+S@#x!%CSXh&ct_em=`3mGq?K3#-oL!w{I?e zNsTT@{6v8ODNCoj{9=CFCTT@`JCUf<5I!o-5{YVH*iC)BPhSxJdd>1QM@Oa4P*clC z6_K{aD~Vp->`iM7$2@=j%V-P?s$cWpTJGU`_=d{DU+gN!1CXsq${sfm*-$o32yBvj zA05oK>%E}RV9s?lvSO}wYut(DEcnchU{C$+u8gdi>NKK z^Qz3=ynwYI+k7-Ydl?p0Y^{JRR@cLPg-J`X>DuLJ=`+6Ma{PuHO}fmb1rhii@K_80 zk6QZ9ZAOAVO`JByeinX}Etxe}J26{3016y72=j}a*m9HW)1&~vSb*p{bIsWWiz@M1 z3}Gzri`kBcu=&U z6jBpypgD%snv?b2njNWJ%FnY|RE&|!dT`5MajciI!d2-VBXzg#yV0l%0}I}3;s*XR zRb^3?fm6*6o8>|RUBXjCCH;;z-KxThG<<7M=GGuihm|^>*-c`;PhBjJTbx%2hF3;j z8<`SMB_8EjcHqjsK1Vx7DJlY81jhjkzX%%BEtf1c40YTZ%@wZhfjEg)VR-bv2Z1Sm)vumwjsLle~C5K}B8x(pqRMI(1RAN!q0 zvQV;kw{NCr*OMR%JS;&I%ESz?y+c`-Ml-%HnE2nZ<$9qpqM#SzRd^=E2-u0vvgqrGSVqx4<6x!IR>eU@R7XuUfpbVBqz0g zSZTHr0VB?)QSU$6WfJw12GEzH2XS+IxGt<{9F{Q)F-pfwJowR5@Q3Mn|ql=RzZ zIb-}%3l&Tu$bWlp9Q1>OXGDFO>DQ4;`gUJ2*3_@iE%ug^WuYLlP!UvnyGJTl55U2K z;H^J(J>JH^Lg3B9Sc8S~sVebG#b0MYJ4!K`K(7I634Y`-#IM{=$#&`fi|?Ncr@kGH zs`?a;8aZfqm`Y8zJRZK-3NK<^S^M^_U=v65Gc>tpG(&}$lE(kr!_e0 zUO2v&48Up+idxhz8x|JAkN*v~D*y*ESTsv0p>eCqM34~qiS5l0wI`KLBeOZuq{qrA zs^u1xiF%ZE%0zz;V(ZfdB_Esus=4^7)gZWm=3TcG+Vws!8d6*AjOx&psIghSep%eYJW&9M*$ea0{WaaTy;;02)}6u5&MWnF^dH=$tjdd~{Yf3{uxydxiD7KS{A zz1Y>zrsOkIRoEhEb?~ZFTY{_?>G7~c-w`eiN^nA{u5*qf<6qjtpMs)}|NfC(b+U}IY_g2TeqZO+hewk$ zhiQ7ypfY|YZp(H{m4&hr;``t_Lga|hgjy+k-5xN+eC7h2yr~)2H98{gMVP_ar>lPV zIG23CQ1+$&813Tp+xH3|R5(hzZzguxQYqcS;g4?5Lq07Ye)o2MD+0#;42!c1^t5N) zxhd^Aek0+l`UoYI5|}sCZ>D{iTCum2A|#++mryd`Tx#Fp*S;!CnEIfzKgMJ(B??tX z=XY{G@|yWz{WT6zX=;u~aV8owf@&T>1cwP@FVmHtMvFAKjkXDf^-oxr@Yh)N)%1^F z`IzQmCQbmAXR)iM&0+=*e0=s+7L^H!^Ba29D%ibWuAulhlfy4`)y$XJ&tN<;Kwvr1 zdbs3dRd6iSSI}#(y8{6@C?9Y6Dy2_z#K{^af{9F@dIq}uYYDSV`xUp$>gSgs21Q$g z`}hkQb91c2PY@V%^PKt3CbuO4qtnaT-;{$Wr~>v-(Q1>Pm;XFf{E0G%C3gcDvp+T1 z&}>0ta^wTHx7Joz>tOgj7RryArcQ(V5nGSEas*R-Kar9-K@LtZUtEEKokR zNbCA}o{4WR5R^cktPC)3t-oGY!3GF6(g+CJ1GITifLFrPuXnr%Wft-6(Pp2)@jZ0*SjDM zvjK{A7N&$s|9k{bekW}+NO9m32gW$uxU+>7-DbvD3y!7}Ho@p|w?}(f%7@(Ia|$R% zttaO1ic%Ks->BtpkQ7=3)owJbk=|cakq{O310xh8`L0*7&kvY%(ZB*ap<4$G!cpC9{_;3jP`@!N8DJf1AZL(`qtXk z#NpIt+8S|F4znNKfk>(o335Eg=he{bw2fLh{c@G3_ldvWGwy&Ou-i)tiJQz`&1z{o z8wtx5ji0T$xpD{sql%sA< z)E!1%b7(B_M;&bfyl3E#_|vBzN}iP(yt4d1;xqsmxTa0@D55b^*=H-Ks&4Q&gSx# zXUEXap~=*rG7VGXbB6Br$Ar}5}Z_&x=qHAZmqLo0o?sFj$yE(KF4rQlP!TQBFLkUvd z&b~cf`-|(52(33{m)n*72E&~&9-Oum&QB%<+WZ{0>blmR7bDx`0U>BjJ!MLwcl>rV zyCG62HptjT6d!(@#4iF>x5pI|Y13Q>XHbff82dsnwQ2FNrZ_ir0?L;_+X*Im!1RPI z7)9s{-0X(1(H0%epX4c^4%}Bgm6&p7NdO{^hmXAzQN2^qeIZQZUAp}IOD|&Hq>_ws zOoNZds4&)xH@cV6x&j2F9|_CYl3&;p!PEek>S@QDS;8qj&utO)eRm|hfrf3l3n?f!ch&5BNeQ}{SWL`E3&$|m{RANnuUe}0=B+Z6#2T076@$h(GlJLB~%R`@e^dL7^1jb1Q$+kb<5Q9akn= z_@9)R1mV2gkpX2||0Osx&aO>p+tzE8?i13L?}+j4s;3?D0bRjf$G7dsUe)_nYPXqy z78p}}Ci!D5Yht`Z*$a|xQB6WT3}S>)x>81ZR{_fq*HFcP$OMQz^r(#fUZCy$M0#Wn zzg67rm|f=M2ycyr^j&D9)kzl0R|c^EW~fHE@KE_{VKobI>CCWtk;3(QtW9eN%pOh2 zJWk22#S=!BvRjiXUY6eUt{~JH|-5P-6T5m}p{b_#j#C6~&qmE%k>KaA;d^%2W zZc*!kKC+bJL-4zW6`DQq^p{D-#v1^w(DkXMdOT7|IZBrB@fgT(e|ynf+VidR8B)1z zS3B*ed}&HUyGJ-RIHoaoP^dc_K#?apFB5_409&D$CLEsC3L9h2E4E`|St>opFPMxR&v~f4Q!=r>Nr@n!9bF~RuyZOOkQ=ZkMh*Clc`5Eq zFNosRV3$jJYcM@=6A(9r1#RmL;_@##UbKR@rN8P#|jdWTU3d*>qk z9H`gDa-_;K=A%ldQ_Ny5lRjG&_N1I|t)bUg6_?Wv_k0#Ov^P>vHgjN0TrG>N6oTEx zsa?T%;N!^;f6_@j?U-Akis$}{utM^HMnULTB@U#trappBAHiQDCh~CbnJXmnteZjTtoN9dIe%XJCf?NSKHIbSMq+5w>A9QoL1G57B?iWNiMC0 zK0KI`V9^(HnHo0?V*3prEDFsiVq^o{B5k$4m)^KCA4R?MooRbVQ7NyE4pYvJQA*>nD!rIdbSuqFI`Ojl-hsFIllOL zR?cH&Y;Ioecn-4EcC}-xPrUiLX0rj5ofywTxych8(5C!*$GF4mJt~o`PdhsQ#bjh} zah+1>;k0)0NM4trQzDedp$rL|iid?}7N=ftw3RJ;J*%n_$}4_;qc~o#IU7P3kzXtp zU^_GG&c9kG9^M_9V1THGUz|c#&>AJ-0A!=ejPI7sFPawmWiDS=WKd24gOi;b0FMYu z<92}*UafR0a!a=D$&|h-8Vfy|rg=STkZ}TP^&xjdFOu5|oz5lfpiT2KlwN}`ck6>h zXZkSIQrtzL+>58WA<2+sq`{hc<~gN{)wf$LBN~z37f*>a6?eSB32HMg{%-%~>d;56K?W&n#8gw)#u$RW!b^5`QKeQ$7yZX*vS?&%Q>y^Ma2Ci!)ZDH3gWurQkw^f;A1CwYX@{WuBL1`CCTT0mL=h;# z-+MhjuC^*%*gyLj?Ld75DB@Pl%#YQ@=CdTV+T|it#x&I#o46vgF*MW|32uz)Blyj? zv4sf;gFDvln37XRS9*O)XEL}YdRrNU%yZ%jq=UO}5nk&a?-FOA#D_#|^PR*-O)##rvuepCiXhN5E^jd}|~ce7C_ z!BQzjGW?T5OEyF=jk{NQ8>5@Zkz~H>RZ@ZRG&$~i{e=paKqZZ({l*I{pa@h)jh9Gc z(NqWHQ*g&r^%Q-Ec`MdwER&wo-9wrK0O>1x?gp_loARiKH~#Nh3!FfHLClPY=}!>I zPyArH<~M%Z|9E&dcOq@MMaX?FR%$Wg?2+*kExe^2etT?gWNo9@Mwy3Q@hq-*jx|Kn zA@VBB&aNu2*r88CbtYb$imRtcHBx1y0Rb`=#Vo5!&X^5XB0lk&z$J)3vpynHtPK`{ zqcP^8z{qM;Ia*BYDEBH~x1Gt0?C&3?UQgsa@QGsY>SfvT;>K%H3IRc-*DacfYi{Qm zu+tA!tjGEE`-u_G3JPq!mM^(WBg&N8Z=#axC8Rb}&IC#Q+{oUgLvZ*ZbpbQEv~$e8N0{2(<-GyrgftH0h->;tZ$LTRz?k35j` zNVP;oDEUuK=1*6S&eICT?!#Fy$$-r_3!rm2jtU!!X+(L3YWv({Wk>w~boVlZXJWPG{fpoM8f z_JP@(LXX8;|!2t0D zM~*OF8tRR_&z*2j1gJzI-O;1Cy`+Ko%+Z0t>-yU8mFq&NVit}@RZ&&TotRi+C0Y#g9ctJ0q&F>J1{t5l;LUqM=36j2FxF@quc&4 z;6RfF_*mKH^8JP#+cLkKg2e86yYX((e?vgN3CS4zE1)fw71!k9rr>nHz^-M-t)+U? ziXY=1DdETu2szZ)v$}I-N#yn@Gz8Ae6oayF8@W9)iOhhXe^T6qijP! zOL#`EWWd{!wmc_T!2DPu@Z^rcU-$ri8Em}owa0GSoJ{97@~-lH5SzHr)w#f70?7Fy7x=XrIQ96c}5D-)p29WL?knU~~=~7S_T3Wih zYmn~l?jE|no9BJsN56BObN;(8u3_g|Yp?y=YyB3uKeno?N6&3(O<=zAjFDzKUF?3W z-o1xs(w7WSXj*h?AdYo=H$*8}#(J>>$Cd$zhX1HIQu4>r_htbDx7-%u|JShtiU&U- zc%OxuGFP?tVEfAu_n~uy&`6-l_)z+G6#zPK^v&}Jk1DW#;r#&~9t_i8S&t52303Z4 zUb9a~lTP=OMiwBNb?oLGJKH-aSE{#r9kr!1v#MoQ+&o@A=+xC!+VswC z=ryPNUenD?c-6wflgX+x-;~>%*ix?sTZ-#4d_(Z9+Z_B~)(w5phcZ!}dDgvutj(3~ z<0vrQeQ#sMKbmt_OWADtpgG;r7LW?pGpB@xf;KcFS92?68A@g-@7ul%yDSe2fdeh$ z?W&mXQ9p;3vzw`a1R938O80xY^{A6Gxt|zDQGlDX=Jcd(^$dy)XmHI3XS_c$%ku;< za6};ye-Ugq&te0p#D;w2vp6H@`W@km6-(@gc<1jL7U2Xx_>OjW?)I!`_%{!g(?N}(>(oB3CBDs|w{UKn*0$ILv9zT^(w9^lM06kt+aFh}7%u%_(OVgx>lKY;4BFnqR z+-m_~B4}*-g7)uYEyxD2z3Y9M{2%^|&5!Xz6qpK<(Qv5c{=;ub_-A>mAYPi2h~^Jd#m~Wz~}DOMzYAkrH>sPvnRLg z!vk3%t><;nvyp`R+uMZtn;&Gl-jG1SvgI5pAM5^n+WJqmyeELLU&RXCSd6kAmNytEEFq00?skx7-Y z29(9;rfqRq%{1pJw*y-D=RAdiX>FXg7IYUtnkMs%fUH@a0H6o67=OtSPr{#Js^fNpCFq`Jn1gfjq94cRii7dWT_jy3W#p zdBD5KVnZ;Mf{8EiIPCp9H=Lu+Ye>Ban}VTg5d0vy8Cj5jO$Lw*2?*BIsFUTN%|rR9 z19VEaV4Y6KG1Vs3RwlQH;=u731}Az?gA`4&30&^ot~&;DJDV=j9>S5Wq@K0$ZrBvd zO?vr;am`&VE}e_Q)pvFz0&=d^Oq<;SG1VsA3Pfv8JAdGeczQSp%oAT+7SRHZMtajMK~KfA zXq@N-qxA>7GC%t0j}h;ENR`{I7Gn9!t~fj+NWm-8xO4pyN9!{y)#hNd&+G6U7~>X3 zj}hznr1v3;I~VMGCbZP+=uHKk8aLSCG-6vshtzeIEYflR)qCzPkkh3i?)Fv(6z#N| zlI(wN|Gy;{`Y|0g7>5>K_R}_bmft;^Ovle}vgjD*UN(;c04P6K`raa7p8uKYKnFB8 z6B>Zc-65=TSAFbf?%j|xurkEa;IzdrQ$;}r7#OkYd*FI_thQoph717Tz?sDxNAvHx zVmQ7B1W4vk?yrRM=5|!tYPYdrEB^3jN;@3itU^?E4$_x`+onr9QP(}fwz4B{)#{Ul z%RPK9%Fw;x>Kj%f!tapmY7RV16Ip4iWNjLX^8gx2)VQ?hQpyIWO!&uf6u`g#>_EC} zr?4_n!G~WMT$DFn#L`nzeE03t?fCwDM^DdgAlGx;uNmhdkskD`?XQjI1H?@u-AVs% zaeMvv-wW@SluJ>tvJ$aDx1Ur!b7MilKx6>KOLXnkPx*)8=E!pbe^_ue=L?%Xe;z~4-!;l;87V%8_WdWl(Oyt33OhBDv1=#a=rGW4<(k+;Qh*ncop z{nK%O)(rfR0qE|1#_+E_69nSqU!>K z7&YqtuJ~{vYa=cY8qsb~7&W5&>0#iF`zFlHTgN7yhSwM1gk=8BYpOQw3VReZs|brS zd{Qc1iUKOFBezV>3+YQhNM)!3y^-SvDs66?9P5VTn-<9+a-&S z#Pi^}N5@C}VeJFhI)DXMnkf0B+62%>@h+A(3^~e>5L?Ce1RyFize_|ZktsVR)c=Aq zGvRpDICks2{SiiQ2{1!yKVceQ4I(a0XEt+Avf@E@9POblb&_Uus@pia{+}rkGP?q zT&b79hQ^-Zr1Bl{Os(J7;(;6_|FTK{<`;l$SU>usIk!)N0dlHIi~Tz= zj9xWgz*QcW{*SBNO5X&duVj{AiwEWtuP&xH73M(z$ST?r3nlWOGJ3#*p?_?mQbk&&eU(Q!wU*Lv7`Mbyb!@mPXS&#e_ z8L%->k?cbc)CuvKm<>W#0or-hPzvM21=hrDamwi!m};~@*r^=JUx$Wf|^SDb%r zA^|iFm{~T4NtNiss{4gzgrYD!TQnK_0=49AdN83Ar~6l?Kp`1#OvgVG0&wpEi;ZE- z^QUnXcO_u48{Bl@<_r%uQeub;1OB<0lgtJ+T32Rgo^Qp-|qd*dFopT?2^-ug)S2nKvY!SXcC)yv9(W4Vi@}r0 z6Z^0{g4mz`Ef@>H8sB=|!W*L>N{9N1i($6YEk5lc_RY9(&;qg{tB5VQONfuME&wt| z_2`}SHM;d>8|R@L|H72Q^2UCEGGYYhl~8XxFnES_Bi26~?C_Ythonmpe5CgMBJcMU zHh(1PeK)IIgZ0?4dW8SWcFW3!>8s^Kv1%*O$Kzy0P#9y&G13VMao=N z1Y&%OzL|GR%fu;$yi>aK=ZIOcxH&EOZV|%nz=@A^BK2Syw0DxpbASri+Gt6C+8iVZ ziXXq^Y+R0fa+Do)!5?#Sz@kwh)EJIy=v98BC7ls_T*P!V@#7*C>;K}0f)@fid7w-6 zG6DD)aYWsd*XKaZ_4(A}^P1cO*oGsu%6H7h@`i$US26dtpyWQ_?*;7%>!oe|Z}j(3 zX+0fJpXBjV=FI^F84e52O{k50#~8&L=iWjpsRpQ5OQ@*+Y!EFefXz6AV$zY6?ns{B zKUcq#EK(1uRum!WG4>K6k$sg#+gMrq7d1okO60w(Mkt zg)<9;9e?xQU*6Qn;;I6Q%#|E@1`+jhVf9s)_PZcQKUH zoDLFl`ggE|#})`+p7gP?;G3!OMmY^rNgRK4xKg)5G)8|3sTf&q98! zN+FH8vMU};3m9y1i&qSp(Di|_gVuLi*xbw=qy9aM-~X7@w#Kuz|Fk$* zRCe^Qj}K7HxLu2RPd)Mj5kUT$rvChc&oCn+wuwvzp@g$qdj40TE$EYq#s6uiRi8gG z`9GiTA%D5#AhLhLH@tLt$QbSaf3pNs z*!g#@RCRNx8-KgMp1#6j@ZP|t@~w-RDZ^HzyZvcSAMT{^CV$bJ!?qPXpV^ZL4-_h} z-eb}0AbD{ix{ZF}gT%v~`2du4|7P#&y@^YemD_@K9*%ck`$M%lA7l200|TFZA>5OQ z{a>V&&h=2x+D&NmmrBz*|XWEdcwpE?w`I1g$K?RNTlyjiYyx7~Bb;&y3 zna`RY3xTA()95>U4RqR|Trd3=53$1|Q>`kC2f{O}nYyZb*L15Yhl1NqXW`h&OX2zZ zg_NuE`$^{w(}Ucqr1^?HxdQ;#^0|;2&~Eg+Ol;z3^lIf95IM2ock4*FKU%weR2vV! z*cI1jK?2%m$eWi3Buo6k!Kou>cN%G zNV^%Wa=)*69lFzBw@d3|al0{buXQu$G^(fFc_(SHlcGLz=T&janMZV!V7{ZLBz#9x zF{1Zj=5Eh%luoYmBF}85DYo*ir2Nz-gXjj?>_k32{f;Bv=h2*LdN?I^pIBh!&71P0 zs=P(T&5^ zFDm^}y`j#_YquU;(AB^?;)J@z&Usw(pI$@7FxUf`5?hLKZQmhIsc(9x*+#EgkP&A+|L zy*;G7g^k^y*j|)1eG|xYK2WY0xL~2%Q<;ySZs1f|_-20ahF&ZnK4nD32W@QL^EhdP zy$^rx_@&9OF`wC8`1fp4Swnk!fwTfl#|P)q1LxPnbKBl|xa9cD!!k>Ne^`}A;Uz4DZ|b#(xY;I5WA=XM}}FnjpU%*E1mHR4oq@9Z>^cShb? z?>zcIZQ9DhNAdrk#$wJ>tuoN2+u0<2PTfpk_UOLsobiJLu}Ly#Z?E9F+(I0W!?o~v zUG|*S&$*YeHMg?zbw?p3##A#_31g4LxDu?Uk6R6q(MnceXzh*k1ff&Uo)8d95dQR% z`nmT5C5nJ>8lm8ENmVm!^6D<`K0iCnJ}=+hqO136BKRcPv&=sDMoQVJov6t*xk}aA zGujMwINE8fneOeO#HI@rDx1xk6)3H?y3~in^;@vyCXev2xeG{tiww zv!T!;53`C`QX#Vz?4s)}z6_IZs;FCWDn)K)nX&6dvn_CVh=|XF{e%PgS2LX+~U6WuJDX)4C#OU-4*_lRKXk1(#im-tDRANQ`Bix!F++^Q&nQ zPiP=24|5%hIB2vQsT)P}awbgVM+M#~vL_kk(^xD{5q2jyX_ZCQcf|~J(_$!j4IMzEv=EtZR;?Y@^do>)og1t8E>3Un%gN8?!734j2#lF$T^rIUA$wF|XICfMuDZjWx$_ zQz`ewn`bGPrK7za#kGk?C86RYRi5ySH+m7SF572hel}cO!rP*_o$#K9$}GxhlrMaI z`i&VeDvY*^C3JI{U8#?{*7QUG|6VseU6a~p_egBAmUVtLVpy-(@pS(BhMiv< z;$eyUi>p}8a#vx;JznQ!f7<>JZ+(TL_z@*(x=MHm$xGOm{i%T!89D|yd0EX=@3q>M zE-D7w>VQ>>1j~wbA5W zA7ipL{!O0kW^!SdC!HI&Q$P-csOC1&?D7ee#eE|J#}QNzCs&fgl9)2BKzbR-g{XY& zPA>>&MAdAc-bO%kC#I2d7MoTa(E9}&7t&R|nKXC2T*0d z?gqqAmzk8YQ?$*oajc5|H8)B2?sugJ5&NIK`6eqOIDAYI)^A=F97sLKBQO~KBA9Yn z@5x<}g@xetuB5JY)*X4TaEtYg&ZitSgQM{v7zcr@E+wS_bozZsb)}Nl{Z=pOwdx4e zIEBwb)T+hg#(ZE9^2z=}qkmtN!z=;BLOBSq-s2EW>>BYBKf(!q9)TXbrL*uHKEeoJyep!MOZ z6{pF`R|@ui>i(UY>2Vk{y8lnM za!KFhHYi9Rua-z#7eq0x&&I?t5sx{KclzG?U@W|C)P zYZP?le9^o@snejDVWO&=`M>S_kNH3(IV8{G#DQ|33;x8^K0+eu{&iILhPxsI;_GRjcD!CWamzsl0)>Tqp6yfNTi z4r4roeP0dhJO?lE!jvm&g);{((4dQ*ykhKoPaqyI+FzmQIY?6HJLK;aJfGy|2JcfY zK8|?RfPscvZJ5jVL+kfv+xpMbDvd)RR0TEgI%!86bRVal%Rez4#Ni9diYX7QeHTXz zyo+Cm9_m{0IRpud02fX|d`QSuG`3)L*;}@8d?lf_)jGr6;KtT!R!0hG2MH0A)?3wJ zmyT7r`3|6)dcWMlMI;-rBZodaegjvBA^2`Lp|b}I!ZKp>dSKWK^$V9%6V7+PN~S>v zaw4=|1L>Sr76TN2o5;(%_txbvtOK<`SfCt2xqbBx5Duq93G% z)%Rq-VW3f-)B6crNG2q}?8HxZW{p=bRoy<1>y`}9JN`Fl%1AGfHLEzbdbbeD<}7^{ zWDgB+;L3_8&-xK$Z)*O9>&Ko;+QwEPQY*AJuW5gtAJrXrEmf2j{k2*mJu!z9w)NTt z^PLlu3O2hSB)2)w3PY#$=@SPVAa*``P=@Qt>aqx^hQ5&aQx}EnglkLq3j?fWH#N0K zm#o7q`?eNo?jFCL{ih4BQo>xqdV}l>4%PhdXgwkoY5dJ9++m>UFe)qM(b^=u zCOnzE0JK*pd@$CyBXG4lv@+sAKE?uYA?7a7lV^?ei=>?PIRyt^1&}@8o-sgjqlY0Anih;o%SlL{ zHLl2(obJ9r_g1I_DScDdWA9DfFZ9xC(xDJ`;&~_m-C%{kwMTk{)1z_dmx>l&8$$3Q zQ2A^-JA+gk8$B|V`PR{sou`>trnsXJ#hE%$e{Gn9d|;%(wkGC;SPZsU00(-(`UxQ!JJocR zTc{q!x9W8%(Dqvn6i|)BXGc166i7~cl+1bC_ioVMb{;MxnSF8me1fwm5F z?`zkN3ZX$V$R-d@o)z8vqMt9vA$)c@uPZWQC#lnEF7?m)OoRVw` zhG8PFlS@_n_;yku3TvMacup5z3Fkm6@ly|xkWsKUqiNuH{z5l5{}JZr&dfm>L}wb` zq7}*CDk3001duH80cRp`gi49K?X?YDKkJ{1Qw8A8S_Cy?pj<98u8cFVg{ zWeIgT{ZW5QF;f~6VjCQOV#lg`GcTN$m+$R$0Vxx`t>FwYGOrEt<*IR>VELuo@}saJ z$J`}+T63=0j`>iUwDWA9+IBYWL%gCS+E|zz)KlQBh2;bG^YwW75!~$JHy~qp+xKsV zC8mZ30nBlRzJfp~zNI)9#}*3Au`j$$0^4zfH6W5pWdcn~#%KO1a9sJuc*=N4Z`CzE zSWO*I_B!ms>Bq7anR;ai)e%!7npXuTP!<9$=@)_^@TbWjt~WAtT*>NJ&Cm$Zv-S^L zP50N4@zxZMX~aymNTRS+1?W&r-!v~Z$YlsSQ3xFNx%M*2oSt+;wD@@aI0+=^4OO+y z4}MOD5c@;j{?-6W>Mn}GVvT_V$;D+f!CU&AQ`;>Q-`-VKg&7EhzjuLYlFaVQ-CJf(mq`~Ja1aPnS&*gbPFvqCm za*vXT!OjYCe`cy%ce&ujMR1^|=YLtWv)hmTydS!ARw>PS*%P3c_S+3|fYrRp@w5vE zbcyJwlmzPF0ki6PWIX{&vrP*;ZJfXvl4K1h`0QfVXCFPSZqJ89bR{3aMSt1THxRnY6~ zzQL7MD=6P(HRqsZFMiLJrFu*IGGHtJglD`;l8P}-yyx3FW4!*T}3^<2`)HzX{ZnnF<^1(*tl{cTbGN*MGPIn7Clc7e|R&i?Au`k6)_tOS3 z8kBkHaF8V|iEGrqWIhrQX#p7y;q|;L@988r`MAj zWj|Kp5r~ytoxDNTrFHcJ+fg&OnxAD1Ur9BfE7U^6PT)fih~gC$5);745)fVX;9|%5 z@VHm@vpx>XIf>tipi%g_0m`zlrX*(r0o<2tbLi^vuwU0Pt)ZV`MR;ir$*~)T|ipbdz|85x) z%Pl2ajqSXQF#l*K=D8>thuneElY~+Ou*fHkOuo3zlbk*Ci&42jTi>-nH; zD~?jG!So4E)o}$~$~07-Vepwkpt!2rZ+?wE?ypakDGoVxS`S@TRX++(ct6UA?Ax?I zPRaoO&~o6kj@?dW zP>f{x_d40m+}w!kPPVDw*sKRRbK-7}jL&km%=|#A`Lb5JyFw=Qt+>@xB8hdn@^29#n>9K^C#aw2p^( z_QX$0s@H6Qs}Nb7ffg0|qTvvic>l9J1j-f!q?Nv?|IMSt%T*SNMy`a^F)RXGB_B&) zclpQJK*=*^yB%y@B(o^k!5xx0T6YZ8#iAHaS6C&~vAy)3Gn5hQ!&Z~nO1O@m9JYx! z`27AR8V>ueeRT{Q)kgkRCjFoV85(aYA#~`l)oW5|%z@>m-}7g>23$*=ZM0DH;vUM` zN-XUtgAjMDFDb49jUkfiLPl0^#lYb_U}z*ZD9aYEh#${;j@Sy7zKI@6cY1|r0M;SU zsoMR5)DXz^Mr66Rjq#$V!?sq)z7Q8v>H~8x3!)kpkdgJmF4fM7x=OiB1cM`1LN~Vl zE@VSHWBf>w*FMoC=*W@_ASwA>&Dwvf7>=!7)dP2*LFYB>l3PNK%E7`ko_dTm7@XD6 zxxWMgS6J%(2I<%-ptbQrH12koH;f`VOuka*;qp2gV0iWjHE)LteX99tYAhbUTm%)w&YIA}`jPu};p-xTu@J_}mGeyy*hyV60mHycIO991EA%3{~unk+Mrf;c|Hq055rxu)J>`Nsr=PI*|Itt1n$kXx+Ur7CvBgT;9 zOgb1q-Pg-{s%pPmg}O|h-FGjh#p2H@Nk6PrKmX8ygi*?F#vZtt3kDj8jm8H_cggnvdA@AXBB%hY>X5( zXI|YTxwA^FEO(BnEAqd3MP0H^K&rW?x{oo8WwZL*2qzl#C{F9hcZnNJ z+SgeT5pP!h(JH&Fc%%(VYLipAo$n+Apa|dFe+`|9dbCJ`PXZY(R#?ReEHK~bRg~1} z#?BVo@kPW&d2wcb;r_kv%S@_oAHH##1Zp^>1XmA&3BArvkX z@^qsqms-!R#OBwFdTz@3@9cznZ!2ulU^k$n1|Ivg4dKVkiHV=PPhkgd<)<_r-~&~g zxdI3loEr88v25twK3bBHuKyDJTrOY8^;z2LCuzBX^p8v=`lE7E8L$*9KDoq=@oJ&+ z!f?BU)#VrDrX6WAk2+qNW_SpuD^>QQYzN!9Js(i?J}*IlPh?Rr=#yqJ*E6hgYVW`Z(bt6JFmZX@^=>0xO6 zB7&SZ2pK@i-2H#4eotF#>Lh4u@0j&G`Iuva?!y=@&mbbIMdg{+7s1DD&DxnYGnT0G zdmAk@3bl`vkgiwRKP$`Cvz$efy@Ny|(KJdR>qF1`w|y*_*i7*z9zxexRK5IhB6S!C zGHjUWliz9a`8Nz)#jj}$no@PL!ubD!NL3JM2+y8sw^In01bS(%oDLz|tqhk6ykVfa z-dZCjGdK@GPsnwoveZ#>9-h@IcJN2uBo09@#d;)l zD&eI@I<{z+lf2u8=lWDeyylo^Q7soiNt0Oc;!5JvH5-OZnYC-Be~b%d8?lodKC%v0 z+o%W(-asU&>QV(aL4-_uEKufotPjg0PsHm_Y=3VQs2w1b;1F&eRo}X9l-Fhi$6-`X zcQm|5NiYDv$BF*j%{P0v^@a9Ba~t$*UZAhDW!=TLIp0JrfEu0Q8ZYdqVe~~aF|VqO z#m6i2M_LeQ>yoVA$#kY>Zm9~+2)vP<-V?xC8b*`s+A8b0PMhVWA}3!xDBcIlx!mXn z#d93Pb$OBJ7W7nwsFCKPfykM?B&s5V zYT#Auf=^+@+Ywd>O>0#-#t45nPV|dlL-0p#e#@uNh!0TH3vPVMZ`6p6+g5p=8|x6D@VR1*=Z zl0baI_VHuXLOY;r_aY2{!UdC_tQt+Yq_XnkCB9xNN5M~59Wtp3ZP#7!7Oh9R>o^$t z=m;iS7ktn?z=MQwfuDS|jxEU;3MLq@VtYo!=&P>F-?bV;rX^<~QgG!TGRczRE2RO- zn#?uDbq#VY3o)94z|z>WXPWJEBReR&d3G=hKf$IN4OhB?UwSa95oi;naoH4hGHWAF zl+XtcSJponM*SDa_FZOaZe+bCU;UczV|WwpBxZ?=BfPO$GD(g|wcAilkJP>F{6<3O z@%-nDiclgA+Sz1$A(34gir2KQ6>h@L#8auI`%jA?$clAAGYwVNP+a+Zbn*nNs=+-9 zyNpxFROUuaA#sW1kB8&1TXzJsa!~^S=G&c7*w+U34QC8RuCFF;lclnH7?qs+?4E(L zaGWQIv>hy>3iv+7P_tUhy-96kyaps}GTKY$T*is!a1{6HINp~It<^Z{cm1dGHaO9; zjBQN7Qx0E?mqg{D4eedSFGvBr8{s<4Mj0P?FdgVMQPYoasu|Yn`_UZ3-=IRL9g1)K zfvEFm>TqQEpfX=_k+TF~KUm^CKRh<)DcbnVst;961gWqz_ZrW9`Q^7AUt?@;%SyaMlky7Tl-+9z`>@3F(r13?SwaXzKW!YL zY&DS6ZTIw!1Uhm(oUkr(250jccecZO1+M0}9tz?(GP!+!%2*!lYGj_yG0B~;;E#hw zO6_J4jbIal^RA90XHtH)n;4xKG(FEZ-oG>HdMzm%zQyVFVdG8F^8_3E zB_9g9(BdYx(_gX|{L((^8cP$Iu12lfE^9`kLzCuBE6EwT&Lf zCbWSXx(swh+P+&t&%DWcs@l-6@pry~d0S=x!s$V#0bBeV1$F;t0fYrOFFvXKCUqdH zhh!SQ%#dVIJs51M^c1X&sA&q?oE3+6ntHsu)98TlFTK&iv&Ofs>7Xr@{_Zbkdsl9! z5fJ{a3pfY^_?NL>tM6{~GKa&d-&PoElpmgNa)C{f>3To&sw_-m058dP$?^(c(UyKx!>|SepkQF-t&!L^ z#IS2Z7MiX}rJ*hmNx@$n?6xR(2AAlrUfVYWXVLOY=qAbvP%TnLttFFq)xPD*A`a*} zP1AHiMRGrI5fiyh5p!7V*RdfjPj-1R(+n-0(Xp^B0FVND>)n;vz4kio5Jt7(!OVu9OccQ6|b~tV3t;sZbfil~?`pdQeg|H=3+{J$RlCf5}=axL`lW$@itGMqzarf>E1g zZ;$+h-t9%0eh5)kh?R&D3BcY^nx#gr6sRRP$8isU(9&@#?P@RduXtF^y{JcRWm0Qe zg=Py5u9CV^W6fvs%=3S!e`2;JP`|eB-u}|1FKrRTmT0UKfT?8PwiV7CX8`ytH)f9(0HYA zDYEZZRtXPGPB$o3%?ZASG=2B@#+Pe^mHrUw^o*a-W3|iVfa>L*E~Bhob<5MOfLYEC zB(O_l{I=oTF4fd_8rJe0<)`5E3JHBMUYoK3pJ#yCaBE*=-wdzw{@Z{)EQ&=2PR}vF zE`5}oYQr?Bdb-1y6}^%tcbx3F<|F6}GoxoZ1`e>w&a9FW^o3y-b6U@3Hl8YYefx z$z-bT4oyr_Tw0!&P;|lrw3c7Mycxd8s0$R+tvg*~9xA4Gf0F+F6Xz_nxVx97UFOI+ zLtxf#WCyC%H>($(xk1c*X7Yvq6L|88m?;ctJlr56 z__c#E(m6=oEeLGbKe7RA$|hC=z2yw~6xwdR z85ZnI&vZCt2Q+O8?R0-lP1$sErK=IXF9611r0&O#%oDKHg<6EhK)jH^ zmoJ%Y)^i@YEWD2!Big@ngWMr=wtPXNU z=pKjRm*Bb1@};~#Q+#pM@tIX1Xp(wCh;s6sq#Ts`%UW=@Ui^!L%v_!@lrR2rPymzl z$g&}XV1;d`zC&$k8rkq5S5n++YmOi;&1-{2ynGkDaq|Hv-mYA>JQ1v>uPeWd$S`sH zz8!VKZzVYZ{k!m6xijrlxC%1ymo|(mIjE%uXDgmIeHb$&J*zF_QxSkbebMOnq|%Bw zvM!cF82LP*rx`)V-MJ&rI*)H}icEXjes=WD4_j8?sgo9-kdwV$2u6Z_&g!zmHYs{G zTt1)hJ3PL0Rx76KN1RGP*LgGXXnRyg?=tCL()!VsE8v-@-Cc6XS1eo1%cpr|uj>_4}50G=5 z;H}z@pR0}7Ib?R8bF1PWKfeBKAavS$l75PdGa`0lOFUyRUL|E>^DftBJp?cpRe16M z-Onk;o<$rNO^0aarFd?F2^fVEY3=PvzDF9~-yvlQ#GsGy*5Q`^I0o(e`w579R~gIx-sGhdAVi?9^2?)1C|62z=q1dgICw!L><;UKat`0-_C0TpSe#52{jJIMX8~IXBbZdBQV1+NYVW5ro>Q#02{>YT%SOF$t8}EVO3B;;L zC(NKVgv@cS2FaJ<`++vE*=VoRdsbbLCN;k~%T4TWMk2V+IetR2y2s$Si%Dn9n~=F5 zurb!Cy~2fyv!&vkr!-!>_|;G0n-KZjUBRxPOb;p9FMNFEPl*Fmp-+qI4WJatKJaM0 z-Rs~cmyJ&=4ICYU#V$Gr%}>p5uwvdNxsSh@JQ+w4Z6;(4hRktx2ruTGsvpp^%@BEw zWg~#SsktcMMc%eBi>rHkPG7z&w#=Ysb8H=D2*Z4Ps_r2yL-&dnC3*RY2loKY4DN}^VZF5 z(u~f?o{*xNL2)K;C2gEngEGjC&KNAso#(f8?M(KIm`DL#Z4>H1aMO09w4-<=3+O8U zB@yRb*>%C@3K1lv(#F~^0GYg-pPgLBzdqm2eDQ^Dn%(uUgCuxp8RwCn7Okz|eT~}T zTP;mDgT4DW&Wo*2J%tT^oNONQIzHF7;Ik>J?RKA+?9)OoiEL-)9h2XD%L6Z|%uB6f z73w|~L}s!;f^y6s{|w~XOCqdSoQJx@)v`LRQ-Dy5>Fk2SS!PtzXP9&BL@<F@%X?xU(@#%(V^eZS?wtm1uW_+RYRL}k`s@$@=`(gw(_-)6E}uLX(nq|#*Wc($1)3QbE3&U*pSwhYX8?tl&xlP6 z4N2?=G9{j!%kUvYm$g6p7_=|B@WYNWCgDP|qGSF8`}g=ZD8JUYhW@3HU}Q@Wc%jBsu^B)hr{xP%PJZxoMkY4m zp}d^D)W4c_>3FS;tbOxUOY=QoAL7vAAtEZ^$gVE-+hNbWUUuBw(KGv0y4EAwz42aQ4NzJyfd9 z>UwYgH$IJ0jmNKS8DXxC{pc()nuxHm@q#BnY)P+2KY45}W(OU+{nA3Z1OM_n`T_)m zd-(g;uaprW+?=^$4F-6m0pal_5%c+yh0xwF_MPv(fs-ejq54>oA^vfuE(J*~r@aL+ zEY1_fsi(PA2Pmx)s+j!4j33!vacg7Bh`-`&DK+1bki^?HF!evh=?cqxK^EP3v?~45 zu`7u%0M+RcwFu-WyXlSyTa@di zTZM-=!xMPEsrUc|ZnCpzFC{pY$v&WXkYidjjG5bCkNr01B>6s};arxxOwY_oU$PqS z=Vk#O=riJ1KH{pnXD>9-&rE23tvK|Y)P5)Ak5GmG!c5|OBHZw0Jri~xL-n%w$-Nd{ z<43sc43M8(Jt1lN3`mcJJdS8cic_j(Xv{2#h%_yg& zIVYjQqzsQ%FrQsw*DnrR3^^xxpLHan*V|3L6PLNZ+glj99d^5SK7B7HN^_7?)1!;l zWpv_YnziVSx%Za_qH_xD-TzlQM9AVy-&pf&4o8T z?EC(i{5&+|N=BjaBnOBK@Qewy|Dl1%L2f|^NyFZ>*9XVy3G=GAK>7n|INLAIejg++ zy32)FJ0zh~v)yiHH#Ps76d5;U^E!~6kNP>NPKjr!V~R;{-aN`t<#>`r3;U9KN-}{j znZ0VUAcEr~*e&7X?|O=lmgId^#1YWaQOlNnyKVRkr~HuQmW9TxH+ZuJ?CnlciGR#t z-)vJJ0jzbIkOMKnK{28Cz>F9GIx78>T@-^(R6bvd3YYP@Dj}$;oFMkfb4mg)3szX zG;y+4w+MqZUfCpObBGxXqZbQizBi;GxX&OkE`>I7(7V4K(fV+ z0Lt#cFUzbGeA@k^J;Si0Lv(OQDcVO5KcLMx6yN=ac4iUzg1o@k;qNubUr+q=EY)_^| z05(WWQC>iZ3fQJv7o$zCX-vHuw~k__lVBnH%Q^sVgTDOrV~?O6E-?B-6lsn0!OO!5 zsuu>iATTHu0n&Pm?5@z@dlrpiGY0dQXh%U=ZfVjEwcj{A0;Qx$FBVNH7#Jk*+K}x2N*+lXaFuh>o;by;U!Gbho+iQ! zP=bQL>C@j<<=J$W4y2^m4IMG2RGu%~-4+#5V(FdgUBXiT4_$8+P-VBZ4HF_A64Iq~ zu0A|Gl@T=u}dBMxjIC*~dz=|3IBecZSAjnYynr{Yu-gO+y z;o7?sD+Ofp3*qr&g9hS3dlHIpaR6U zjaJnxP8Pb^s`c;$csYEI^~UiO08^t+^&|->ph`g_VQ8T4c&-nTJVW`e zj*C0bFhU!Y{k@UMq_wtaQH6G!o=8Qy)&tGv-c^WHiV2S z!*M{B$iwI?2-C^3tkL>S-2m(OK5nGM_JbqfTe&PIln$gWwFanl5-A8ixBz8;1aOccAfuxV zrsIHw>Ce6l1rarD{Pw5}hdQkjaKeG0M|Tg5mWq*agl+C!Ta$_qiZbvaEpKXSBOIz7 zrapWOgw;aVDOrvI2Lwr|)aRbh!@htzh3vpxu|^*j_i1>p)k=-81PM}PTax|R37!sM z4Uo)}!#6uRh7aDw2SLvFNOgIu+rT8^3M*=F4()QV4tL4!uy|F{0xu#>to;AzZe2J%&%kQV}+BjmDOVtv>A7z8iUw0`Ps&KHCXO^1poCIzuN7YJ8_-BJ3choG%LErnK|6xu zz~DkubwcQ&aK>PN$G@GU+=5o&I^@>gdcLsoR)CSs&wsFXuQhu=UICsEz|Tzv5)-3L zK*NT8N6yMUJ_A>fF#&I`2C=xaT#D}O@GAS{G& zF8<$})t^iJ12J7`sagXAG2v>%^F%10EpIM$E05zKmFH|NjN_!ab>g5WR`%)Vo1i^4yso-O)-RcMJsvy4Q4;#_QaL6uuWW&KdTHp7a~(J z3O~foH#1xiSuphIG2$F!ubiUZX)}1gQ$?k+s7c5u|6!5~%4P#@#0X~!FE1FdV4e%=EfzWN>&%FQJG5 zj*&ka27CBuj7X1?P6&c`^lpBQLWLfh!H$#U>ZS*ZUN?V`7X{DFu*Kl$NGy-^NE%Ey z9wGNDZ!C8nA8KtWns$P$ZI-GjN;OwHK>Y7K5Pyx>x;i24U}BfGd)|n0PJeUq1!HDh z#Nx@>e7zQN$sZNxIB)iwLVA}2M?_aM$}Nc2hg85)jI?vzQ(e9qf@269%X`}%mLDwd z>_a#O3NwZA#O{91xbwMvbetwYE9zJiT-cB29FZxv)#xMt$?HSQt5@CwtD5HRFKm|J zAiv|CQq`}!lOa{2()H`4T==v18>_afDdK-R=o|`tM?qewjv>@|q3^YFtRqBw$E*3m zQU7@E)MsDnX+BR}t*u`V9XODoNw!J7ZYOZcnQXIqJ-kRvNSWFTblKGes|CKw!Kxs@ zRy~!tPuE8iY{8lkZF8aJtel{ND<`N(>6*i(^M!K#d31lN;$Bk!(coQWM~ZyOV~qi{ zrm%}4G*B6?+|Cg8Nk!03gWHsBoEGRM;>Y;IsH+3&d=*M;2$TOPjMR#s!W7&J4AuL{ zjnpdE{=NrhK$n|zBb=`fI{3yIASXzv=R?EOV;h^ZI9_XP{^VBmZy5o64gS zT`a%r+Z`7HVcS{;JGQ%ybxM62=Yc}X6!|T@`=jtD?{;%XZH05bVO=#SDIBRGE3AX6 zjlgya$kXlwa9^q)65dtdIs2*sUWpDO1i{xCt`r`z4+>vVdX?);zUBRx?KgVcv9Dx3 zCiD~Du_e&Cy&~0vpySfgAD6yu8@cdV-sTwIv(GS%M37uvCphlV-BGu^pR$&a_1}H*L+YAX9JQ8{ z>F9#g-74V-X7^j#-J^FQ@&{>L#ovSXZ3Wtnm1}ih^p^|&aDtu_Z1d`ezm({g`E`F| zQKM@$X81ZaOPnJF$wnqfed@)^IZSIkp(CM1J$8i)N;-lfIc?~V{R5wbmP>Y7XW4PV z=Ozq&?ByDHpjy~6>_ob2KM$yM)rPZzLPX(|ak?fD%@FA!)4z>R$)9?`1U*c?i9ID? z6rmUM*>JidVsH7JIf?K_p0z%UMfF*`a~sPP4obu>_V@PqF_v?R+t=3)-{*98+L=Nz zCJDic>#+_Gg6*gb;Ly4=nMyqSJTW<>zosyl_@EKh<5IoZyS!}(6vTp}x9#R-U#`BC z5pCf4yuplB36r~>O$t1}>4iax*x1SV_SMvzDDHy_cZyNpHb_m8zyWb~`0t(@+ zZCf7m1s@y71no@P7STGyiBH;sitA2Ypf8ybZ_N{)t8qA=nm(|tuH61!lX>wv^LI1M z6lj$TDQXV`3X|%`;naS|$vh9&^LDlLS!&W!#DBA2e2$PB65Gm3bveJIPa~-hf7<_OmKWFxxiyXG@2pb=y`1*nA{qpsIpT#bKL4dhi}^( zR*e8JP}+V{`{;ZhC;0Vboi~)D=_6F2zx-MR7lr%RR-BJ_A6T*3vUhOrTE1vjx4TYF zL+zLX-058G_>eo(Q5egL%>TGj_U#KnvCt1^{!(~Jo(=T(dzdcaaNi8kgcp^Lwl{8L5y>f1Hpo^peNWJo;km}^_9IWAaDjoq2VKlHneJ=d0?u%zpP}3) zDNT0W@;+{Bz(1gs;u*z$#vgt?mBlF|kAt%Ol4x?A+j7)j zQpzc<_9%kh5A5Z+LSxiC1&RB*nSn1g1Y~I#oNzNQWN{?gT5m%iQWQr>~R*KGw zR1Tu7Hhqfp6K~>|zQiT#tz3KMIG`zLm*~QG(%@HTUVcCuRFHQj3tGXp{<2xClJO2M zMzv$cK?$4FJ(FHaHRZjKP)!G{?Xg?=n2a0A_EiotWri&c?Lrn>M-4YysLs?%3y6-J zT`AKN&_jDEXHE7#1aR)pFiLUPlTD zoca!;VMnHBd&Y9c{|+A8adXX#J+6G28G9~ylEC`B3x<|$$qrf!>kP%QGEhWGn=`cQ zg{yB1+Xw>%E25NWQ|d?9(~$?5r8_N*Q*5GNrpFMTRW^5?%v3QC>VGxBR@%2>z+SvkfwQU1Uqq( ze3d+}7~f=yP5?I$m}lD=TFTfSM*TW*E#I#x;=^&Zb$&MX}b@4r`vKma;$xY(xl>t?~4d3mrlRwnxX zE^hyqZ*p->_tcGA_prFegfEojt=xI3kn?MHP2Km}M9O-DBG><9a{LgO;5Z3eqw0^l zrvf!?@O53@K)V7HjWI?)V`xy=y)IL%iSS-VYFk0Dqi=UX1~PeI zf@u&F4m($fY3~=dHxZ#4altfB4`&C^bmUB528&nO#3^W(qj}= zWRGY8tkltodr%-j=H+jul>)h$ia^-2h&S?OP zZdk>8gI=2Fq=@bKjC{(dZq}3CPX~U8B2As;`SCw<}vdl2Vci`qyI_oeFq zvkL3)Oz@dy_k&B4lhbSxiK;sGI$#6nKjv_yxZ`h~W8Q&o7|XF1kF;l?lKt~E`1~b1 zC5Q|+nOG_?IHMU9WDW9@)~~K-6Xk3zxSxf5%T)(k{mb39M#lVnXAKyH8oRY313A1L z9%LBY4;oj0YX@A}KQQUT2Jg`-wmjNI>0G?n!E`Eclt#Y?$<^%Rn^gm7x*I@w!OQIY zP9QKHpr|hJFqx1qRUQVx>;Ov+Rhr%K^21uD)+yH-MOLn3rQAB-UJl!7JIFZc zb$FxWwGvQK_n@_~eXA7N$MD8I!Vf`y~Ye$^FB=ye$lUl62w)p={ULwb36QlI}nUVy8p0 z21AFJFK#fDOW`BEVF%-49Ov~3Q`d*;zBH57%ylqrj=Hjo=8n%t!4et$Raz&sS05WN z@Vp5H+dh37KJKD)niCo_fr%y7v`adAA!iuB8^OTLkt}VC$av%+h1PY?M0k&wz}EM) zO~5X>Z9qlLRK3njFqx?wkuny#xaL2tm453CV}4WarojPHth%s*&N9`{1O-%lj7KAU zv+Z@`qqwj0xAbUws2hR8@?@zI)y*dSvU+Yon z@Qq+X6c|l5SUO;&p^n72G5vAGbf1^R0(#P&z7sV{uV|yX)ogvZ-8L^ACHF6T+~= zKH)C;Ej~`^uzC9OU39Sh^fSjcB=on^E7~jjq}`<@eq8)OpEOYWbB39LuC(E3#vKWVDsp^lQC`g!QaUQf zTlRg;Dc-$~|LWqzufO*a#Dus#ixu+TyKLD0IUD8f6mIW8MVORMz6MR5_H2`nB937sj$dd?Hm(YzF7r_l?W1NV(WV* zI+b^LZ0){(T3LJ>EAlY8FPE zCx>&k<^(^f8XOJYbK5@|3%Hlf1@AoS&tt5n!y6%Hx4`dwj}4Y7(4qG=7U|EFW>*zb znty>HACeRJaY(M*7K@W`2vpdXP<&H!{V@<+t7)LC_YY9SU@06ti90**vG9ps4?ng1 zcC>%lh&@`nzZWJcA1pmC%R};{VF=-e{=3>Veh;2<103wjjX@zdNscuq3QpIPRfR9B z>r(pEoOhuOxPN@H)2Qd3UxbuJ`M7B=kJtz!pwj;?JgjQTlp#0igxN8Y1w%-HmLw6B zh(QekDUJwF&rjy1=|nqc?1^*P!*oQ;rA$rttxD zPB#KlWNFT=LYr-0%WEUzA61Z(xUB?RkwK3gjIemx`3#fa&Sc0 zyv&kw`pa5+7*C`e1^t_j3h{KVTDuH-k-v3|{6V!ziS_28d$ zw?;b2%%ziFac&?$nkl;Y^Jd7+ytiB%KA4{?NT7b_6Z86U&N}xZIAQWy4f9>J!VQBH z;YXnOGW-~e{3QSg1Axo0c8J;gf;ImnaMgcCq#M>rJo`}mu|Jjs9HK4K-Rm7jI?MHG zebh^JPG-cwMTF9g_v*F%Y^8X1%j5>=4pIOwCn@v&x*O8g-v_^OM< zfH!_?i@u9cok9ft{;2wWVVSiz_7r%^8@8wwJa;R&lVyjeD*bEUIyKtIX!~VC7r_4Q zv_K?jCEo6M7hR$1tiTYQmx+Emy}|rx5&xEX;Y<2C0{PGMHV-OFj10#MKQ!`gpF`mTVpeQL zTgWhC#tX`Hf3n|Sc9O^!-o*GcB4c++n13h5GwDGljR)`Hg>mrck^}5a#5=_OEr(t3 zGY4eq`v!rB3T}5`+3o8vvrGJen%nNfN;teQ3?k*wC4%i~edJH-W}Rl=*Y`>uoi=vG z)crnajt>xs4H2xYx5S&SVO2#)xr zX!k?&l(gjhe6AMyn!bBQilz0Z{3pzy$gEM^G$G-w6z|^nJ25CEuG|o%aVLaG`Jg20 zRO*evU3jkM67f&Si+4ZN2hNlZwFj_`r3CG!$%sD?_e9CS z@-0W6fUshD8Qoj3o_xG+|NT#CN>3f!`q+)!eeg;_;I8@*Og^?P->dTVft(a^L3knS zeZf~03G4Svs?XI=H;RpQ7-90Iw26lNtW!aWv*S`{^(vZzDpA_=dsuyY9=d~zw9@(U zd)^E3;fz}@O)I78Qf0K1v5-l^GW2Qe7*oeIpRq>?6C~*Di>7w}eoi-)L})H2Bvshw z{t#O$)=gIotwzdEDvr);i!@|dw{C7aFVKgume~>y7Q1)+Dh;}RyuP$V*%ZZj66045 zK&MY4?o~A^t+w4BJ>gGSVY;N^(Tx)8In&nLR&9QLLFcOg8EwMA+h1t+Ig$7bf{ytv zy{{Lanw{q*byY4?Q8Im33J^t(x$IWzAMB+wSE+fIQV9uZ!e0oa2&{7e0g89(B{SuVUj@xyEh5ngCJ#_**o zPQ!t7q8}0fLS+aGhTJZ(Q#6z5UaIS_ER9+vZ8#Y~SSy?RsHOd6N-Mmkl20QlOX%=q z6is`-;1PUS%=ME;T}axvjL^S+cPt`5~mnzu+$z>6{OdS7cv zTki&w%2G$})WhkDd1YbdlvvBn7}HWQW%K89)ZFDz67N z@s*v-SFLOt){x0ORj+Y)TfEm!CB%x?n5&>Nsp0fxiS(&@?np=P%nSdP&Z3|e(3y1M zh3D;tx|K;!WvN5C`g>-_Z^L(Esq5*mL-hLV6Wj(<)++Z|8J8WEQY{T<_KhO)4QC3K zOvKUprF=lKN)&=eyS@;p6KT)3~+nl8Kf2 z3Aqvp>k*8F_Cy@ED4@J=VIf`AlY!iLANT|j7COkoT|3(O2ua@%_2<-cddVdD8K*R@ z<}wv1?gthMbgO{fjG-_980b;n=fSb?s{p?aF+P#tDPuIGI;o8W`vTnYDjTtflQsej zSy(Q()?Mun%eY?ss8@jW&~d6Ad7qq()S-S+%pP#Ye~sa? zDT)~<+JS&-N3?D5qL~QqD9A@jq0#Auqow*rM3n)Ak2w&W{754JM1}_V)WHjh#7VV= zVs8Z+hFI4MzoOF<7V+7(TyOj7-wXyAnekYNeEbacr_9Sfy1mAhNV}b=)2(M|XtmX* z?DMKXm>a{+qj2BdHh)prozU{99*ve0AOC#d%Z#P>u~-OT_WX*tA4eMX{+$B+faxOIsVt8^cq~X z$Gm8ZFQ3jECgeq@nMM*h6fGl%at~Iu_?qHbt#o|QmPQEreqPsA61m_5{r++Qmr~1+ zfo!z&->ge7HnWJaT>nr{E65`jO_|P=fo9l!sbuLcTeZ-Iae-=rBZT7+28|k4S|Y;5{&mvdZZ^gI+`Tx<2S;u+b#v@ikAYg(FdvdMUit5N;r| zzfWy+{L@VnT-ceY7(yrx9}UrexS_7T(OWz2N}T%8(I%Gn>`>~ZAOvVd;B2^U*SQma zCUuu}iWm~}?uHZjS76#33?Gk9E8X~%NgV-U4s!R+%i?c*%tH;;GxY};c#fYd?5UEM zy-ipj3_X7B2~bHpbv}{qX2F>dl1#^?`JIyWM3Ud*KqMx}tIuheW5yO6#2JdJCAJb4|C zxmJ=iG}|zZM0pUXi}L=hL*PAf|K{1{Se6yMk;TYSin&c`ZFwFmylkebpiH#?KaB-Pbg_<;15UbL{^mUoAz_3 z*<1pQZg;6Ia42*MB+`sXDxof=_&BVpQ8CbG&7YD{?xli1EUnom9m~H81B7l-$+C5I z`Vch5PbCvogbI{JGqbfjb|TG|`o1@y-$kCSJ7M)%sIV|uBbDTkbvLzE05c&Tz)2V> zPTxG9j932nDeMiKpNZWY)Kvi@7~#F;KkwK)R~r5B@=W}c$>{6U+kuvQs2|0|^N5uy z;%ret$GgqSkbWa#n_cT^-IC|z&D@fCqLFt3`qMAPM}(9f6H+u*02rK>`hZa;Xn;>A zr=ND0oK?3B-h;nJSNp8(3a)7v@-l3vOe$l739vym;>E~uf6;pUfJ)T0FzEZ>%1VzPy_ zyq3!IpiFyF0`GX2{~X+}oaCqL{pYhSh38cfW;y4&qt#6YFBV*PPXen`%QHuu51%_< ztG}#(H$^)u!N7j6*xPIm3_{a9D03$CoF-Ek?b&Nkljbh28&>zaSFnHZA0=^O{5-BK zTBb7XR>x(mp{vb+WscXkNivl^WxxW;YoDX%CliMB7O3CA7ry+Wg2PjkAK!M|_nuD7 zAiSE^_B-~ZW%wx{Sss=CYKk_X-JP?YS-SXxz_dxRK;g&_b*}5kc)mBN$l=LNG`ok1 zo4r(FmK{#tClLCAx-{K6-4ix@s=`}fTGH&A%5f$WvP8-+=8?84-#lealTIynJ3)9ykfO@L{Pl&{V*x9ZU|3oS;AfMfRjxSEUbfR-`p0+Ka!tj;V2zK19 zXk@MO!f2}BuLCoiO~cAfRU1(>AU0*NE?sdg`JSwW_K<(}S$E)VtZEl>32rI~US@p- z@C9F(c7+(=>2j^H*C(?eq@h)&J{{Vuaj)8@~M{BZFYzF`Uesr$(B6GR_ESYda-hA-B4SwHcij4-_7t|E ztF`&5iR6xD)O7M&`xT-=clakA*W?heYC*Qx-DmVhk%2#h(ebI&PUHfGB8)%2lpqYO zs}IK%XKwmd|eaIYbN9DVW8=*B5MHoz%ut7Q^RyBD`qHh2l{pYqRLZ} zgCA^*DI5`f&YC!d(;Y9aL9T3$B*cMvHQ%XBXkCN=DN}uiYf!nX;gAQefFO>kKo*)(;6Rm%qq|#YJlSIl=>FsZ#gkyJsHu3il?#13EtIzm z4La5-$R-P-UdBT3ew9%d_H6|?b>V9X7ic)Nj>qmZ@*@G}MXzB%SItuGql=04BQf0~ zmZ0%nY9;j3-p*+1$~x$-57SuXV}dArEQBW5n%Kq4%Q6z`FKwJq;df$JAncob!hXjI zuZ}P!CNFbExNwDr4Cm3sI4hbj`{7N3s2#s}IKav(tp5T3aFT~_U`KNUg&ytd9Xb6X z0X6`XjXRZJrW=TW5!F8gqgHO3k9MYT{psj|r(zYn3fcUG62 z*|KSgyZ9To^Ojj?lDpZd8G-s>%WqDy*DQNB`G)U*1hwZn6@LU=1EOM&T!irS8luTN zDY{FnMDJGTcJNrN{>=lzTbXYRen?DSP>6}O-|ekV7c7>5rVrm{#o`x^J)Bk}jfC$M z9b2R-+O!nU9)1N+qKPNzl(5r)*YRHm_2Ow`&v5keePAq!pjXFGQan$T1Ca87X4aMifd##1NKfjXoifR z;4*S0rhvkZA^ZsCvMAaEXwKV*UgV+Q6-%kaz#Q4Dx9rd1@X~&`!dDkDqx6CjYL=#r zXqn(*cY(TjzK@-K470xslkNc^-OKG`!pA1THQ@3D-EOCfPX=?~B=c-3?X6fOEzV0n z2BV5}CdD=?`)|;W$;^Jiyp;i0X6TM}3_0-KFfQ}=(l+KxqGEU& zSeYO)C$|s?o+6qew(F3Jx+03J&*#k5w^S)V)l>rKOYm9sCV6vIB_=WWVV0f)uZAjh znE^JMaK=WVFJRiXr504NQPRn7c~zaMK%!t3D-N-aZz z^?;o7@ST!cfH2(dfEiDZzZWY2^;a*U<_(}00>mb_FKM+FrTXYYl*c9zZ=*{D2s=Su zLA>IBal$ii0ZT~2V^L%&VxQE^1Sms?ChP_Xic=RiYu{w2YXyFMXrj`pp%W|FpZe&n^>Y#dzo$Py zraD)Bi6sF+Gi-h!2)tE(I4ltf+(S34h%8o?pgt{iQ4ctyZLfnx$|&p!%%9Aq>3M4~gBaOfJp_Ka4z_M@Ue5tT(Y9 z=jE`zUwNF&cq}nhM2m+!J)ih?R=@n=U3Gb3fv2?|QfTb3YkyPd3zR5&TcH?;^a5}Z z@=#~@C*0|&8A*x%v{(bV{LCUasXU{AZh8J7Q20Gh+Fs2Ji?JJkpUt8Z&cekjVVhmvV z>~XED6owlee0Y(|(r>n_xJ7Kl5&Q8VoN)0MLHExQU}PYh?~}E?+pF)4X=q0WLy#C6 z4NYIr;8`ST&-H)^s%gR!Euj!`X7JX(AlExhfc)A}g2geE-wz@Hvtkd*B8av2N!2YE z_h?8|hQgU?lRqp3fpbZwBm^pPChr*Ks!71rfb)Xiuf^}rOq`^@?9~4IV~7-Fk$v@E4^T zK@?-9FqCCTrF2UQ&;ljtzz}iP@BW($w8_9(bH+k5WTB8=c2R!6|5lNWxgm+r#NB~v zD^U2t8H<;us;hXcEhBi#rrB;GBC2TQ7-g!#(?CHd(1vQzc>Mhf`s1GMMWM!0v*OJ| zmcA++6vAqCChg1!g%lFSO?n3D5Irj;#v*!aFTDC#t~iP$)u7blW?a0CaM&jI_pG@V zLT4adb>OTsVM4^_QBPNn*>={4KY_CHiVH&WaZ^cR{P4T)93TB#fw*-(dg4?XcIhiChA=cuZ}A~6si(6t*T4D&Kwrej$h-ZEFAWr2KmD4P zHd+S^Xa%aNO^;hTN*U8esn%_aWf|!fdNB}t?1w$LXPDn^^O&2jj15k4+1tx%8X70eYt%b`Jx!&I{`>B5 z)57MLq5x28;zN`aDCRST04&>E&-KUaO*1Tr^zFlv_hZK6{-fMms!8<>0h|r^ToHy7 z!N=X|$J@t;jEU+S{fB)Y(zn}%&f3ehH6L$1tgpZqm$5*!@38&x0Z;{5U#E6164QGWA4n$^QX%D9{o5Sz_UTc~i!IU7w$Bd`VD;pwJ z#k-nsCd!AS9)7=p<{!J6c{IVxVJH)l>MS*(qm`t!o+3ZGE#-tLc@rAKniSY*Tenhl zFZIuV`gmXD&M}_LVkk?Yx06QEh8L0+?Wg~@7ft9RzDC=}&B@~aP^bme@4|n{xn~Ep zy>Y)M>#Nk)ilFtRSUpvNtJQ$$DX-xx#;xk6>@!7VG+p?r_=kz9uR-A23Tu|W+(2+{ z;-o(k`XZgpy7J`jxwapz_qaKHHHyw(Q^0s;FHI&&i3FirRsBy9<_&_(mZ%k=?y81t z@}71_n-Qm2NDiFmQg{6Jp8etK`&_}V%DF_!yx(=3?p4M}cOM^?94R3dKYBog7c~m- z1`wC?!&>i|)SMf-;KCq_eI<`Ta3SvhDt}6}aNX8N7@+`?vQ#XpxHs(Pn~j~t^+9Ny z`l8#9v&ZrJwsOxXwaYIgrPxw}Wlg+;hwuz8@dA57HjcAx;XqqR_IbN&KOh=8!^^I} zE)Q=T&wmZJKi12?I{$^H%g37^XA_}?dW!B(_bO54 z^B0Yq!OxsX=JD1`Jjw5&wY2m3B2$Iib^1Q`e6_{zqZJ=~YqK8ER^1|6N~QWr@?Fn- zz^6k!3hfm@pVesm`DzV?T(gpHLH_G|eQ!qiy6jE{1dn-Iu3ho#6j&P767(yFy__AJ zFQ#m|My8x(8PG zgJ??@``(J(3coU9a5qQ$HGycqv|kw`AVHQB`+bM1LPT*OI>xaI1h)gl>oVA^{1WF) z34jA{mSl|E{d4(~iaPse1nMd=3}xZL(ts%Jn>ARs{3X#b6#z48a`91scX%~!y zvD(uRa?;(i`_2EI@!$rq$yyO$lQvILr>}ea%hoD@w(Uld8Thd3o=S)R-6$%w36-~>QDooQ?=d?&MQQ2>+zUdu2?O6H2y-A=ZUXd=?FGnjy^-K zcw(tp+O&m5bfZD*aR#G*1*MGuqz<7;o^C&__($V9$<8i1c!V|@zWP29fR#*AN(yu! z?EG^UR3nR;2f|}lC?q0Y6AMh|*sG!w0&z=qvdmH2(O?{t1w0mKWv`{?2(+_zeSzvm zHz%&U^SZ@6ZD|YCH5}6pND7M#XJgsL^q^1mAJNkRaxDGE*W9W!-Spxra;a2ZmtAkY4pz79e0LCA$`cJhS}yUhX);%F-YR%^DxYgpd}ilyfdYul%a-Qb?lXPa zM13{KABq#2+o6mZSjp-7k910%bW0?KxbM`^oHU<2BR06DHr*#G{AAO0)@2-%Lef!( zM2hCgnF?RVA}lGvVNAY8yhJPuj7a(=2YcsAHBse($ouvRjW{5Q?kL2OZW|BTZggbI zYiY3YNLvR9NF^DzYhRMut@ze9Ph+KkQ1~W0B%V8b#pZUMH@FMKJm^%H?Df*v;%f)I z*+JVm2D5)J*_!|bxX*za!+zQ8AC(S?h)8fv@GeHym0ZsEif_NCRE?n`DNKKxpnsVC z;;~Pml*tKvV=sKfx@qWle{sw^7Gva3dq6HoDC)@wNuV`dQYZs6I1?Jv8;sG!0H}1V zWa*0%cQQcb0j)b@l9IDmc9$M+`j!HG{Fwdhx}JmbRI@|;p|3`Jlyi#k%|(DNs^j}L z{tD^U3CnMSxop!AE~ws`YRymmKRJ{h}1f>a`ZdufsTawFA^B>lP&)19isGd;x$OXP*Is zf04-(`biK+#*t9+`TWf}e&!IZr!TGb;a5y)RF73ZR8ps*z-ULO znV#+wRxHlnh09y#t@tR+aAK&LxED>HxI(#eUrqlgRLD}L+Cf(81nAxxD{))20;_11 z7nc18`%DNeUdK;E9pdm^<+sxD>VogHU_~O&{oRYTT{Kw`G8VB`dI#6#_xgoWDVKF=B?`}CbHY^9{a)d zwVnstjo1nMg~8RgD13%ygl$Dsti*pt z&#w&4DTQT%btrcUT$)t8SM=i&WI){`RRV;>+xRC z&Gmf4ACE7o>QhIINMG+jjq3?-q3*k%aUu8EMU6Z_(Mw9V7K#PWSod&Z(Nhx5i zNE0%_@1WS``KXpH6~Q->eriuECs^!h{VN!wjBvoZ^+kZ{kbmqg_a=@w~a4Q%0xw4)k1~C>+YM| zoqgUB$OQ^E0B#WM*C#i1Vyl&qftJx_Xt zYzj#Bza3PRr$!=q;`!{*-K&4SUcV+_Yemd4{{<&fAOSv-kjHRN_3wT1KEX_4PNDnA z17TP8E^j_y2i~9al^vh9vPh_yhk<4^NE3$@i;$}ftgsuZf-MGorI1e2uj*+FEVPBc z%ySW%SLOqfAL{Gtf2TAh;!7$RT!sJ$N_Y1Xwo=rLfUX3roQTPi=zp(;q4bH8+BJus zASmQeh4*;oWncUyuF}IzHn8qPK~jbz5S++oiN|{~1i)V_SuYg_JdrwcwkZMMycqcN zd8TqUJq0ALANphd%%*iS2ThMc7p3O3d3XOh|BXt(0m?$N8Il1S z#>ZMn2moHIsH!d}JMi5>8L2aNN+2empD~h%ApS&6MH#v4GGIG&sxKH7UOtg7m*$+T zR7Gg=u2e;Nrs(f~#Y8dz3uQa(oBm7Fxu<)r!#(`|2iWiD;kT_{KzXS^Z^sla@R3@v zzA}BWf1ZWW2)a+NVRhpf*@Y*1UswY0aDF3Cbme@v&(^C1EY-_Y?*B`TNVyZe!hBBs zR;>nC+52DYRvmz+7}a|fII?FPSnLH7%5l+kLcIa{i zF;|UbBbwZ%ah~Fdm@46FPXE>os|F2`hHQb*g7iMVP zI7}n*E^4>aalK_BiT@pSqLmArQjM{2|3CWSpWYOB#xd@vTa|TRYG?&m z*P^_wsR`e_6rtJ0<}1h?ZepRl1XK4qH~#}mgPWbDZGN$oUl%j58lawHp43x}bn!Dc z)mt@xk)N;s{q)k4d|%eE_odAoX}yR32sGSOZM3RIK%^v|-ILjKSE3?BgOKy#aH1D~ zz{cDPj>BsFp2eXk4?hh5twJH5smEPu*Mo8FuOpP4bySNC1Z^#8%YL!eAuyIqEDk+i zTQC$%cVI`-Dg)@Q%~r?;D*=RSD)Rp=LDuJgFdA%yR_fZ+^i^k=eGwR3pg?Sk-lWnV zNlAki!ffF1?NnwjoQ(l4c(;4$SlqTmR|0L5=!VILPYQV9I38v0-gck6H za!UT965js8mmUiQzg2D`x|ZYX4nc~VC( zX1-pBFp7iz|8QA_&^C1ec5!3>R<>8G|WG!u((s0dg690rV~ zLNLQSNm70uehr5#=roQ$U!ELv5&z+jx_Hded2;JcC}SZ`($f3Dps@9BC=WD8f#S!0 z8E3B02*CRBe-M-|Ql1o7_5a7zSw>aWt#2O*kyb#uC8WC>q&JOpZ8j<0(%mWD9nvkG zn~*Lk>28p2c^A()|L43P7=sV!*n7=2=N}8 zUf^1lv*Kh#-#i2;c{c8(=eyz}Y__y-5@3O~pMG4P?m#>R;vphRdwNXyb;V0f_3uUy zS%2AGw-i>pa8@3+gnzJ?UX37srB-5i$x6HEce2A)jexv~XyWZKoAJ-sC%SCEzh=kU zF_a%y5f#G~YqExs2?|lw!&0R<*IvsK@t@7fF1;y^jIodq?s~>n$c~KJe-e3(esmZw zS9j#!@FWdMwCZMO!R?RR)P*y}l5R1C8!$J`J(ifdMSGL9-c}$+SrrVYl#{_y8%8N{ zVXkWnuw9Y!fDPl1olv{*9XMhLK7$72fby`blBP9Rn(~mfvWu&=7&Xc&I{8S4$k&_h z-A6BAAJV?;L%O3AfrAr_Mq4jeuIV1e-PM`Kxo~3c1rpE2OsoA$lh1}XIvx|{tfOrf z82#Tj$Er>i8cNE?D|Y`sHkQaR@Q8jn$P7D)2B_%@h3#Pq0lG)(=AJG`5E`#BY%{EP zA2uNX@A8ddLoy#%0Su=?sTK{jE^OgYoV?^a{a3q%WZ`9$tzq0fA~<;G2~2=mJSoV2e+#30K^Z% z^Ih+chT7hAIGpa;gfK<4onh;9|r9$IS+p#)sw8&`raLR=gLZ*0h_6; zKVRKLz}n+@hHxe?uD@_yO;+ApK~_D0Jb8d=DRFt9q_afqy49|9+0>NiT;I{$M%*aA z&`)CIRxZ|)!ZsT|Mg;ILSKL{&x=hCBS)K)NagG2Ok@OTxn${j@(zp{vtNv1~cSgzX zqmcWe5eJ3>26*S=L%UM}koE?>1bJ|{EWR}eI60#B3-b#_aNo1252`DqSSm#_O(2?> zCGc`2=N_dKz|QnN9?q)dpuFTd{(FM1!)Dys?;}{jKI0a-h$p_V?4C5BNv8p2;-+Ss z|Bq(uH}#S=a7ZjfBj%=4>EaWvX;=ICAT^M+5WT~>H{Mtl<(JpQGL+Ohhvqn3s(mU5 zE64bW@j+Yq-K52|$7#EiF?`53S@Ju0r9tU;N9*0U5s*L3niN)>x}MUUL6xVb?=?OM zLZ@rMLU~6x^BDaIA^7-Eeo1CIm5>`ooPJ}3(KY*o(1Nt$!Hry}$-q3Crr=IA-i;pG zw}@=Ddo`l|qsS5NacC5+!O(JZX@nZ!@oRm#O>TfSYc`2;=slY})Y-3lomXv__nye> zlf)q*Q{Tv%e@$`&AuD@NN-f8mOx}J?D%aP3b*P$bQM?GQ_W)`{gB>N4HuK1Jy+Bcg ze1o2-tMI5G`4;!thz41$Y^hGJ;zOaxx0htBU`j=w@FiV=Gul_8ozO%0Nk@)x*$uEG_g0$p&*e-L?^Ua3>U3Nv?iVWknKK9p$+1999q-!D_F_k)s2=f?!9)Ae3{LHnJzWAoR`dCjMpEAg03& zP7(d^Al6AjEIjHzGETig7)#7GvW6J3oURzp)_V{Nn3alINEZkxmTL*G zxc)G9Y*51fWt++{#rds4G^&?cC%hjNs`3M$BB6mF+^aGxg)Hrd`BD@H29-*k15dWV z{l7`t_DkS#8|Knb#Bu&fsR3%H%c(V?K8Tg6Oc_$|cPII`qRBZ%hJpC2&iq)FwLAhnMbpeheT)>3l|rr{|(TET>trWvGt3nzxPn*1klj7=Nx(|sAZG>&eTlZKhkpdmjK_c565@;NFD-m==(*! z>~YPd{Lim-iJ}-x|E@j93(3zkaoUYhsjDx=ju%iuS{hd-;z>kfqnr*@F?bT*upAI& z^5UbL;MyZm>N7fd-N*p$>`OfzJqY`Pp-gU(9msmKc(_D^dlrnb<)4!6SOL>pkx@nl z$!~DXV8 z{mM%+af3JMrFj2*&JI6CJ`VR}|ii*^ga1%+w!Pr4;=uHORyyDvonO zrc?r@M>c+avHWMblIE9kjNC(=N?@r=smes_J8Cd7+c)0lB|F~$g^jaZQOJKag`U7M zM@zb$qg$^FED~d~8g2rtp32%&exU_V;hr zo0jnIJE_0I_65IUM``7HPgXW$6bG9@5*H=S`3d>*r6O{#p77ZG1~eHYc@JqlL|>t@ z|EWy-YQZc}mZgkr{IWmP3!QXPuye$zQ#p0W3Yor1yyAN~PZ+fK@&4T(BFLX!KECW^ zAgq@Tb6?Ksvar>c4c$x?Cj`lg$6lbLM0cV4t@;|2E2}b8Y`^Y%?3@UmU+LZckeEmV8xP${_0({qoNsDuNH2bEGu%G(5%FUuMd8caWUBP?)ESIUa_xwA8G4;e2Ow*2wyF3=x=hjK4 zjH_IhTCt`~i#vsdI^Rq+4;J~_(|$yzG_6$u*S{8WKgi@ww2umD^?yflxJ~XTdf#^~ z)S2yeB8Xg(c%H?Mll&>%9!}mBZXC+R-irlZ6F$m%n@v`bxt|Z<&J%#nCrueo_o?+g z4D|BKmc;$cWG;UefN(bcZt3{MMUSW zkI`udz;f>B=&&&Eixqh^B%SS-dIoO(k3+BgkL z7Xj4aC_GkJZS*r?Wo01W=CE7q0@CQy##Qei&EtjN?ts4_U;;Maz6SXI5MMGsQKcHa zx3LaZt$ZznBoPLulu#3bhQ|Wa7lpwUm+~WeTb=vB7q;5mO97_>{mt^2&QH)U1!re# zS|xa3G2iDVBn(hv?+Hfk&$jAv%aI%Hzb1v`%@xLOQjH_2(g99Rv=NBZUm*?|EbWAw zfwTu9B^!ZAD=BPu-~$?{ntdPk?aMFqX#nwkKYXw+g}|||zP|sxs#m0iGHct*vwQrV zizf$-gN3&q!~6!4=LqI2EC3dl&Z2wgphh5K9QU=reXp)%h*T6ndoQD)`)n$(`KuAV zb@MN)`f64RRa}XhM0v>nn6i8?O~+lUEqVsdM*9c^{ z0+$yg!3*wzUu2S6pY=j!0Tlzr3>WWP5B(E$9%R_QQ5@XU;6Ps3%rMkDXuq^w!^$e< zexcyUN|eDDGO#NnAuGp_A>6+t41ejqUpSV&=q0$99BAHAacgBX9ojZy;i>+yh1WKE zgItrl4l zO-~IU2T^Lq)&SjM&`AX&dH=BD!}6{(Wz=WR2Ju=uC06`*lJI8b7&c-&-m!u>Sc35Q zk9f>@l48+H8M?KP5nge}Sp_tBS(sXFm3j<&@R!S(Gu*#{DaZKb5o`JVIJN)DBA@!O zba5!SxyVKe>B%{r^+>xJgy(~geDjsev)XS2j!#T@*^n``%5W8)+dAOw$G z=(W;|;Rv)E4Qr%d4Z^=7=j81D@!tLWkr=|LkqK@3U-cl(&~h~fsaCep4cv*T-y7TyzNqAUfB78zf zZ_?5hFSrzig^CBPU9&z)mb7%wU1JBoX)UKIY>X7}$GbPqG8}wh#?$;7zX;!}p)w`O zsw99FxIzzQl~3imcv|%_-j5-D;-!&C!7HM#Bp#ypfdH;9Ae&zu={ppDx?^V4`@uk? z^_i_uB^X}baSYjLwB?=?aPaD`C6dJ)_%5=-cAvcRX2*9Vn0-6%gO%n zyDgR}1JuI@+8<>-7R1E-Z`vyD7xz*vQX(wu43I%NoL3xYL`ffKJ@BR#oO*0K9=?5u z;rnv)aLS#Ak|!pBa`a}Im{pT71+!(an?#IqO<}|yoofvPiGQCKu{hR$fkDm};Bx3w2(n2$w1w*83Vzq8aT(!Ar`5tx&wJ=a&UdscgL)i{+;R z#=|^DZWOmjn8h**txv7X3(yvQ=~>(5Y><$e;?e;Srp2C0pg!^|kjI(pN9Fp>drKnG*h-rnbPcFS3h#tVLJJCggPLbi-`Jdry zyrM&!8`-6zaX7i~IYo(A@&@%M)7cMGc~o+QLyVE{a!o$Vl$EoHos8rWp|FN5rxF0JFg{oOc4zl2XBsHi`SP_wf5pv808+%jR*_LjCzQt*}2u@N9gE( z;ZRt<>(Xqy5ts8@kP-Lt@Vr-PyP2!9jWZVe%deVKKe^fWg`J7`P`MyMPQ^=MU#`A& zLPtNsN%Y^tqYFrX;}6935a>{+FK7dVVnK+c?w|50u|l!x-hm09z)IAn!M`o5+TU;m zHDMXgf2EH28~p9Vk9~zOy!c6)`Ej4)0Laf)y!l>bMUL-8nU{YIv4)gVTBZ`$V1T1I z)6E<3k_;9wboFw-+o|&0jJ4m)HopYRJ2p;~R3z$s&k4&vlXNQHav#|U%k}mB$nQ9} zHA{qR)#LqP#!lYf>DEvjRW-j)yL@xeY?5u)E*Dv55e4l?eVUA5bZ5zyWJiq4EzQPU zPa{XX%%U>&&9pd9Nr35~cUqX0Ddn?&amtlgr>w`vsrD0&c(3g-7p=mEotl$CWpn?M zTvPJ=M9xhx+Hy+;qUD$JigR^l;ObFa?2s!{{U0i~Z3jD!0!5+Iu{_|`ju!H{RGi_P zKC-2!{dc zz@jd=qj!b3=!-7S8Qx_q zHU$Yi7R+>UFGB8$Q`PJTBP>d+0CWztqkbU=D=)|;atGKRX8Vg<3`JonO(OcC_~l|j z$EQ}5_U#5~pf3Esl2!~^p!Kf2_1=A$sg!Rb78Y=#y1Y2a8Ncd0M7w{y%HUqPvdgE8 zk6`^K#rh^p&%~G$rN7rk0HnylM+FAeTb>0d*y2Qn*}Z4f{>Av9W-rdSdtt~1s%|e{ z)Z1mU3^rzq91I_kr9tWc)F^|ex!}Z)E85&ATRK>Q!PSNa22EtMU!F*FVH|?awOEI~ zl~qg7V{YXN<1qHK8ZYPTq2zUw*gRMhJ}946lls`RSSTEAH3$AF7u*8hCM9+fAxvf$ zOS5664mABu2@CDlCO6Fn?~h|~dNJvLu|hp0@HY?Ga6D@mP9@NWE`<+_1ky2nF}x3a zS2;m?KtD+LUWIxSEPuH08;g^3R$Fko5}5LK)IL-o{+!bod`Ko-*>0h^CK1+=KzEX` zr-roZeKU_GUYYo1iJ|YEoU%C*>t^ZXhG()|Zi;=@Tp@?k{xPn;cUc-&dysN`y1I=g zinzI)%t`Y7t{*MBVJQ#>x5me~fV|F;tl2o&V)1BuhQo4!OO8F+I=y+su_s|CWYD#z zmt&?o#psDeOQ|`QyQmTZ`aURL*}A+tPXuUwhL!3He96;W)~H6zO=(gmR*~hG&J8Yk z4XfAK7+?jt1a`cgHtkSbe3?ejA&3}I*4g6T=GoOA?<^Ck;53oB8_v3QKHF*!iPN!e z438Qcu0OVyhGV5ImZA)VCo1fXG(%D%W0R}Sql&p6>uD|vNs7}hm(I!)>3}@SynCB} zvHI3?RgEB2Yy@_7r~sS;b_Fdw*_jQ4^W(WP-;EV0tts! z6G0k(EkQ146H!KMMQS@rQwujAHg{PIao3s8rI%mktlIB~9&19awOob;68-Ffz^utH z;bG7L*G2uso#tyC6fh{4evN`QEwFYyTow2EOTEi9kMkTH1Y))KUSoac{<_B!Qp_dJ zW`7QC(4DKW%?HN8ogAgw%&~r(kR@#^ zlloaX4OS_HqqNpjoZH$mms?xLsqNnyY~r6z18`dxXd~zl4rS>JU~qDJ6&x1OK^V*_ z$(GALSVQ9R^ESe#IkfM{L5qdjrQn!vua=;|Kl3(8T#QLWL>Pb0Sc&&=lt2XvIifdZ z;P6;pg6-^?!H)s+4MS26m~?v1mlxy=p3dh8F9waNED7<_-x5f7r)VmYQAhXYye1_Y znG~dt(JALiG0?JV!j24M$>8tmZhktWRcXRJEkR9}ppOsAwFhME(jnF5UpaVE#>{1! zR<&8Yx9=PKHLe})cCnYTWfb3MJXDjjE2|VlcQGt9rM?+zrLQ@bh&6Jq$AMCN>7t;r zjq_sHK@BmYLdX{t;&Q_@)*46B8@`s4RFeN3(aLQmX;fKwzsJ0khVr_<9?RdXxYvbG+BtNvQLGf7k<;8fFm3&8Vx;3 zej8Tq_txPFHsyXhkQOKrlEG;wy>aO~JYd+aUJg(H-6+~1@K7!{bqu&=1)M^`Bp%gJ zOofo9=;mVW5=V;!F%pg;#wN6wAoH&zxfc=mrpISx7;{HjE68Qa)fF0TY;S@-ho9YN zjSb-sB6`*gi6hKyt*aWedRw_0WmFeFmMVW7l4i^e7tEJBY~m@WojshDcT-z-mY{Un zoIdIkvjk{BW3ZhNN#k*{2eQ(VO{dGX>jljM%|ienx}>;J>O}b@o^^ylg+UnF=%#MC`FaPk(RZ97-A8ti#-}A_^xAvb<(Up&WwM27B41vWPUMFp4&x*w6dx8F&#|dgg_KqAS26V z?qvh^LXA|#a7R`B8GM2O>q3F|8x{FrF@;u+;C!%G?9&fM7SZK%)ZMdCDOB;e# zdhYY({$pA4;?GYD6do#9(tw;1>$TT(mbXy7?_1NE!V@un7|1!%ICS;#3My%GGx(|g z&9XEF?FiD3g_505`3TYW%Vb*PSWllle+sWdC4A>MNk)7Yz&nX<%vr5_fl1UI5eg2A$(d&f*VV*BF<9);v_VdAF0X|(njf)f09ni5T{#Vw+>tYUOrc!CWU zP}^sSS|j+wStY|8dfF2R!r5piG9(WFN-}6yl4tI?2PElIS?9<@Q5Mi|eBas|83f@7 zB$qg`3CTsKeuQ2siJMaV7W}heN5d9Z9$kN`)rwuKnT8OIaNNUWD!?JG1ne?gZbD)% zJ1qsuNndDs8hPj}Njf1LSUfTO&YtiyiG}6k{K4<^UyM2P`1I+9wTNK^-6Kwt1|}Jn z?31@j9P?i$t5dsKr_4zYXE&rL4z3=D$VosS1`hAYxA$adW)8eT@@%@vJ9H&iEX|D=HJ@$5z zdMi_MHSv0q7iR+QsP zjA2k}L{WrT55Qryv5tzB-hzkL0xc|2p<9S?9uokTJFE69JEj-2#59etm!WqX>kMGU zRO3`jg~0kiJ!;VUY{q_PyaDs!7o%eTz; zkRqGniT31C25p6}uDXGlG&@)x^UvZM3~8TtxPCOacocHoa?gzxy{~)Mo~(x@)iRr{ z+lfDvzzdAr(2Wua$QhocZn1#CkZz_nalJX7dh>kZj>dPb7>K|ia6Q*n>O@-#GhZ5i z#pI@#3Dls7|h@r)A7mK5oS&*)+<M?ccO&;ufAFxJEOh%B=fVVKnFuwXGdykY?soC zS~ivBoaQu*3u`j>T{zOVn5A*}%p`+te{Z#?9tz03BWwpdJ$gMuxg~e7vdeut&E2Xp zJeZ6qj6S4`XXTw7eT6rH%VvvK?QpH#-KX*q)8Y+A-Fz&Jq6RENn=9%924!45=DDB%;)USySD)I)V7p(n(D+LYl9`F?rZZB{5ujY|l!qzr>l7y3eC_c^#QX zU}+lxbnM&j4-WKHU&2qBP1^^6?}r2vVhgAZvaxd$VCZJ5Wq~oKL{0zU!emBX`wdTX z+EktJ-pJvdulu|{#@p0$H*t+$R^u8ySEt508s52=U{mUf>V-gtHLO7 zU#I*4I5dpQX>#@yY(o$djOvR25HG6gsAgJO_l6#u8UyW{shh3oROuq~ zF5GLirL4kr(Y=y+Z6;Sx&%XG>5T6Wu%FpwWlupe0GzsgKoOgm>A%NOcbI;mi zE9JAL=~#55#cQTB!|9Ahqk*N}#%CKR>TD1^b(2#Zb%4?btEke4a+^))WW%D!!pGz& z#;A8hgo}1_);IGcweMVnPkLzeL$3|qR+Rc$^p{-T??4>Co(i+k(hnM6 zMHN9~u};RXjuIm&R><^fIhJM0s$ zyP=)aXhAf79w*hZR7QqN_0J@Fz#Z*B{#d@)KVRf940Kn&StF@5HbVvhA5xsRQ_q!X z_m%B}064}mGOUBu-MXK(m*vhrZKa@QS$Cb9QK#qD@;)ya(X&F2GG0qb=WqO$$O^G; z<0DRsAqn;yoqFBJ!mOZN@(A^xu{LnKv2V(qbHk->*ag^Hj6WJv4+WGGkBOJ3hJH7R zs_XilQXCmQ6`T4K!HMVdCvlUX6jFz1629AkF49cZk=lm3(46-*nPaX-zb3X;dMXY1 z(S~xt1E`{xyaQ#;&J5Zmc1ab7byJiYxZxFpnJyqJL06iTqn{IpD{QAHt`!L*m=!9X zC?Sz*rfZy$VfYbg`uT35j089Lxd!;BCK}OwDNDaGJ-mec`IG0?NfoM=0N>TB1gCL9 zv(uOED_D6Yk5FUTZlLQlGZq^T-A?5rg7W$oO)4?DhF%r6dbP90geaZ!U`241+}WPW zuQL@M2O_+pOxBL%yh}{HBJEYVNNtr(?|lSjb95}SC$c-if-l+e!|d}~NBs39Z}cd!`0KN)yQB1o8HuDL&B~Brpfud-gFnXfFQ+CK)b39$zuRKREuq1!2aJy@jaP(vWWxQ< z5T<+C#_C&6lhe!j^PWP(&oxye1(>CeYlckz?p`FILm$f?eMrY_c zw*AHI6!4q&={8;75#A!xfm-dLc>SH@du!_7-C`p~)DENk^+|6b;o8J#;M_S19IbK$ zY8(i1Di#Dy-X#LSJFr=>=)O@7uTbOQ4KB}|$FEJa2d97TbBY{n5WzgI#X2+sCAqc8 z#SoO#rt2RUaaG|mrtMwnaei;6C2dG7;^>4u85n`GzTPk>DAiMk1k3zek5+XARfaIE6O2>avO&zurt|aUB)*+3AvyODd}8 z)^!TkDj(9rZ!+?)>9Pz-wr)LKx7eqQ=S=Y=i10IEq|;Hx#G9=> zW8wN)AdGZo7;~5t8kN|f=41gCwfN4t>5VQLmKO|?wrW{^Fv4gj4XW1A4@CW#9c>D` zGnzxe_3KB7#*WtY#v8#8R2v&Crg2rMC$5e1O#0bcVt?->LtoM%<&t9;#u8tkr)q(U z)fxo6?lrj@x;~$0=Mk=~?|y`2=?30-%R2FjhwHH(&sc1el-f>)e^Xi2)%r8EvzYoh zxyqt(tXem2C?eUxpy8U(p1$)ze}~rQud=^sz=ulXE5A!&0`eypjxPd88vb6{wPN{#ChycgM)Vz*_UGVI=m=RQ(RRX z56e31r2bpP+ddM7WDoc8WV;4-&e&uOM3Zh%R`h{6@D zaa~eK?fWS!4wMRHh(r5Z=R~!I0NWV8oxoeTM?AYpX}cE^@~4E9tc-@O()5#asW#hX z?k^ko0nFf@AKb`BzyIuTcR1f-u_qY@sOG}O2wH4JQvD_ROl=;<+MLY0r1H@)gVdm$ z+KR|M&*prhkYGSA?As;_gYa%#**D!ApbOHU`{KM02%0>`I`-)1o-ps5Y+&1+05T#; z+AS(3R~!trQ|Ne`;ZI?&gA38$&lk`2&$}3c2VX}X#*DRF8iMsp(a1H%;Z(a=QXdNc zLO`u9%(gc%{-~-VZM=@D#Y-HgKO<;9WI7J8Yeebx&luWeI-i~5=xr6FoNDbopj6;n ziL{?N>X*y0fwBG2iG+5N27`)5mHqq0674Pp@GibDs@q?)h?+ z-&PT|r!5m3EYQx|=~SDm*U((gPUa>r9`AUzrK1U0?CH;c*lJrAj_*B0c?mV!%{7p- z5NWXWuNxyBVP%?@IE`E0?%3M#&ai_8wrRrYuOc-m0UE74i&M zVhv$-ZX4V%+~8Maok{BtS+7G@rE;OSwwK8B*#$@);iezxzL~s;X~c%k%UCuO9#&}B z%}%|ZkA?Sp$=Uy`AQo9&9iJm6PboH88uxnmZ1o1wQmRg0F{-gn9qQ~YG}kizD9F1a zSJQ7xn87Ji$i=KFwQ1}p>95}OSh&Y1Z*eieao-EU@lZAWAXjtnKS2*!2vG44fpeYc z<5aF@1khQ%;8G)nCh1X!H)8zikfy<`aTwbsCjvrUv{c%5;bsw6F zP=IoxFTyNTZ{FQA@m*q=I8JKxfk<8IrZvE+RjhnpC<2{Vpoq#ek5rczvUTY!M=!VR z?XtOqG~O1u-$pOVP{)mp^DI>yGBx_i6h^c;(9~KND)*g7?70OeMROBrAuaZf%Gexv zfjzZm?^B$ml!JAa>GgV8O=7sgS;vWP$}$Rn{`7{-53+Q_aP1_qR9EX_)075?u8z%~ zisyV}k%q^gSm$4n5YOxHL5yEOrquHK5AuD#CzcLF9MYkr5SdzFs2RA?%#Q)1Y@X@c zEzu~4_v%gEm1;HeJ1qW7AsO}yM06n^Sk_1@@o%m}#L8llR*Kf;A! ze5b*;nIRV~bWQmv(c=2+)7-#RNA~S0MohNJyA8Y9?`L%?8H^_DNna)lGl>jlB$5>b z5AzTQ6co`3cNrP^wnrjfP}$>r-!`xB7CWWR{Rb*8r=W^Lb#wY2Pe+j`_-5Rnm{U&+ z6}=BGT!jUkhy1V1^uC(N|KSANV5BV`4#~tW>CL18_2|^rvq@gU37Mw_ zG)Jvy13|~OImPw?mZBl)d?T6El}6{K@|o=N-T0D<@y`pRk6FGO{D9Wq`fgN!Ws|If zUbF<&Aw{!MOmpKQTdM<60Y(a6L^Jvyw;9IqSU?w9j(qFy$6LLd3IoQ7NLfIRT!!VY0Ehw3ib;IE>%8I#;D_L~>eg6l{jdSX-A8gsDe zdQCIoWK(WjJXq|i!=bm<=XU)&fT4jFVEpEb0iUx{Cr=%wNR(Y}FJZF38;ScU3O8w( zN+f70SQKJN&3E|Y4jA@~fS;HZaKWnY8$(YCn?jj%ey4W7anc3HW#)b?((e?3{vx7# zxk$8D?t*3J2w)9b+HRl<$ZYu-_BKB{j}V|mLli)pV!i4Lm-qm=Wjam{6h`Z-3`*^4O_|Gs6UEw2KGXsa|OpM8e zDTHKw$NL3b1N&tbr5Wk@Yp&Uo7LVS*R!L9_K&N>WJYB8iJ=VZo%u@@b6+zv`GI3E17pTM8VLYzVHqHh1+MuACb&g!c^41#2 zI^cTa0PP%S0RYnS*B9ek2WS(KNE0eleqg@GJuGjp8Ko8jzQ0@39p_Qveyrd>TmZXq z{uY3-^&Db;7yxe;cecUoVG=Pc3w}A+GMmeGTTk5M73A7%&VJm0rED?))>WyqFy{2Z z6-tsO=58^uzndS>cR73!49d8fx&l}>{V|IC&n>O}Ae~x-eE{vNAav|m;6a+s?RhR@uV!KT-5MUhA<;S)sWcC;Vk-DHZ;>dpxJWHOT;UMVvOth zyf9%^J`MTL7>@ZPX{(UU&8ISZo=-dH4L6)lBDu&)i(^3wx{waK%&dqBWYId`HVo47adJKxBo{h~0D81$4dbm86Ee9UT#2ZDu+U@Ia zs=sB~a@&z7507W)uMWCICJng`#8W7RAn7>w;tvT|L`L8uIwV9X~+APA0IFNmqD6gll5PQ#H<{Q96Kd@ z(uo9H3@z;%z4q#$!r{`4d=L-@IRZZ^!{|;=_t2?)dg?ls`o+A@C$PQK zoDk}BFQ}vJB+AT&>JQ;g`;~=8VW^A@uyf zSjju>MLQkevtO_KF?NHgpo5z_BXZ`?V|qmKz7#boGWl0*c@fFz#}lNPNjU^kdtzF9 zkM5yS!x)_MukS@L5qUwKJiC~bHk#sX@P(QT z#<=$&A$tDRmiYXb3Rl_b#e;b*00=h{&< z-@9qV49Bz2b4xp!2$5mY$v+v7pBjC9t|~BK_3}1fLJ~|YC?}aD`|c44Jx`w-1?&K# z;VW$d-m_GD_H1Yty{$K}r3AQMLBx7A@aCZlQ?co!O_skBn0=mN*_rT+E>+$N*es}H zKnQqK_ojTSh#jDMkV$0{L6f^@Ac+NN%aOJ|_ABq_mU(wJA0CPS3JJL3b9p;Lz2?ve zF8~_v-<6sRmgFNUQVm(zC?n9tESkrkW-n{%+6p|Z(nFIubd&GhZ@WIRBTEwed0uZe zPHBHtnNm&iW;?WbyIQ@W`_r*{zI2vwtr43xbMFaid6MHh1?rIJ|>^7AhL%9-u!)st3beNtyg|nwbp(* zy=YC9>Rw}hHS)im0|tQL39RR~;A|CqMb&?{W5K19{#`L}HoYP5;g2 zg~_KaSk-qNkP#Mo>aJmjVRVCkil}8{|y} zEvJ(fZ}39sG1{N)tv-MWeT47!;X;`*y(T}S;td3Ly!%P{@GyZjPQ>*G{#M7Rhl^r> z9K6{?nknlerx_mzaIPjWFFT<-{OqpJ`E{|sb8cLep`0mQO_tN?6DNO}z`vd<0HGLTzOCxzamCLVZH~yOe>K-CgEOQUM}Yf>-P8qP z&1yBRx?XbOaG(ojYReLgbnO@zpWfg^II@{6*i_Hd9h`?DU4(dYuoQ4}gjZZl@>p{L zDRu2*SH*b=He~MK*RitPQs0qO;?*1hC@{o_^NC33PLD66)|=|De7eQLT}N5u2b1SERc z^4{Mjz}?Q=T10e{XL?^#N&oHd>!$%PKFx_x5#d->T@?wht05)CVdQ^By2SiT%xd#G zrJw`35WZ6uj~TGoP_UEeY`;c#lC2gs4-*9(VfmkWNwX!*_q$n1GT;^EM3Ubyf(bo3 z?wLdM`JI|D7~9d!?M3u zjt`_rf?h{&7Bk+u_AE6NBnP8s!#g28F*+61pxwyPWV@39DIx|n&ln<+9$(9|pWBjHCgkLIgbA+d_Tc4VV9mwO9`ysl$cB3b;F*jj!0SNM%W zUVrsaBEiVbF!oxNF{gE>r^1iluY`H^l#!iYhQIWf{f$h?et}uS6J|lbYnw^t@TmE$ zgWJhM_xG!YA5B2~M?qIxrMhxv&-eY~#E%9iM-MUbZEQ}mNZ33NJ)}>M$-7$5(_W`_ z`R1ojawmGmr(O!#f7-{LyFv_ZfBh+8p6R%0zu###bUIk%gpvrZZ9d<{2tThH9c5L9 z87xw%ujQ(SFL2S%{a@_RE&=Ks^-`@aOJb)9(VNH&&Er6gB=nX5q2T>)k#UUa3qIY% z4Clp1a}ie11$#yYq5Ys~DDMgX8BHhOZr$^hqVNO8L7=Oi-$F78oIj(><9j-<;CBVf z?@_VBSE8nkho##Z^2wz*-}^_=OFskFfGdwx&kctdm8h42FO=xP)rV+)1e_Xk1f16| z+rep_-EFeWjy;$FJ<OCTv*5x7&bu*e-0xNTLZK67>WI2TCXs#Qc!3sJj^BA3i#>P&YZSVSpy% zQHqgFseBx-tSdDNCb&8fgyI~0!7@%+f$%~|K4`4GPa3!%z$5H72Nbs|8(UcZy|2_Z zdTFLbR|Sr0El<}9el3|W!;z;wUeejgWm!^1#?F0BnEF%0{+2L$V(O|fCMSl9Xb@ku zTDCaL`JE_m@#ECC^;P@)Cd2I==0-1my;IL%F+x_-<3d$-w*916ele@U(xn99Pevd$ zy6R&npWsJ0?I4K1 zkZ0F}U_bD!$+`-0ARv95VtHnsEQI*j4aF!5ukIBhH*SGJjWH>KW31CR3VaBAQ_1Lj zc$b(HR2k70hIj~TUxDWO{;vMnG8Q2DOvx7iLf+5eFru1y)8E^2FeS(J4gV8=$9#kf z$aS_Z*;>5u{a-w9ho_815`!Q%vD}<^_c^RGD8wS9VOR6s7p_yl{@@XCV0=HQ*2E=` zU->dE1~|}!;vrPKph+Hw(2RuDLsufw{k9CxM4@s4)W5+zVE<;s(}`Ob9&ClN8jBu6 ztl#SvUWyDJZeu&H+NUd3pHcdpGXH*5a!p+Zrg=CoUGon+Ztz8BlYH|#$dmj!kv$(c zY!kO`@yt#ePQAWD#Jtkky^mVV%%0Esc(t*XB9INi_i!|2`~S1I1bmLZ68myfquys_ zw2wr#Gxcns-P2{cvYtR_JkNVHYJen~GnD0|58GqqLeM8dSO!G1Cxh~4J!(IFmCtD= zqh#^k^w}b+EzjkXpQbH{n`rCm`R2%vo4TAbEV{GFG|WXqbFCXb*6;%~a6A8_>-fOn z#iA{-h98{n+;D@C!U*AXyDKX6_Hg++kmu*Lo0dQHsB!cdnK2(^OVkEE!LJkuZ-=N(nPh+PZuzi}l=-I_n%G zfav3wLDF*|>ubJ0E$)|U-c1L>2s1u7tNcdN+4VA}V7GqdJ}VW8=htMX_DXbH%zpd8 z0|I*kPovNT&vk!)kIYEJN*x>!Cg0h7@Z$qOBEC$#1BEa98c+qqS9fdLW^BU8J8iMj zY#3NgG{lX1MQ7H&6`2AuFNzFCdpIvCJ2@N-^iWIz#`ROtXNQk}H(*`|Lp$eRX9uGF zk?~EkEorFT-+4m@5wA-p-H z5AoOO=?o$Dg2fCr4k7mPCuKb8sq%b!%cBF^h+VMj895k(6@um+(x$oRwrVc~Rk4!l|?rpC>bQ|$5?MuJG1sCkONV9=m zqs9q_g5II~dR{)k+|j%Yp%KG{9Wrq%?5T0dLL6$jSWDJ zl;Ft+D$~c=mIpy#CaA;6-#72}n&~}1ppZc&%=0M+bvuG$x%Rn2fA?@8rx|yu+KSk) z?SVdeoniaJ2`e?pEjKh4Tqb3QKzeP7dFN!ri}4&|4JIOTC&&@>bKnGBl7Tcerdnvsp$xk0}0XN-E+fA@lQ;ruffN8a_?X!jjVpEpztGc zA1|c(TW8XD!tA#EV?NUvbach-+lULw@ZBxr{&|^)ET8`K*mu9%7+KEp%be|6L0tO0 zhw&8%6HKccS%n!O;B0j-$+uu|X6nBGv|EVsF|lGOc(BpqYsa7ggKSW*S4Nd<~(p-^7)PMQv2d(Jv+(I6s@8cpNo`%GDCfT6R`CjwV?8CgCEceu_kB zI^Kq!6hA?)Zw13B1VP3LIEm>ui_;nFq`$QA_NYHb6l1ip+#rz%3CeWjHw7F_o?j%t zT6$`QNthRs{hqd?bA+IGtd2)vkr$vd5fisFw=^qR8g8K)Sx(o|VU3Cyty(UV+<$eh zk{u5YZLC^Zdb7qiH^+VlajhGrUC@n%gm4#UeF!7)4-mq zKEG*q8XLv*Dt$ed4ZLOVb226*+U2>@`tU|Y%l4Yq#J40SG8AmV9`HyHu3qdnLI;I@ zv_!=LUO7}YT@fwoG_gbdAA;T-y{4iplUgk#SCZPFUKO+h# z7GbCho{mn&&@pVSeWa{y(($@(`9e1&3-WKWq{(V3U5;E^noyb(=FNjYKVZ#cxQQQ$ zFu!N?z4DrWYz-VSpne%s4MTH2pxcS7(Fia1twf0}ylwK)0lsli6>oqZksCuu9VO%X zvM~0|U!B0y#j2NQL#;tq}v4F-!FYsj4AdeBiZV#wX%YzCz)KejTw;6_jS25^`z$y{>+*V@6ky=D6*q zJYH^)KLIK)vE%=1{yKqvpd^PsB$_X1WNth}Fl8j-FEAx%PK}9q`EuET06X9(OPvMU ze9T7EWKH+!r(xoVoyg+Ghe`;kv&KHXOe;|``RU1ByHY{Hx$-|;xS}(b0_lSd`h?js zRU5DSG{ZkXq~F!$eMqRp)@p1xl*Ms)@a?NQ$o)tN34D%Uax+)5#Y<~={gx*JEJ)#im;`VGIIM0K2TW0!kAP!x8;~g9d z7hQTq64qUUNw7T_Qk{13x+y6_Qm$-9`INj_sBes&fqwAS4^lp>{qH)gMg!Dd>yMJW z_?IX89f0K zGbke2B=mK*P_V_2j8P(+x<|AGb)(X4SwdyP@z`Nal>34Mm=p<*u_W`7_q-?zo0E>Z zc=kL8!%c>QrOXnwqc?!y*4HM>p?-Us0J}TvmjTa_m5Zn#MI1?Vc*I`?n`=lN!5fcZ z_~KDgv)j<~2zkBtjzcwkt_xDRIBD%HnW)W;HskzrzZSRqZ|}?!z4Kym+!tb`c=>$A zjbm1yxQPwS@)R%Yu$gh43grf;N1o+^Kn~gnR1oelo$xL@f3?X{n_oP zHjR4Q;;`RRr8@+lRpO#D4j0PTx8%A_!#y2>5topxd!Hw~4~i*IpYjfaZA{k9m0VTr zzqz``@v`lW)LMU6jLuRr{oMIuH6iUVmXbe4j5bM4*|tL=6QrBjkD?I$qXpD`qIzx6 zgZe7qfvAaoU%*)1uE!^T+CEt7b`8o)m-{%4XYc1k-zn;m05Vord*mML4>)H|Y_HFn zmFDPJjXSpO@Pp7)tk3oY+l?i$iz{Cp4;4`9bg3(YVSrb)9BcEZjPKor$FWZ=F zyspJDF1uy7LdlQE-DXS94GvR=dgPA42wL}&Z~Emdulp+*5&~BIR#urYuZhomwWed+ zn=yL(4L-y0MtO;b-Q>IO3xn^%_73&r)JLDImcC*cnn=-khJOxGE4GU<(x|jk!u@KN zLvQ+6tktr))gcdey%F4==VRUO)B`A~8|g0gVZicDs0|kHW-W_Xtgm=TkbCj#Ox!g& zm~HM-yJXdmPf_!J3rgb+a8GR*^)nKWQ_=PglwDim!1()&Oxrev0yVMAb}(MAv7#pc zMS|IxaWru~|12Be5^wI++92E*(p+I}a^u{8+^`}=jyphkG zCnW8YG=8!K8x(2b^JGXst~%U&h38}C6(5VKsSm*U0orQUG+{5rFOqUJS~XIAZnPN67v4x_WgLO)96E}u8^;N zs!61bpn#RF@lO>@5NnU4=NN-b2Z*$C7ty9Yi5 z?n<+np1>a^gB~p3$jL^}hs-0{ z9qbb?DES7Yw$#QVXSL0&KP!B9lykp$dC)U2U$aH3_e1oO4h&HZz1^|FcOm*Ml?_ZX zvf9tzpuJOFwhw`kH9#X0-v+T#c_F@tDM7P~;^c@2usc2+g)?!jM$cV!xW9b(!Qx$^ zNkGbv)7fX)3ATiCg+DxejO*7AwJ`J#Q&=t(mtXmnGgsv5f9;IM=}@l0br5QUjtR<; z`W>Cj&+7JuiArf2Gf4BEkG}B5q&!(HShQN_va)_>kVSin-FEu{)ubSf9&Ky#`Li~6 zn!AsZE$Z9_?4K&?2wEzqUaETTz1h-o3JNw%Hc6qxIZgDYmWlVV*L2#u|9zp^1@dR{bQaNQV&h9rkPb1h*7THjY%S}*# z*l6|bLV%FkA%FPev;6#ZJ0PIJpQFCdtadLWA5$4+#^$s}aQZr}oxi5=l`G|Fp+CLT zWZ99s7OxaJ3-)Bag9Jr>R61apU(;3V!KBw|yh)a|5uf?v- zrTY|%sfix6PFPe2^VRxpnYnn`OI)>a4A30vJU#=QUfJvK?2+j)rc1dcsY$veUs{@B z;N6PeXz#Z^EqZ~`ikrl%#!xp=8B;G61*!p*mq+>yWj=F})l_ISPAkmh5z3u9M7YoB5GSQ3GiBOCEJ>(zMR!*s&zpaRBm%=lpwV_r z?^=ske5j_OI>cb{PH5S~$;gaj4OUChAk4`p3F5{(#b~*WcBKrO)ptnX9bPC6@eG<8 zuXIqqh#DrA;|9EoLaKxGJaBbKBwZ-MF71 z`7ADa!v2qxkq{}gaSx${kW5jMpbUf=H>MH+d+2-lAHNRzAUf2-Lt?L+9`QG*{9jX z1?c}j%h5Slj`)9$Wvyp0?>BA%`g#U4Z^tbIP;X2;(bjzl)*>`^4f!AY)Tdt#@Z9F@ z{J-z^p+s-I5EP_&`%n*uYxXWBfnD1;T~M#oTsX-a&F82(ss@&AXlE9p6T5v1&0A}o zSzRVBkqLOz0*KN{M#pX?a@f}>kS>LfH0&m!YuTC3_8jLLl1-9NG9je+C^S(|}J$yZ+l9M(M@Sn)s3^Uo+LpAuPXghAP z4z)ddk-sh1Q3qS2FQw>mV5F4 z$1*{a;f*Z1P5`JwGU)+I(YJ-*em^MLB&~}gC0RYN#id9XsPaS=V8c~#S-#r(TDXaZ zH$GWGMo%Ru@%#F*Vpc_nE!BNPcDB>i!Ny$ieos@zQ~2mNrl;Kj)hLvs z^U^jsXAF}>{s3XZ+1RIp3e~|q|Kz@}T6u-x{<5g5WA{n|LkUYYxLSZsR$0WFln6r0 zRH^)g>i~7x!Vo2_zu5Ax(6+*L$8AFBEc) zKnV5Kz9AREFTuw3l7?0sDFvM4J8=C7pq1_yO*a%u7!!&USnbQ|dG*#v>7K+bc6o#p{GPl6m$wJK~|#BJ3fCy>XRY6Gj{m zbg-Laln4_h)G)a7BtPK00jmsVZ-GBM9atIgYQpY7m>D9JF#{;HqKx&AYjO_8K3wc` z0SMNj(lFd9$-?c3RcsX|za71ilYWDK+o|Tbiv_Pf~~jCzzL_p|rohjsAeO+sngB&4{3Q4UJ_~*$V+oF7$T6|o-0G`{+(lW6+$fIF74#|k{P2K3a$DFYS~h?Bcdz!Ppb z*y5nqQq!@@$ljUS%KuEP^l=h_zvYkTa|>#2m6sBTzga+$4pdxI5O9ZzR+e8_;`d`x zy=VFTn03%&s(^V=gh{0W)gjt5H36~+6!t1Y?K}{_O;$%-bw9eFay-bf81sOdt&r3h zE;7l0*&T2jibs1pZXlw1xh{@fY*jZVM~_J|n!A_wgaA(`W>YL5cYj+zj|5@P1=V9g z8pPn`%mWBM%+_6z$OO#AR&cgVKOX2Oh;g zg>!w7W{zE)8BJOcB@WNR9N+oA3bC&IMu5$?i<>>cv5b#6fg_*Xfn#v`BA*;2sLk=( zX(id9OY)z`!cl9{&E^|GjC_lafc?^Z7KbF{}!vv1;fLYqQBl|lgkpP z>8v|A<4(vOO#|?x(5|@yv)M}f0fLC1%un)X7=j9yz7zZm0uuYWK7D_c_9~@7o0q`L z^GlJVH>P6VJ?I!y3be+$+M3g53M%9bZ6-*2NICkc=UNCuDYM^gjW@YG5zGj@`q(&E z*nMy&NIf0~#ubF>x<5+ebzFk`R^?F*;b0&wf-Kje zLQW`vfORu}*reyWQ<5WB`;*0lpyKU|=7WJfrEa~$4&_cZl{8sjAdofqvdwsy&N|NJ z3@dpPn#XuG9&z@tNT7U8JsuGaV#hGX)A&bZFa^pm^NS_-{Zgdf<5kp8-&AR;a=zA* z(f=Ngk5ZNAcXr$-25v@MT8J#pKnwL|tp~ar^kL%I6g$th?1a1UW)tS=7To^ImkmT; zm4TrL!D&R8f-smYab*fWen}`zk_XD2A6nIP-n#_$wdGd5_Zv!xRe07f&b?lPBuNPz z!|V8J90G*ySZnH$V+ER!=V$*91%lc@2A*MnVz(K-ad^!ih6bJ)@D5YQPC4`IMVP?o ziS0Lpx#g*blhtp}QVi!$edoN|QJXOI9@~8qDnERe|INi4&mx;2Hcm|~BqxkgY#^Fx z5Vb-j-3}HaY_JghR=@qrT=GGhB`Zy25ea*`coA`Z({Uz38AF(dgl`_B@h%$h1mDNP z^H=1-96nT|*06_?KBZW3%-v{<-|@(y<3dDBF$RtmZhv5YABw9lgB5f6fl(GcHTAxX z`)Ms@3{N4^LlIIq9BQIU{f2XOghYVcS_fD;-hCt(U#ERD7QSdunOPR&YlEgw;r8B-cM1@>kjY za73a0ki_z`J>%FiF<1&iX|kVwkLb62F8t=tYLp=Ytm9_nkV##5ogtuU{lRP*CicNU zhx4OCK)CS2yzIMKJ{H4t67lX#$;i9JWjjq)um~&D$Ff)_+ABlIXa6HF>rQIaPER88 zF1FHfZ8z1%JJKtxnK1_GW79?3DW_AupyIBZS1CPp4+Tzr(fj`G@OW+cq(7L2csd_j zJN>x%NQji+YX(I|Esc!M2COJkY-zNM-!`j%fl1y%lS8 z-rWDqm!n0((wP-8#_b=g+}DfG1Wap$J>5@N1iXqPa3!D>i|+5pl0bw6v5W3t!shFt z7p_H;fVRGhA_*gHxr+01g6Br&X<}H9QH0T3+xKtw#%ot9bz2WBKj5MU zP8ErSqV{Mrr1$k_<$W`y(_EnzXpyi%b3{}_G>Su@^OZL=WZ-tuG%Vwumqkb}BQL;d ze7f*sC@NYR{b>;b3w4?wCXbfi1N2q8AHkT)qUs-O->lLBxB(P0Rc8Nx+@ey5;I$PA zyK?-kPXBvq-OwXs-%oY&H!ByjHs$qex-%DTyVwK}YJNRi5XOufJdpB$-MA8(5u7v< zNlfk01VjPDYf_KnYHBupb?i*?T)Pi@{+UkAm#&x?Tc+wZB8**=l|ckd2~87m92(cRw) zk-V40R+QiIcTTOKCo0|{2HWxKCzkf9#QW6s$KqLMyYXfsknGo^zd#>aaz<65SrD== z0Dvx@B8XXlnA=vlyuk0GHuEccGi`_2=_z}C67J_ra3ec)TCoA_UP?Yhp$9CI$GxHo z!2(J5)$XBP`LZt1Z@1M(Pn*VR+^e%z*G4Iwe0Hhmy58o=?q zv!m2RlXIW~T<=hur!V=hu~h&wf)ux5s>Tg0Qq|48$>yhdD%(9u zyMH$wFVSn|8j{W;d++2?3`v`kvU$&nxhp{6USCUKO8W9*-qEFi>!Yg~_mx4YrAcZm zqxUX_w*ZPFqX=5`g5v4QwrBM>u=S}e{pCRx)zoT9S=+~R<`k9%J<3QK#;>7F6ZGh< zxME>w__Tm#_GWlx9uF`%2;6;G+ZX~*oTk9=qmRq3TLXo(Db_sFe>@{82&XoJXHG*_ zV6&CmnuzesanZE?-?aDTLV1a6mryzE6p%VK&%;R=x?b6PDj^MKt`wwtI)ZQYQ7{n{ z>wH9XyE%l?Jo!utY0Oi>t7zuumQsRIriSaIfli%&cC%0Rn#v1-&Vc6TG1T-@yroUZ zy<>46n|c4S6#lLWr_kAO(`EeeCdg;iEOTRk&MJWDe=FNF%0z!{ocrOzW%rWysHURI zUX&(=C|C9scA6%LVxvWYAZxH}1)dN2P5IU->t=ewQQxCN^*>}TUFfIGvE@Jw{P!RK zvuE(Xty=yG|#?%Lio?`0x$6& z+bmKOT&+<2|MI;+9~I`6s>p+eJHZ_}V^r3k++C6Xz`s83OkK18zFt`#>QI^x4XnSx z>l4Ue=sh8Q08aX1=mP)DgJmV(8SiN(c13|u@w({$eOwBjb9cS8LCSXm+JTt$fz@G#U`{{{27s_2huMPzdZ3aIF^ z7kI2dzKJUX-iqX();-;J1yj$M8ZH)z#1C~28RPk(U^PqLVZx`hGBv2v>8VQAEJeZ3 z!V7YZuKo%2{)df#xUNN5|60rgWhxoFJ7*Kf2?EzAS{haQ_x9~yb+zM@{}U1iufV~x zNe2gbci;?o5z(SvK>c~sm-B@iyIXm6+j`}c^JcKohzJebWOLNq{2oQy=RsW~&S|ob|!2 z;3n&kxGPVg)8L#mq0*q5uPF++#0NVb`M;A0;@w2!y)+|x0Y*BI{{6dPD1ys#6eYe( zKw5#0o?ZLk@^BEUq*l2DQ(!^Sb$iuW?*7K3_Nqyt*?DjJ^l%yt#huVZ4ZTteyv~lQ z`lK`T0+&P2!F3!Jw(Vx52$kykl;r=$O=Rg?XUB?dh#kq}%(2L8DVu=GkmEMqm4dFmd9&9-9 zRRr{$tm3h-IOsWHSj`F%=s7V}9p%40m+#}I)J0!GvaC+1bPxTx#vihU@1JZn311K# z1Ju!Y&)#$p=jpwx9-&5!GVf~+aIsPAAsb-V;P=W8hg#stKJ`!HnF#)=!H;u zAmLdmPzI33eRCF^lbu>0<6QdF0Cl`SXDsko(?(?0^^ zaVdC7x0-F~o8{l725yaPu(B$fQwZYP9S~lZfGO;EMKvT1oQ0431n#xuzZO}x+YkfN z%M__Ojv3&OV!-d&dUO0WbHMZ9qZRfWD+=M*Xef`cvO+_l>L0~po<3tXmQEOIvR8my z_m@OO3RzoJ(Fw*JAvtJ1jQS~7|EIp4D?|eb4!3M%0LpB|lSulWK#~M(fw={#BVbwl zJ@PDNx=bnq!wfwExMrUi>#+5h`sW&y)OYs{Yo&EAYi@M}8bPq0yV1{L&h!D00hH(2KifAXg~NyvIZpeVMG7V^o`}c+aNf71K`k!-KDb->rnjTCF&2LLLJk8 zeePDjidVZ<%g;%In=|^$aIlWN_=flL!zyzz`@e+*7cwSdOiiULI)FczGa3HpKOX(r z0K+q&F+SE{qIXCGjLjj^#8R9ja6elqlQ^kcC0mo{9nsuBvoAyudEFyEzdI?5+a?E# zp?1TEDZBvJEqa^^?XYOZcgNjjb-Z!cb6-9@_}L?HIf~j;6q44EhQx0D9XV9oQuD^8 zDF#qs{|;3S8DiCS0!LHwL>L_xFeIct zGqF;OzSRP|m_@1M%Ht8GC$$G)+D>B;$U^QXS1n6KQJ9qPf6gfc+l&>XA{`ZkA`4`p ztR+*gm3}dO0F)7d*<_Jf*+m9vOVQ>GQch z5chK-7@~HXEPblpP}Aw5I5y+1Cn9CUeyPHaq^7(y5Wam*Ku%($_ZrKGX1nd?-HH-t zG!lp#5GuVx&qghO3}9>M+*lEWzmYkvvS7XH(M3OoTK`&6er;79eBfpxF_HZ<5&v^Wh@l&b*lo<4;=TP195Joh z&OOSym$V#Gn9!#;_&0R`vXO7{aFNt5Fv{vWDGbQ%gWI883|2_|B)2* z{@mygS}T9X%M#fGY1y#c_k(6&OVo>}B+ySAQHTB;nZ$=5eF!`}NB}VvTKU#0nTAt= z6H>r(LJQr<7Y=PAl)DOnDnBOlk)qDQ_BGV;Ddljvzn<|wBfb{_n&dJ&ZNN$t@i)tc zBTL(ceCzkC&6eJEbNkbBKH#sEG5=C3H*o)axek5H^QauKv+ST{?>Cnd%6B?Zd!EXS za+uXxDhonHfZL*bnC&6q%Ln`#7*_5OuPf+aUXxURn%v*Woac(Tbaz)Fs0_M_b>D}- ztF;Jdp&f;)<4N3Z<;%wt$iMe7=+J%q@KeeeQ8b}yb^Nyl(#!wjo;-z)%%E_R3ABQL zljhPJqzQxRttcK&5B&!9G$v}@xHv#iB}M|(zp}=@NYJ$L37oiQ0LPt>L-D7(?*EQn z-~Hcf_8ETn@r0Jm*U~fB#bBCE(yTq{T%maEU-SN0=tJ1sAm5MD)rd~$IV_YES}k6z z>|OvN+|3KRAp=C}T8>%Fn_gbL7`e=Zq`{JKT)|&nO~}Bety4iG z32yHEO9QNlEf{XJsDM*)lN_-Z8oW>DX3GDn1+O*h-tn&pp3MS7mdk4|T^#_FRPqI! zoa-7O^uo8+7@9QTG+IZH?zt-_!KFVmDEDi;jzDE}KGcijJgegI#+NpNG*>xUpj2_! z-{CaSOnHQPu(>Rn>3rp5<8f%M!=(nnSl*F5Z@;{m>S&=^nx3p#iuWebS~^^IE!9pu z((9)GNO;4ng>O*0rOaVh-g_Zubntp(W9^2L36p0>TM)DQcxm*u`^MO-%Sk0vwNaS= zuaj7Nxp#T#=||ZTmkWb~7vSH`!eG$`svz%GD5~dG%dZIU&TcHP&0J74twwXbtmeKm zu60`Jar6E%i5{3I+%isig6^^8mD2p*UePiXBf4OIvZ8=q3FS@fz*Q%A%8{B(oVfoN zi)UoutY+84J2b(Gea7X7P7j&$$m*nX!~eqZ$nxG?o6!8j@f?jjW45|8(m-6@+%PK% zjtDF^avAqr%qtQmG~G^8Ii9<@e=W9YIhW!n@mjHBZraWTQr7em$+Ma(IdQ~unso=V zd3X}Ue#bw9IGZZTHp16ZDm`Y1VEM|x+2~txr#vo zC}SUujFd>QGn`nZ>dI>60U4;`mRYmTPL$Dj%cQ=_DQTs~%5T!4&(hCh^bGJ!6TAyg ztXn)T>=0fZ#ajpDa{a0+IeU7ki(UzBY)eMrYDLfn0V?B}pao>qtvNo2;UX(gF6a^^ zQ!-qMTDr(C0|92t)|(C)l&y)2M0s7wGz6f=xZ{?f)=`30z$e0GqWBunNWvCHTB}eh%LPM1`6_V#K{<@s z;0n9U8%8$+;<>9AZ;ksj5LeiF^%IA5JdT6wbgMMZx~*D>8KYt8RJqzGen@29m4kC5 zOwV7!>Z8#KM=LywMXKLE^f7<2!&da2L;2I)0?Q5M@x#b)12+omy4aGq@<2GqP_+zJ zHuhBBS)`rJDXTZtP{uVXA6Gb#&J^CtSX34Ic1WXjg{yh4Okm`f3G6qTR|#;p72c+L z-vUZ-liJRIbntx{Km+$>MT5kk706HH?pKko%0FYt)7mS7OF2|5b7|Et#Pj;Hj@N2u zUFB-_NR!pa$}s1;==-s9B~n^M4m4!C3)m|9<_#=51qOK z0^^RmW0yltzRRIy@(vyrtjTJOuOIJ)b2E8Uz(ie7^74WsIR@;yE_Z z9O=JSU1wOt0sCI( z%=za)y@4-q@091;l_q|BBDqjvUSX&j77Yp<{6`KtINtynsr5JUyhgOSQUzQdS515A z%cZX?ckb8R!jdWd;e@Iqj9XW>mwUgdasZ7YVbQlRNyskwz68@-sx=~ftq0PjdR~c_ zZ7e2sUCV@zAE+^5E0#`RDPeY0j{odHHhL%*2E&%Sm)DzOBx9VI=4y=--)hH$bK5ZB zm&jO4dKyzSIBl*bD~2}R9Fz(7cJrZC7nULSF&}{_kBZqkq8SjQ#&JG6w_p+G(X44! zQJlQnU1U7_Orx}?iox$n0E7u}8{GQv6&8Fhq;)g6+r<)ugWi6i*k1A!>_PeH{A7}b zAz_oVBjACBB^UQxgT1heTPQ67XxxQmK4QPEkiv;5`={8R(e!|QRX==}F5$l7yC5V` zO8fIc)#k+e9gDbVen(OeHc**%Q-^#pAzxgDo;;zz+z(Q|_)yfR%Wu=pRWXBrHBVhC z7>q>HqidWQ5M(74l8)`Ll0eTWHsgJn{ zL#r~-BCOX*9MKQ?5O=&CR$BOAlq@uA#He@0$3O~;=0&zKcDLv#C2L;AV3SM#z!~F? z%aK2HhN$!FL5zXhX`L*6WBUmUwaYeV7+UU8%;;d#ewLmye|q14>EK>_GvF9>FV2-F zoe*ObD8Z@Eh5i7k)O$+#r%m2dtxG{OCk=TOW0RAU$93UpwE$l>1e2ZScZ(9Q7(QH@ zI})t5gwH_qr@Z ztLUSfjFuKlZwl@|MEpUQ&6GwC4oby#uxCdKLn?Bc&c2;(bTJQ+M0p~r;LitsMj@|%XtUxX7}=HFn(}f!dvj4}+9!#R^7Kan*h1m#R#`XU$~7vu=7jy* z#%aSc-pQ7Rh$KZJ{dFTJzViG|^PQaWFk{FSU7D}rbSG5$EJa8WkK`>4mgu_*uvqPe z%$Dl`>E7mq%~5In#Lb|{E%Me*?lNVcLemms1Qr#-JTc}=dg^Pj7>+G!e<3@NrfU&L zp2vWpgl8mW+a(&dkzl4rNcT<9Ys@4p7-Q6LO|M&XYUsNgf|<`31=_o6EduM6_Ja-c z(F0Yq^)a}gp&aBx)yFFX5#W?R!A33p9mePg2k*$-)f>`r%HCU>hAr2p#H@y*chl|K z1JEQ{dVCO(g*$KW&JLBl=3yEcf^DGM{HQMZ6(QL9D`%PU%3p+sgwJJv-uEWIj)tn^ z>1m-WnXCSBa*Ltw02sxY4KAZP5hNhz{%e#BZS8aa+Z+i^Qx%4Hk(_-Wo|^ZPYOG{f z^)FCpvs8bEZxWJWVg+J7>k<1s~T?-2xq+xcPH# zt!1}#-B%>~haWI)*i0PSm$eAnx3Y&;&tVn}+)riklLfl4l*EI~<(@1ox3aX^+hcYs zThN!C$h9U4t0H}HepM>9{=piS@vYe!rni38N34_?DxdVbw`rMoe&}E!s(G!=T^qRpLZS`?C5sf661SbCxQ}1;>N?=zIOmb%=bzd7xYglF6!F^PL1-5A z{5CQ;_>Z!taha`7;U=!Ru10;t-N1&k!0>9S(+EfX2z0Lw%>BjK;wlj*jZC08&+RA& ziGHwK9AkqyWTYVv-mM2T~bcAvcj#sAK6XS|8idzwPJN)n@X zl&FRHvBr3PnR$JT;*h>Ls&ueqjOZAPawoXGsH!^{c$54nDN~GH;tMm`xSAB~nTAK}BF?cNAYuul;k8i~0gI1!nMwGYV znKo!@D6<;UYl+g$!dj5Rl4pJWR?|`M>uHr#Z(9935TT>9=KsC#%n(8^FjC5BhpXla zg+g%%!{?55jla{dIXE#x>lMoR&rchA(g>Z(a6e(ITB;bxOEX(}p~8$g!|bFnGo-7U zr_JFQKX8^dsBFCYWet89rrx*vhCn@s7NbE->TmQTg@wO{RBoQ}D>`?;8~Jk+EenLa zTwi$?x1gRPsoT*;S&GqwO4uE-A~rJmi2{392Ewv;8jNixCbD1Z{|fwe26&X$=gOd1 z%-lXMLJqR^qakOf*I=vUbWyXhK^g=*oINwZJt|ykI`dTjIrOAu?xh1alFYfqO^gJ` zFvb05q%uFNN%s3SpJFO8t9=cp$m*RJQFgTL&pYXt^nVzE^Z4@8qFuE|!nWu(X2)@) zt^BReBVA|xB4W~hMG6)vRBw<4UnKFnKV$0R|ANdK3!pQq{9J4kFC*DlWY(DkPRIDd zNY{m^p53Q#Kip=TWwBHSaH=#?xR90)mvWvp|0g%GE`@gv&qb*;qO#t#8M0Cr+d1(e zvc=!QtDt-S?9NT(Ho_z^fLRsE#j~bh3x^6<;l4OTK$2VyhbeDu56>4c#L5@1am{pE zD#c{=uRcdKlz};+c?2S_GHBz~SQp*aL{EOSS(0prG|>`ASmtFk@7rs^Pd5?tC_wwR zPcJ51ZxAhJkY)VR@g0xBp{|w8z^j7yxe9|c-O+#th(nb3FsxT&Z<$R7n74hUO>Z); zA2l9VD%UNsr9-?>#45FXBIb8IA_Pj)F^o&FqeuCxDp6>$0%FA-iPj|e7U;_Ze|aR| z5!V2UgEkLjQ|%qOUk%o$;>k#jfAteBrdJHb`a8Cvx}-wCN=-z7 zmT9HMBM3{}3apWK_;k-az&J~uba|$+T|Yvst6j}UaEM6%1AXJ?{bqJ+WcNGY5c(f^ zwfVbJ@~`isPqA={IhCF8xJVtB=M{JcTC&_vlonXfJABGVHkrRhY;R|D@q+qw;Cgsg znw?>VEZ1$l1*cd)=gJpO{(V);ZD?Chl`FJ^V9Ryv19(b8Et#v@lXrSWDen-mx6HR}*J+Lh2chXbE<0PIo5=7UX*f|iV z$4Yxgi&tTA!Uv5QTSAL_hrJj_qjnK5F;$33rzKH*SUo+`J(aex&(Tr8=$5hJW(xG8 zFWe3b)qAS)iBEYr_w6@|iR)<2S>wYOsqu#VEF2gt<4mDa&h5DUEMM-|> z=Df#K=&$~II4YBq%VCjTyWA^3P9?uKM6ATt0aP?&1d~o@LMuEo;NP9^>eP9F(L<+~ zv>E(6e76GGTkbwZc?y*G&`}C|(MAf=Z(}pgIcq=ycR-#ayKcfU3iE%bcKW^5)^?E0 z<>i|?mRGE|K6Q@K)+hsYX+)h6(Rcn{bRtqqn@5hmr@p$yH-@l{6{|zhKcVFJP#jbV6d+NefPU*_A`Xi_oE2Q=)$n9{ z5X(9z_E~=23NJi*m5oZD!zWH3OM}YeZCLH|667;i!-Dv- z=3D&XHO#07+46)}7~UJabZ*(|Zq%_>H=(298SUfS@A8t9YrF(%r43Df=8hR8zT$Ug zyHDYfqV9Z9|D)p4Sa|mH**x;|M_!ivucgCZz&&_I+iPx{8zj4{ziMQwK|_n;Y=0w~ zszo)0dN=CKnqw(i4SuV0%;ANP{Ga{{g}d52kytG5)t$no^03%)?}mJ3=< z1)nj41*xhw3SXG{o~O|c_Ud;c)GwN4BbZnO#F+vUw;r$w+=CUz0#a1fx zg_5fs95mt%(*mORn`i`%gkCVsMG7v>;2a`+u`P>?y%v{HP^qErlePBrj=p}AE zYjb>IuxIfp-_UWDOKV%6_t&xHVdEOEk%L&@8pkB*-}8k~;Bu80y~lB99!%4VD8?}+2FXUFay!x3^;nRa#!3dKE^ICEw?r-ECQ*U!ydYt<*#boy3@t+ zo%$Tc;gh*84roDL2~MnaL0yr1xrA=8O)r?CnfAFKLB$vOj}#OSQAiNf**@;=W=YCL zs@o;Vo#N;hp-~bbC8kitmEurWNFW)x>HqXo7nG?x?7kJWVeiFIS42*2lsM7kdl=Z` zWy8b{GIA0~Z3$nNkzY3o^u`9T8e|1pth08t!-SH@7W^FL)Y&NC)QPk@+*`6vJVLH+ z;3FgE^2z_vHM7CQn@F$_OLMRLM91`P|JDrs3;R$bmj`4-{DBv1tSRiFy9-K3gmTsg z;$s2qaK5OX#Cu@^9SuKXi*%o-LNkm;d4it~iizmFOhsbFi0Nl)UD_WR(5wNY zmJ7L8G@a-6+x@s5J7TU!0r^8$a(C#_q9nOOx$aO>Y%jJyUQQ{%mj_C5QpHmS6C$m3 z6uY-3*R}|mwcWGsd-`4T1r4dJiz|k~-dnB4Q*2IAw7pT5{lJ-bBUpQqz&61Et&42& z+EZ9cLA#H6me-kdfl@xu99Y;G3N`vvZiKHTKMfZNo|h=LWO%XF{z>E|%7gaAtm_Vk zu;8TE{*>j@J3JeNF~l&eAJ%J(nyv~wImha(+N9H(1Vu&##oNy+Y@_%CWBSzxrELjW z^J-5NpFVd%L;d366qxi#v)1sHiCu~tja>>sa5?NudSU;#n(NgA{2#4Fk%;;s0J~G8 z^?{0_{tn$Rni4HSlMyFNP%p#n*2Lxw1DRlfn|zyR3A8ofyuhA;q=JAY1a z9zjPcZ0NZi;A{!n*tZLhKXHYa&<-mn&WUew)^9hHo;TsZ@7?UG_+Y&mru-C|gNTi?#|U7A@&Hy+<4-nLO(!ZL7J$qhcu; zA*=Y43)rr!-%<_AH?&sM>lRrv`IjqQUU&dSon-8aU|Qb0gDN7$9?arnYLLc!nj-w?`Xi;c^z|rlS3~G zqu+#CwE4RWf}Sh>!rh+x{bfU%`0Vsw+_N-IZc5xd#jQqkl{vj@ekYw}9MK^i)IvR^*{2@M_MOLGU;_iD|t^0vu z3eTkw6FpuG;EP!g99ng=K%1}I(dptaTce#ge)f_9qhCk$*EtnB~o%W zRlS#iTOK~orBv-@eK=985#pvgqOngpmMv;e-U#yYQq^mtcP|g1WT8B2Gdkd%CVIqFBaG4@{mRAT5hW|!0^k1!H;&+5ONAwJMg-d*&d zi=sBFAoR?8yJMz!#1K|kK&AG@1LT&N)~zs3f{IDr)entlG>p?fry6CA)~rPzvO9NV z+dqrcxgBM#*eR@9R9rO zpdmCu@Y+tnN_eJgMRz*4*qS(LF{YQ0Bj&CKRU1wT&2+~?j_aJU^IK0!vR3|Kzg9Vq z(2i}Rs?SBGcqGg#sx&v!^I@dI_)q0C+cP(f$wXW!8>%vk)>XYox|P-=M*pnttJR}& zonWzwt;wq`xuEFAW#t`Hr?723z8K8cq5!x8%I=;DWJZ2&d&#lG{m%g!Sn`P+ue-4a z&)_)g(SxGYC=vFI7!EDR^HUoxDqnYh1a#8cJ!J^<+SDM>x06MeL>LvpNv~U5D3ox% zGViO{BK3j2eayL$p-dozd{mIm<4#2CA@$o)HMRkS}nBlJn7f%eLO?*RZ_z zr#+e*GI#Otbd$6nW_%5oTXQ@Nl}Om`?=EL0)!)h+ZX8!Ii-%wmIxm$)y=4pXd5zD$ zn_)xt?B^$<*8pnL;Qskw1UW+P*JcaJtEi<#0;%p{>C*l)b+?T^Ewa}7-uJmN0%l8j zO=s7<>SReQ$&2}_NHW(wi9;OPl`DSLs*Y?jg90_ZraAf+)L&2i>CH$SCeDHCxc72b zj64aO(c-W4CPCl&ES@t@gWc=yCbM++UGAmnPc8P*P0sbHo?m9q`e(ZdvlSJCgM*tg zf-w_2172=xDGOnWx9L7`LE*jSiMWvy*Q^$~iz0eoR7hbS1w~6VT=C*YMSi?uwa9vW zv-sj8YtO@~SK~$Rj|A7=b65zpT<}THc0OfY4ZNx@6{t8nW_Ocs@&3{uf4+;Y!eKUG z{^KM$G+Tlii^iCTFtR=5wM3ZH!ICr*JbfofevZg^p%RgRViT=B&MUuHPBNlOvgX>B`6iyjVT~Oxe$BMT~HGP3<{}>7N zi`#3f3_Y`N->#U?$h|t{zZ4t`Uaf2x<$XzLJtolc$o<0oh`TeI|7d?Z=Yo{SVdx{v zU0>MS5#5Bw_2~bPvabw_s_p)T5kxwNkcMGs8M;HsfdM2W1ZfZyq!Ezrj-dugk?uy2 z?g0b^l#p%|DUpymd*0`H|L2@<=X~*+OK05oUin*buO;r5?TzbYr~<}KyxeN(idCJ~ zsQKl;E7~Dg_xaaZhPA#X%$^cLUxB(igqNIur%Nvd3c{4Aw%3`>z3zP~8(st1@X@;ZJr!w1nf{9y3Eg>h5|6Y{IDcfP=7DFl31F^%{3@=d$LRMu;Hplt#1W zxSF&eIX5r2Y%KR3Sy*NT5AW~6lN(NFzJ-7<)=rEnRhL@VHzdH^3?Cnp9^;wx*P_Kl zM45*}LFKB-z<7C2Kzbg(4(05cZ#rNY!?hkfJ+I)@^xxGSe${40;SSYrgJs)LbgPXN z=`3Bniu6c4ga^docYPf=S_{D9RLWqJO|FcWd}u#))rGy=Z_gj?=3bU1z-12L>B-O@%qxS zGeF7E!k>c{`uc>+7S9i1~UEs4kwp^NwKev}Q@qOKG&F=af zxNVDa@AeCE(~!Mf*dCXpVvxbBM!Kb|b=WP2ihxy%1PU_xk0^j)<1;l4V3~0ZfoR@` z@yv#MGm&AglrgeP{t?QWMW z1sqsF99iZ97Bj4(AqxVm*Sl|*P&WNMa6;>+x2HSX=DlI;x-+p4GJFQ7CiZ>NUpo?R z=gMeIJuXt-Ket~0%*-VE;s-@#R{NWksi8dYA4ic`{! z1sRpLsp^QIgBDs$X{0j@wt8 z+^(t=z$L&5!ZP_Hc1shiOCAu=KUh1$rcFV^f_W4gj9ETy;g-xrMd|~;B%wL*`yk5J zW|~7VKBXJ%$cq(+pQ^jl9;OLh4a$r)JFNtO3OFFAhqJYE^35!h)Z|mVqNN|g-u)5caUT_{(0j^wMoR8wP<+3ZkKi|v_i2Cjo#td% z1&ignjW4zyp4yI0u6ZK~J?crf^cDxKE@&6GP)ZJ^-UwPsh?!_E)~ z7fZO_<@OFN^ptuP1#AfzpP$;bX*Z!w5kd@1;r65IubHPO0T&Keo@qw)qh3^SPN?9P zVgVZ3qzmX|RqBRMsls1i5kzXIlyw3lZvXIuYTc`X)IpTROyn+ONq0nKuzJoQpqw9S zIJy;)A2%46b3L^TyKW)0DM1_n^;52-WfSK9tf$Q^$M`6&sH+)xOS~B*Ylxgpn(HH{ z+`?}QBlhDvZ4A4U@FE9BvomSj^&{d!sRvbS>GRZg{J1d;UulfT>iyJ&cEdLljd=@> zF;)_0aXfszNN@96H+r#GAO0}Sc8^Px{3LE!ibpH$^+Iy887r@+qc|OV)o3#gS+)9*xrHx;+v!|b#3!0z3pNGJ(-LJ z0H^d-!#G!54X~k(G-*66L{l+_uYq9xRFhf7w)G%XuIDmSt)s;JYK3j#tghr|j=QgH z9p6=_GxqYKFzY%q5|L)0;~wzb3K4+9C!&mqrS991dv_igt3Wnp=MJ}Mz&~1WFgdHT zQ$&_Yex0bWGsNyev2Af2f=N(yhnwBTQOnmy>fRpI=HpW2!ChV9f|@5PQGJbl>+Dbs zHDAb>jD^%At0{KN-iPhd*6;LxhWYFW!X{XRiPTUy-EQ1_t$S@Iu)bQCuU-ft3&vES zz+l;}l4x>}On286@C1>T*4x7;A$+m*u;M=?gE-5<(2g);Tm;lYlgbW!n9vG3r|P%q z_3YU1wE^{hwyy3bQgl{H?eha|k-^>sN#fuu2*l>!xD0$!dn91FgmpkFBgSO9wL@2N zyPI_zN6&WJC?m{x{T(cRdVOQ5I#SMg>&t0{n7h6Or^V6gY4Nl*4?qU>O=Nw%iL%M@wK$3Ej@Cw<$DbaT2dSe({MtS1Lm$lD<#GJp5cy5ag`*o@ zJaG!DwsF@Wm6`ONYieO3_VGpH^IH~>>BSfkmnAINDi%{E*J6L9K~~018!H=AMz<;# zrk6lLTF8N9@7uwaF2ZFEH47B1Bg#kRC6YY$#wiYehr-}i{$`I4!Pk34QA{P!S-;I( z(KL z8&x?-KlLZDbK#`BaCEKiXyZp$R$G~#(^L>#mBDqoPM|tKacx+Fn)}U?u~Vi!5zOY4 z`HbKSMx57*uflC4qLYS&vKVc=7TkOIxK)sFiH!LYHOmh}G;7=iLqcrS|J-&gjLk4u z^N8P(>3o1GwZ>M;I79)YpB3Q&mZ?u^YfE`vRQ%d1)m2FZJ`AvUWLvmn|_vEciby~pGH35P#CX^#bButNEZt!kr$b=WKlLvCs)8T4ilm3iNjKL24@p{!w zDJlgwnSdXys}@c9ys*VqNN2sj=Omon_SKi;qX5r?lEE>RF^MrAHe%lwAUoQ~`Kj1? zAzfH;Y;yIFa37U7RfU@?i*KL%eS7?CArSj=JQJh16_NP)7{ZG3c z#j>(5Q^L}cUEI=Xc>6d)?Li->;hcF(H>Y^;^As_0QWukLbWotSyZdlOMioH%dX9C{ z^2dNX2Cr>il=MXqryP}RcOE3r6Q22>n@?ZL-F1TzF$aEvSOU6$m$+t|u?VZ*;<|T! zY`l2uf5ls(FKN0uL7%TcJ17#+XE|l&U8+~2HAP(=&GcZ66-1jN1GV^IFPin|RYTo- zvZu5ujQ+DA&|Wx>kg5Je&ZIY!Lypfh>+Q)rV@V)9E}EdVhH}-1*a4GCgF-Ni7&Oo;ebYqm-cMi+_{##nzIMiULYj z+<7h)#UXPTV)^LNl>~w>pZ889&a%c^EZ7`v3Z+LbE#>W7z`oq&!H^iY;D{3weq-}| z#sZwIsDh1I2mwSNaI^STw00GZpp|q50kkWH#rTybejI)z$QtS5ArYHfdSXlIg99u6 zen7VondGrXx}58JirXWCw1N-VAX(IzGY9~qMc+6|IELuxB45SS>@yOc=cC*zyad=r^CE*nTpf@eU79Xy>#X z6T3D;;DXSX4-1|C*2AE0Ug_9@0nN4pC$Gfpwk^FLJy}yS=4ka2r(h81>7jtq1q0-J zH0h(#gL<_qy)!*dGwjF?gBm}G##cqD^#8m}N)~?j)xv;$Dj|v?(n0m811GL*oAHje zzhPVYBdzBz|Orn-LA5#1}GkEedrgLfJOBV>UBF`81!*9jS8xRYpU@28Uubx zXT1(M*^kWo`kqgQ6Kr1$nEbb80XNl}aomBPW)&2nHf|C5;lV}19#q-S_Ah6e_#&90 z3nx_~uZ1IAq9AXE4xiAXh`nDi9&RFG1hmB!)d%5Oa+9ifay3tGd~&6@S4esAf*ihI zQf|7juqp^?KC6A&;rX`xqX@l>oJAB@pRy$?+wS)X4-pOC+fQ~)Fa&m=a;&A)-w#jd zz4GT8yDrfg=KfDgj*lCS^@3UklJ0}!xP9lb@g#2d^Z)30tA)`#*Cz5cX13Lon>C`? zqQl~6WrbzC0cK`5J9JUU$Ul7Z%iO+Tt-5-;8h}EcIT&$mf_Z5e68&J3JqZAIpUcHqCV zj^Rmt!hA~ufelIpcpVU7e6{rLtz=EzA2{%(NPw+7$R$*tME0OV(<@Lnwi28MMHyxJO5qt(ScJfoC!4F8D?887I3&K5MLQ7xV$FBevlV9 zw1?cQN5hhB)RjYlj4h?b8<_Tz=mvWYSjtEiHz|qBH^3N1f>Cf}b z**;TD{^>Yi67|IYONaA*sPWEeo|l*5LV5L1PZ|n4+FB?<%H2aCB1AxC#LsN~Qm3UH z>Hy5I_<_SwV?*LkhlpQqEC`10b@jo4F#hv$HQRk{^(S z{FZV$j$mbUM7j)qIuUQxBKu1=4*l#D$3P9WM|_`vz|)bhkw*0`+LVLaJ>k^xz3^)3 zC`XQ@s+!ZT%lqG2R zl_pNt3qhydiM_YhpdlbElO4NBzdTg)h^x2EZRyevb33q__R4}eG<9TD|u^7Ahnp5(;~5UW9n zlsp}|?d%w-M-H{ycO_skZ{z-BODK>I$L(KTBV)bz zBLqk*3i58!_hmrGp|7n+8_ZiQ9k-{yl2Bjtu;3chY!=1SRC$=aG~GRmfWey4~x@%|+DOzzVkbGh(vKp=Y6Uk0Q{3yOA;p#C*;_kiRF z<#$~0a1CJNj!n+!1bp^k#q!Id!}4<_Zw{+$Wsfxp+eCE9QVRW$g37dlIz}jwM(gg2 zZQ}RF9D?Rx2774=5~%8xXJD(toR`qrXSTSOid$%dm{FC;y0th|?2hi%YHDoU*}NYlh@ID~ zyczSze~_Cm5grM=)TEBKF`DC7lW`duny#o;yp|Qf%76+PWj*tsxh)ud@Y7!&SeymP zd?6I%P!M6Dpj6}rl@5r^j86sUe zNeFn|#BU_q$W`i-&J$(J{SM1HmKB5#R5AsEYh1buTPyB-QwkrG_XhrKQ0MrjniiHG z_FgpQLG1Aa4E3_W#+TJfRKH(}>wt|baK}e`;X-|vBZmt}LZ#dQC6oWR*qlKlcmde3 z^oPFmC;2t~Id$>-D7x-RbKGutFOOtrY7AEqONqMKV>AiYJM_tgndf*#c0|aR60ur15qP0l(LB>izS*BS=uYs;XsG#x{x-D+M-r{?R(QU6T9zMF! z{twA>&&ts{aJC?hFd~6}$~iU04yB@P=F*Ga4gmJ!z7_DS#R*jQF0&SQQFAeeya{4n zg<)yWrtdh;Ce`3L_BMOVP@HLP_4u-~=&ezp*W>Z!ll8bQ!mKym-~Bkea32W_Jm$eZ6zM*aWm~C0pKNaO}eouw<~!hZ&ys{Hgo)3 z{3I{!m||QwtjAfarMJ7`cb88>s_XFGHyFN$yMIB1tb3ym+FM`vM$_so`982h_*5Ld zP0gUy)3n)u|0nCHpTC6(`dbTSSix%XfSl^;JsGq2A=m)!-83zCCuPdL>?B=o^J4F+ zfGq0a09RT&!j=4{K09Nl>M}g$?r%c!g%I_p#ay-Ek!#>S*XX?GnmnHVXssXj+=S;7 zzwu3QWn&+_Da$L)>(-3d8DV+boDSxXB$6o{+GD!BZ3{epnPM{2Y(-iM#mzd@35bmk z5IE@*{1UhT*DGecZP25x_8oou%F7y8s!4zxE54~p%+i3h4<}Z?Mw&_Prf_`i)rcQ9 ztu7}ZW!QHpV$@{BEEO5~Rk`BK>;vt3~sDmKrsvy0$ zCfAau_C}i7pU1kWDW9j;jQmvf@jzlWiEhlJ&6ezIKAGi+l_@DQy`f;&eg2ttyED;p zmWS8$z%frT$6g)*dcU`T!KlV({*2wjVuSp&MK~lDu;v~^sayx7R=Z;|C`-)wVl^?* z|CNEsXO}vzq-@S~Q(Gd+x1XNp1qL$&S-$=Ho{&Q95b)Lu0v&Rn@Zm%>ns3C7ls-Q1 z@^&bAUmPcHwM4DRV+1RX^1<{po5H?)gpPa^;<0hnpZobf#82|$o};C)z7mnIIF^6v zXi@Kr(kCBlNk$r|cno%Y64#5s(rfaUL-NQal+coN>%jkWx?xC{xDJYe<*!d5=|D@T1!QSbXcfNTUssXXY}fm1a$dJ-3FCEWdwfB1nC}L z12sg zPXe(a71OJx257yIJ^n+449U{7Kn?u0bQulUPjY<{1cg=oih%vwvu>UquBaRik6J_&F5N?=WKdXMgN3cKN90punRl5R>n7}j@Uc*wHZgK}Xa)}g7m+;~`qNhk1> za|>q{c8Cc-$&3pDW{GZA{@%mtF|fCwG&OLR!i|6rS~RC<(EUgqg}wVM71YC}tRnP{ zvE3Uhw1?<)*zi!QERsV}c&nEq)2`aX`wT0H`^5*N2Yrwj!iumA3A0{lD|FA)B%bpt zP<5EBMH=J>!(+~OIfrRiN+c`1Sp|lztTmIDs~?G( z-~=Y+w9f;B5j@>+nhea+k>Xszwy?%VSWEw|+-f9ZXrwhY#C0ygP zo#GBS%n~c{263S9T1eBCrHKq|m1DVgFVgww0k@qIb(W2k&-n2#WvrC=VmON=fF~!? z>42EV$SvQ8Y6rU-qE9)@I>+t0cKFIlAx03sBI$=C97Y_!OC2TXklGd%FuEQOzY<$@ zTuFjdfb`*yCDB>lcF2VncgM)Q?^8{z$49SjjC>3(T(h@Al$92b*&t8n$MkKj2-qNc zBHcC@=8XrJ->}9+j|{qDyJQ1xyA%7^NVv@*kp<*1o5Ug&trcfC7NrO*cjzqGaQX5= z^6p;)y1v3nB(Nv14krlTf>I91%6mi0DCVLQC79?bBDE-f@-_U2c}*dL(On(2=*XJe zb@8E3rgYEedwyzh+t})(XtqB~MtUb?KhxIGG0T46TGU(l=(FD=T+(yV3w*)iu~UuC z5TLTB{cNVZ@V}Lde=2*Jh7zYg8*`-!Z!wj<;(05x(Z_&&)vJ-lqxzzZS{J71^fc%g z)#A0!kT)h=W7kdoUg#pAuH%OcBaFVogWGCQe%~-e?<_}c>#f?s$S};ltWE>+Qs|*E zX&jtwBr{$9s2dWfiO-7Hkaz!H9dY1Y!P^fknNl|=8^)t8;DTW~Y}?A1-*ZBvRwxMl z${Pp)eGnv`15f`R^ME8}0=9f10}`ePqQ&nH>)Y7wy}ODP9(IMNn!4zLEHv!r*tqIt zWsO7%W*dVhEK4@NDb?4i)^AM6CzOa6qxfOAk>u9u#^FUW9~)8|H z;2u2;41fw*!GI;{6@PRfR6*mMI(Z$^oxK;S4gJ&ISmA_ySe$KWkRChn-Ae5j$Qo2c z1rxAD$gKp`3HMh$?bhXTmtyn2={a0xXcgk={-_>F!tbyW`v-AvJZ|x+@Uwq#KZk><{guVFI8{?;J`mMsU#?%f<C;9#dPt$kT!aiIS0 zgKl9K2fK`^6_l=GHS2luX!)RIXIEMkff##E6&}07{GcSn`&{$tKINh3&#`?3RzP53#E0Bk_4?pp z*KXwD1KJdv#5)yXiL;4!#%SG-b>5HG9SfCWqKPyfTD|GxlBSQYSbpWW<1(p-bB^Qk zm2(|1w=LFhj(t3MPmlW}8swTS)q7Id3>CxAovXK8JGHtv22*>OxC_;~QRxSJnR&vu9eeV8S=fgxtKi=_7z;P$v0cOo(n$q348RMYXyxA=fwG?Ss$Zw6R+PH7I zkb&Rda!ohR$KY;hM_7A(H{(F($P(eEJu)t;cjXX=nSP5Z>gFEzwLtv3{63Hwylagg zp)kjN;ElFi`<1^yqgHG!og?GFOE2Wg$7@;@UZr9~CWP25A6XYJ1)fY~@FFBu>5Wqe zFXu1gJ7^$#F%BjgXg|<^m@}^G_rZ3Dap<>J`sIW4kCrvCux?M_N)Ppud*TwFPgXlc z{1$*rMU{;%q*Kb6Rz_Hc_(CJY6x`Hi9Xi+9WnjC8Y#+9*BVMx3D6eC}ZCn7%0}kRn zhe%;KTUvfHsDvfkA#&24q|T1s?*sCu9XfzSR4=N5!}=8~-A#JI1yC!!*!>tJ$iEPv z6EHH0G^hbi{6lnu?q3+sgn{vq7%y#ZSF#bZ|8Y8I{meL`N>;pkbR!Q)n zl#q);E+uqvYREU~n1`dpceb-s;-c_qB6vCali%b}8~AFOkj9nm$y+JQlOcC6GMe9F zr5L|H>C;cHzS3#NSh1?V2ww;L8cko~BI!V2hk@&0tL2JNg!mI7#I8YPE2)lxTJbk- z4bA0eKr11z2Ci2xm?k7yTxVDXj5tN%as^qBf}&2IPi@Rz`ZOwBAEl0`Ll!&mM20xska zO|w7-aX7@RrC8~xFTq^)Mc5RIEDX>Icp1E=+>Um_9ki4;z*e_}U614G0h86}9*;p_ zsiEyjh>Xa0fXE|W*U&1D#u;dpickh~tc}#Q=~4R*-9WPCh^f;|rNSd2Sz({Dzz=E> zWp+Hjm4Y#DC0bBfTN=yyKKDb`K0}2x*$XnVJ6ejp;q~gRF%mT?cY&9is`&r&9aHfw zX9C@dP&FIpbrbwq9eBM?p;{zdO4$g-%eSk{-JOA?mqw5kaXm&qUn{?08z9PteWguN z6v{aqMGL$V{23B}8ri}1v2VsiJiq>GKHUYF`83`}P#&0wFLgbWi%m;c%xB=qKMH|N z9l|v}r7K31rBnPi?MIC`+*ym~_8rH@Q&SrLtnbUM|D`c>U57j2_ZISH!6X^DdL)y; z3bEO^btS@>SU|-p6kEfN;b>ly0)Km$8;+qWY6@t+j23 zAyk-+)I3Y(Fl@8ax&)Yn0+g2+?gKf+VwLio^_MXD}cvcee)mG$d!&OQ_YL)&1c&iYPt87+*Ltg zPi!FZihdv^RBi%};viy68RiuAa(#Xm22HVH>q|Y7%NpP{1PuEo&)|B6PSEN6i|KXe zQ5^+1aPZCH^fT);%-7C}Ki3}rZl(6wfAvOs^30~>_T2U ztE%Rn{xzSZ<%NKh+BuJdKgdsrwSqIp@9*EL18=vN0Sm2XDL8g=4pu_)b2GSmUyMdtA{^{8UJfu#EQ}u(wHi&z$7?=*+-r zmR#2KYVWszuA!8jgeyj;5(KaFZnp!aPE=J@Aq0?tP3K zQYjsKDe^Gb&l2(STjj3a6)4xLSfl#G{?+nTPeTfGLsj=&*SYq}Ylxh-E15NRcxpG2(JGCRY>%g;>ak3)U zd3cD9Od`F8lZhEm9}}XQgCdQL2QV|e;!jM1uij?D00|b~B^)2s`3Jio0KN`T#YE}^69F&E9hx@6 zW=ya_Xnj26bMn_SKm)gzO07WgJ?U%a_O%0&vHP^?&;MFl)#RxHzuT<)mSt!+|1zt@ zpQ)zZ`cn^{lz-z3m45#`B0VO0l`^5kr)N2mCT#-7UE;Ny79Z5)5k-)VvpVpKlVG#{ zLBP3jI#Y-EFYo8)KWa3M0)5j7z$JVqz$g?n=Z*q^U&`ZBZNh2w)Olj&3NgK@8(M(y zw^q1OqX;;#i0OuDKw5YrNr<6o z9kIY!+x=>Yv=~O+rH;qiv$fjyYEHi|zHN zc&E+U`%C1zq2l5`>g_uT`yc12hqXx2VV81r#eO15gQ;O)AEEXer#_B}D_rxuZ*3>5Ou+*<-*JZF zUAo9oc)c7!C>$1-S1(Dvl> zd6n+1?DorUZS?vIPDq2UVZrKt7uKfpH+>Y%h3%>#jQiAYLw7clEX!W zf6c3*y~op!Bv$O}erDrAF^MF2S+vsD`_Y{Tgw6bFHs4U(|G?UOkQqi+G#>|FVYIKy zGw%qw&1el;Jp%S`D-{A4n@moyuf*OEq*k8v8~Y**5fO^Tac5?HOyH>Z0COaGj!;jz z72Y^uT0%{6yJ7h8h4e1tjlTBsd;Ls%c-4*mUu+z)oS(`UPO8F2=GTOKr$YOc1eVJ2`%To8(`1IY%|BvR{ocY|8`3{Hh zFX>unw2y6WX%HY8P_Zx=F3d~HW`&jZ@hTRhDtcHwAS9>$OItHok^5Q=UWRE{1=Lmq zLjcX>9GW6fG$#APRvw&L+5z$zLcOTrnoz^NUm3IvPFYPV>+xCLELB*;;KmO;XpaaW zx$5yptjJ}}4PU?lu9lzL&5vIl7IvNgw*OfQL&Q2z&qxXlcVFXeA@ImsVB8WpM9c;W zVAIYbZV^_FclvOq9e~7f^4f=2BULCq?{L5&7`=0GxSpdi514N|{TUGF@GX7ZfuG`c z&K-<7%SZC^v2nS?B^)MTB7dS%m|5>fE5vNHUZ{Jo7DL4A%>mwaNZ`M%xcd17z>l7= zG6kyR>S9tY|J5pJGciw+8}3y#YA1<%^U28G4Cb0blYYuJPZ8FyrXs4fGh6O_E($IV z7(742hIHu@%5^3EQ0MfHHAOF6vZTIxIJBV1~7_<;00Hs!d?_87Ds%;5im#q4C9CnulbPG3Jw{A?Vtr*%mxRy z9G@N}iBJB(JeYB&@3@FcL*pOYfX47c=tppCKIjwXqp<$AD1AQgE_b8GG#&@HaUWik z;NfNa9rkD$v~6?Z-A=Ds92`h6*FC?E14cb@7K6Ak?pmFPhkXvnr?G=GQ>}o;hz%9? z5&Tlfo5KX>)p&S4@8!|WMey}(xAUKh!qmtM`%2InE0#c0HMahw3+FNalBIJ>;jEr@ z1G>WYDWGA(&pK{;Kl!g;m1Rl6@3;Luh^Vq&-g9pb(B~SPCH>>AOS>NeeYiOKEL|8x?!5TCeFN};W<7jn2~@K! zzgYI4=>6R&9p>W!b7A~ClHw@nJ`bQw!~+{;Buu6rs;|ADhES}<<3GqyfMV-Q)wVo? zLFdQ}5g>keoa7uF|954O_q`y{EbJODs*3})wqf#zi=}S+xRQ3%j0WIOWo+fH#BQnQ zGIn2TLc37L1qRV}{**62S!>fB)L2{99Wtz^+k3DWu3NY#CkP7cPk{BJKeo}S*#>9s+VFILw-WkU#M;U>I8B!6lYAe5d1ZIm>`tg? z87-&7ddu*j-H6%2Zv4xy-#JcK*e#%oDLS%7eE--iwKm`sNHfJTW^id9@bO0p|HOhm zz!T9Y0cP0*(~p4ziBhGMjKl%|D5RHG#&z#kQ&}n04oR?~h@FHutP8WDrjfP`7Cu{N z_i8?Ho`~e(v$Y05L0z3M=Z_ctD2gYHV+c$i%dAWte;0Y@Q~#PSs+Ngq|Pr&rXvB#Qw0d%ND!|N0Cbh|PcK(H<^P<9I#<1; z_z$KI!%+VbZ!!5CK>d4ZKJibvf|}Li%BUY5Ghn{(4=hUo9y7f`u(DaEK#BRNbmX(^ z3%H1~+#kma`uWKOL1uq{cNs${_ul#ePLu_Bc`FV3LQvz3n68sq>^1#&1!aQv>!Zmt z`9-5I+869RkBfm=CY{?Todl?@7tN1(8Gkk?ah8+(ZfmpqqM}pTPNFWzBYwmdCG^|^okr9{Hp;h?8N;U@SmUzIQotvX+O#vTVpVBY$j+i$CQj89*0+)67|Si~^lb+k`#Be#NZ z;QR}|#fzd2vBf_b%?k~I8Yb}^kS-wfE@X2{CSIa;*ZI^FZey6TKB8^>WzIm)z!D!A zUtNr&4{G>N3wb^W8$-Q@{QtSrx6T2O=!n4X=or&t>-SY$gI*DMKkKM|#TUhZ1s6?0 za>iiZkCyF-tP6B6=MD`>KY~Ey5n#LM-?=@ic_;#T2kvvcpt3Nreb4pZknJDU&KCrp z_9AY)odB#>0LVDfh<8knm}-T}i&$xcyHr6J?T^3_%6Lvaps_$+^ zfWF}ue3D!p2i(&m2U1{9jAPtKzgxxd*34H@5|;s7>eL~qtrAn;-7}5E#860%cNqU` zqX95%u3S4kf*=(G8r-JW>bNn8IEE+IxCqFL0>o5j4ak$mwcna}mL}fR4M@?Gn}uiD z*CzYr?P9plL4A5gpL7XKK&4s~$D}9%c@NI&v8t=GtJVE!3b8_XQlm;rFwc4%On~9d zJC`du@Nf{u06dQ7dz6IHwspfwyifh>r&Xw^89};@=N(d%*x@fBtXED(F!e z)ml81zx=wiw3JHJ-?ejdeQEOa=^8^~U*Th}XC@|D7b(D)U$o&Y?5w4^*{UShe1ZjU zv~0~(YFtplgqSqey?l@%6q=ge3Nfpz4BWT*pC+7C`6cQG{VYDhf5dqfBVLO6Ahcn=Y9iCK zHV^WXjU+{qOc@_Hq>)ITHzt(l1(TgA?6kMq-_~1;jQSz0qP`Ygjv2 z45~2b#m*4wuqrZvN23LKke>X^JS z87cu$&lXltjX5z=7BFIWjj5t)15_R8fM#2R$_|I*#@aWeii>qgA>1Nrdt<`moQ{i|!~w zQ`7eP(Hw?uC{@`FJ>GjmsIMhL>bR>iYc7P_M|tKywKl%;jwmbhR%v#W+D*6z=ovXl zeii>Bl@m;>mlL+>P^LhDu}>lDR@A&0Si(_$B(9%tOb}#AVTfREZ^egARWdzGG9dNL zeR2pE+FDLDM<;(85v$R_K$cHenkjM_G{qfa8DEzgA2kHNe0#Fn2?K1|jCq?IP^fA9 zQE|1<+d=#}N%1bzWLtBStumo*#+PTci~eq}{lb4Y9XJn(iLKz`nWI}a%_F<=L0@@- zyrLpvsG}$?=^ymh##2`i>vkfYi>eIXz;EO}0;)IiYO&rXQ&)kD?lX^qcG&utD2r~7 zu)>~?=Uc&9Y^;ulypHSMo(4E%szz+GMz$1_YI18ly?4<~Clu#ZVU5E6?7NnazU~9X1SLacr9KcRBTII(j=^Hz$Iw@xT-{-%$i!oP;>^!Q3*_u6#*;JzSl z(O&zjh6R;G@IERu__MJskri?K+Zu5U9Q?%d^v@u3?@6<(5Tcu9lSoe9O<2$4yIp#|QKyy&FM1)S2xn z%10tm%0P5lnO36K*S>0R1VbMU z7_bfYo@-)6L5%a9SkOk5Mx#FykYyf+$U9-(>#+pq;8O4)j&*DOJu7MLrg;TC9*myl5@xwG;l0)eK>Ljy( zRUybV6c*iMR_=s+wIA_tjptJC$EE{;I(jx2?|cF{CO0CX=0#s^z7>~v1q z?61juDz0V*Zr409%grW$JOzjxUCm@y?S={Psu=^}xc6&<>eWApGy@@L5HHk4qdTpZ z^;M>V0JdST;p|{Qc(#iSqmXFli1z@L>u~iIZ+dp2&o!wPk@)IXZ?6CMw@DmkLYxGj z&9YKrwA6rmJRF5=lS%RZc;EK^+6NczW@!ghR)q%i4+4?t+lWW7L~b3dJN%3hmRJ#% zw0EuB@Ipm8>x+V{;0lUi+PY>q-(~I2$Y?aZ@dQF}M8bkQ>c8Sl>fCpwh-iQ7ha6PI zafmeFSsEyO$M%I)PpZ6`uC)?82(b@ex#yi3_E0$H$uH5>nL;ay(NJ>zEbxuo8G$z! z!_KOuajmL9N!io2G}UX?OxmPdi;FaTmbFLkx#ib&78k0?B~C>VsExai!30e%kKXt?@Zdeo5` zwe&Qlehv2VU$nz}#~3Iy2CF;jlbg*=G4JSF-0xbgRoM)gK}UjU?Ze}HYV-PP$C^N{ z?KTA(Be51;3ak=$1=}Imjv+MJW9V)W$1`l!A4wXnq+1S+=LYkfpE;Z=++@u4yK5Aj z1fjBBaBz@3?C9R?_`p&PBzXUew^98&KJxJ(N`n0$bDw~H$*wKz%O1KF3&&xtId(s! znSQ5`F@a+iZOZnQZ=oAjE(QL_Aae(7SDnAl*Sc!%;|2}fGYq4leTZ)s@!Iiy9llwp zEYuT1h7=2kj)O+MyOQ}#Pf5~83Wgk;7x2ZwAMhL!Yw;>2;IRU2G2a%e-n{0nu`zPx zi00tD74VD*TL9TVOLUj-xgU#KR=k^iXDRTWl+XYDykK*_z zEd>FdwH4r20R7GHmy4@yZuoQTf?GC;--=E3O~P-lbYEB@zFsk3m;hnn|B(y_bVrjc zC!-Jq=FP7}=4*HdBY>ul#hB!7EY4;CbMJ zturF#;c&$4bT}5-$B#ohuS6Zqr+N0sFJ%J~%vU)H$h^m$)l2(B=WlFD$8LRf21LU$ zyC;J0-+Rxp5teIyt>JT(f38tT6x_|GTVOZMUz5p=``MsKlqWN64c;&Khhghs$Q83| z?ajgjY4kP|DRie5N6wc^@n!8sL=2^b3bz95)uE1#d?Fr;r7P$scWt|_&1%dT^BP64 zMC#*2x55w5<2S}r6qz=O*_so(7ghQ3BUU4pTN6)gxIY}K*a`kAnB0y!e#$m+QRLyh z>#)h`ZK)VwOKpCrxwtOh#n}SC$pdCeB40-Oya)Zk1hD>pHs`Ybn>Wx4CZHlSz!!kQ zXYUr^WN3KH1KEvEP$^C?KHx>F$soNF(}s5RmTfu5a^u-*27s&pH3i zf|)gI&)(1T-1l`~L89ul%Ze!ktR#Tdsz-`M$umZ%y2eVQsfppz+X>OyOhpWG415Z> zV{}yTfSxM)+40D}MrUCD^zw2UWXmR>AjGKkBZno_ddv*N)&9Av6r2&dqh}gRruCDJg%So zhMqg$9ltH9^8u^4*z;3V-?;f$ zO~z-vFeYD_sJPSPy^@b8v`u`a z6yUeag0f`XLSf?k@#AMn6EIa4+v8cmB$F_M=9rC~`8nh7z;(k#RFjYPiqxzL+_>E# z!6J;~_mN@Dzh7@UFqIVrkq+b`UDID@5N@bO=p^a9lV~K-DCdy_rjBrOe<{@RXVi{; zl5XG?@Pg?r=Ko+dy+4us!ocTU|kGS*80?X z6c^qBs>c1_kA)yzw8ChjYTviN_(6^S;VU#m9O;~%8uhBJ;qdjL3^$D%j_QYM8)pKlM>6Gx&cn5WL?3J8|Kn2zXi_W(V-N;rmlo2?~T(loE>5I`9G*eNb`phNg{&u%R;6Ps{wZi+pj;qq(()+ zYnF-mj%*t1^VPjodY4wNmF7Wcn8xsCq=b+aCu`ky6&FzLIaP#|oC{wQy?^hzO(VnF zZE7z4k~Lj5fLW-nMG`~5k1(mB-&4Wl|;+sHpKXm2KJftoa;fFQQuEAVdXY~#h@Y~X(pEDq{R zA*ZQ0DS}uwA5r;k5*+*+U6%s+6^Bu{lu?b}v{sWzFi@%Fh!=sFYS~XE729P_Oc)*` z1|1O5S&~DL#ov2gZp+*xZ4G7y17|88hRoOC6HaeoV$?Fz!xM@h#9c3NFb7-SS@Tqw zQnAGE{N4Ot3=HYH$e|(g|A@--6Sx;qY7CJpz;=N@56s=;kW_CeIuERus<8;erLvKx zSZMycj(3DNd;dSzk$wuqI^%St{_;yKd1t-g4!7T(Tn8VYs?mfZ*%ok1uF^_jOk$YG z|0vw`&S&vNre~x|OLcZL`2KwB;}D-0;SW4*6xL7Kz)!?V5F@7W|6q=9p3MWzzI92Q zWd{g8uTG!IFJ}q>oAt&mE{_5z_f_p?N(&u(B{jkPlZkl|D&iE+56FPVM?MDVRA&Fj ziXwRVTx#kLmI)Z|q)3~qHo)5cMXI`^0rdIX|38?pH|?-Y-^*F0_>!#qb>^qXqbDj~ ztd^k!Bp_<({;K(^X&W!Y=d`cE{V3+b-}>^yQS1?K4t*0he*>9{n=iY2r2SJ5g$uav zNw)niBu(i(--=MwFx9yXha`1ygYKU>{V%)#2cp3(tuq0j$r%^r&?xIxH-EVk(afRw zHE4WGczr&hd}rwU;dY=6Pwi)GuJ2O|G85(JKCT;b)=@1~FOl1!`7GhevYGX%@uF7D zv|HD`DMa|HD{*igmti2JBXkJH{p)_|gjkJ+62oYFF;AJgF^|4s(Cq(WGk!qt{(Y%_ z#G~)*E4RMun3Sf$gvtGS3Zm8cpi`o`fzt(chLSKkxvU8@(KsxecY)7jP?BB|#yuxH zA}XLi@p}udYt@(nk0ukd%ZZncN`vRS{i~cV>#`cGv`9a{=QYXnpOfwA5q8KOOMt)I zna%HrI-mTVuN<99XJu(bCbS_(FT!mc0q>CkdjbXwVj|P;W|b1Dyv@gd*^`|P=Flpq zS*^z9G2@VmI+ey#k&1p+9XJl>=!lq5#n;VD72M88S0Z}{`4RsDE5j&n3uC8mi|Vb) z6LYtX*LL^`t_W2em5)zjA{F_QIBoRag2VCC+11n9qf8Isc%0J}E~$G~Qn&o=;Z-y4 zB>jy@8xXJM-}$-caW`mbEuQ|S&I||tCxXs^C-HsvJmZ}2kDU3t#j6K@F||7hf92o4 z%N6+M1a1LcO<7-j>AT-QWKQjP-ZuT98d;jLlDV3!SZUJxv_a*v_3vPI0O+a@t za0;1R40lge+s%ir7}rE{Za8w26Q-`Kw4#jHxmfVMjZsO^Q*`Sm$7-_3bV2k=GK2fAoAgeCSj{yWhzUjD5Jh$8>LW5g*r0 zSd_jc*-_*@xbbL+uRd5T*@<4bE1I;=EmFF*w7HYfb@#38k_9Bi>u_AdrJI$#_vw{Z z0H5A#uVbe0JTNEPfoMEbKV|3-(l$iwa^B3enO`Gk_qu5_G7v81_TQqFE= zH~rqK@3y9>^6;Q*@6yuiBuOOI0FZxT+QfgM=SVm&Pa-0-YD@j1cs5fxVtA0_Sunp< zw8-y}l(cDWJz}&($S6>{im=#PdF(y zRdJZO$H$PFa1N-pn!}V5v%LorO=NkJm<RspQvtN%Ai;_V3N(#CfZ0kk4}fkEn8F})mLM=uE8w+{(@KyAVKoBl zF6xrEf$WN5kn*C(>XnvOklmXhkos3{QY`$^0OQd7g#l0zD+nBbj09Nk3mR>nx*CCD zayKW+?_x6QUnX{WEF%1L>PuosA)Ahb-+gR_6*rXCv}n54=DOpwK8%m`P!OZ7VlfE@ z{~ZeO8~O2;4FVI+G5_=g4}kN43xWWbDV~R>lq?8RJRs+1`AQmKlzN;iXFy~Ejo@x0 zR1Jij8i5Dgf$`L6Rvd|H5Gy^JHf{I!VEJOm>oyRiR?uW@fP!=SlX@mA5LFI)flJOD zjcsFc`%f`}g)3SLtI4LOky*W^)NU^}CPx|GIO$j4&+?zMkglEES%bpN0bSqsVlrDF z`!t@jYO4t*f4L7#7ke{YI*8d&$Eb0Izb?JBVSENPSbAmK&x;+Izn_kP&4?S^A~-}* zj|+TyP8uMxRH^qwsRsUeUg}jL!XJ44Tk6XJJ+?>ksMHFpR&wbaBB15ZMqt!n-?9Nl zCy~_;&;V{!(j(+;##&<@VNe$mO#VIOlowo#565@_B@KY;ieVHZjDT=Wz1~=-qJdo# zyc;G*!eoTF8r`=Q(Rb2~q6zN1>dxV1ajeSy!cse2f89^MlgN^?VE@zE49F|;Di{%J z*%AsFyYJ)fNr{23zD|b>Z}}*}mi;-uK_WK!e>DzC@qkg80mnV29zs=`cx_--IG>na zACKwOWf~9ln{fgHrg{J(3jXaIU{ZRk44ki@%+_hx01@}6zADzAATTd+(|#%H+l%29 zNjRzBL=dph`6tZnpiPu34C=5`;bQf~fG{#{?GKs;puj9jpm1CEYrR z0MRwNb6EB5INN*WAIiX3#uV8_H!nqCRQ5O#Xx)E3++CUcYHFhFYJW^lCIW#M8r-3= z&VSeY5>H-}BP8hP>Xt<#ud}^I7K6r$c%8qBLbuS!07|k^QzQqweNNU-31V_^q;}9v z*dcNj@CByRTH$)YMVM7_PpJK10;U@6WE{-9?Ai!kVM{xK0>rk_J~mJ zmtVDG*qG2+-JgCX3oxP8@_Dn8SD|#Dr!CzdCXO_Zp3iO>G8ATSFue!vm+Dmbn>XBW zNi_)!9$Ku4LSlop@MzYr@0Fut07%%y0N;uK7)I)zuxd z2|2O%+-t2Io}-K;r;7M~p63bVAMKGTxUA+bo2@2G@Qlj0pc&%M@RX&fS_Z8srs#%B zV-rLpR<2|{Boa8C1DF;o(Fjc6t;j24MZ2hB_vk;BA!V-8t?b>#t8J^9ZU+6R#twsf z{qs?%n`v8rxv4s+c}@!I3xaxLnX5P^IA2NXp>9DpEH{$B0){CFQ9G$rP4^kuUxI;Z zkdh>^!=6k8@>#%AGN!^ytYxc?lKSToo2zfk9ixE#W*W66O&v@L23EnZ7||%ts^QPp zO;qz^2V_F3Q&bG=G>&-mxk-!Hz7PS~yCO**QOMn{ zmvsw+q8RfGDXC{m%+HhlGcR>OzFKrs-haRYwn3gnqU2nhJew|8DnK&{nJ!%+?M}|L zxw%r)h`4SU|KQMP#CbA8DuU2WNFT8?A}!f%G}BpQyinMq0Gy3sv9TU+>x!0IT}E1t z2TGb**^p0ZXt@5`Bh&AHcWZw^vF|U+>N%z+cJwWKhU_O=N*l-u?110ahR^qFGtPc2g_FYG8tmw@oFOJWtToGsg z*`zMedR=J1w(^kro&hE2y-=Y7`DaG(mB_ti8&!#4lHUBi?*m7aTsUKgk|9lUH4*tf zs?Mp40#NgjL~s%Yy%Eyzi9KS}I-g2zfq2K?zUt=9myd~W+Za$eO@|Of zi|`(#YRX=x8oTB#HILJRN;fM&RSY?|aD$h3)tz*2$+gjQ~Tz zXWCmR_X`P}c&5HX3hkKxpo)ZZRVi%6*o*=Hg*iX&r=NkJh0O>}GV3N<@+dr6g*4Eb zASs3GIV&xJpD{|l8Q*r{7T^dPwO&)?{Yj)%C1uJhBa~?%5=2m72Q>r2?SM1RYej8_ z#J}!SDv{=&PET^G2|u^Z<{aLOVc7`f`z^kf;F{KudS(0jR%k$+hfiwz;ss4Bciglg+X0^@I<98^R=awklq zshYX8=x1Jnz4h3xye!isS?ce~H*Kn>;~o1Y1cI$EaHcb{u^SefT*2WUFqy#m;l^xF z%d`)PagU0(-1sK#N^X-3g(@`NA-n;Ze0Sn!F{)={I-6vN1L8ZMiNZrjj%(_0JZ!75Fq%USy|Dj z8#@U<#Q}N2W2~1iOSlZ<`-K_*UZJfon8-=(;kmK*qbl(OjA^>g2UqdiD&LM6xti8v zsfm$|cy@A)aKWMheKtGph;X0-)w%D_JSAc3fT9~QxmoZmIa?U#sY@v-V$m2uyAuG> zuU3FDSpLOeWm6ig?;=WPO<&>#;f_p2pSy+euF-K#Dhw5x_@CLs%|cn(Mmuzsxjw@A#-&L!Le(_NWo@ zzUoxNs4x}-Q-z|7s3V%_l<}74VVrjZoCu*OVPo*nm`I5xfc(y+#%kLKLs;90wjIm# z669WZkmPw%+Q;l$ro0b3Hg(su*JrY?bTht zv`V9WO8uiVm|~y0Dm7S3jF(mjodPsawO+sZn*@4Htcv@|1-@%F$1rv3?6U_A&x`x-Ied*)w z$dIVa<7B4S)uf;(hUA8OuW2>s8J9yfr!u|d+jBMZBZlF(IU=2b1;&e*9x&D)SgODK zrn_LH8pOq3d$srjXMG`lefv$hX&9ZbN=!PZgyT!?qZEO2BMjqy74dWA#~;og>%uk0 z8CMy-U3+s*HeF*wQxs}@`vxYXq7RKfq$~j0()4f0t!I(<2J}ZLP(HFz*tR#A z*K~wWm{#YS0vWjQYl$l~YR10rgQ-}(gxv5+H9}r_RO|mM`el;%Z)3isUajfbqw?9q z9a5#p@3|;56(nQ9NJcT1Q=zp^Xya&7|CYh<;X9a`K??8`7vmIk)++-dea=+^?sD;H z*9+rJ7hgG>A%Khfs6(GFl>UsOCsIbCH$yS36uslA;Zp}cpbS=OOuV2(C=hV-y3zs-Nm#kK+Y6wKhUz;&>{^GfD=#J^rr zU(L2KJxO*Uv5t_(-A^ao1nr=&s7dtQY8@?dq^ZWy2IkPz~Bf+_>v;v>)=O`lD;)uOxyyTt3^!r-UxoVj}8pLDCEn)$hnkes;dO)@%>~vr*IE`Hfft7W!61QeM zk@^{xR99v@+hNPlnyU=6I51T(HI~Omv;4X1Hz5(0Y&{YXRkWLMxv)2;G`ReNi?$rs z+hQ%&8#nS)Dvm;RKc%;cs&bXO665$BtlY*MMa&0WMUF^94X8PHnEx77QSgrVSg8VM z#5v(_SI}ll}5FMzW-^?oVCLlq1A4gcnmsGHcU&tcZrA=tVSfeWH@K zv~TkE#AYVgov7Lfav+vR7LWKm%xj!H|e~jjfs{ZK6Ik#%{G1gVdoPJg8)# zGo~w~`z139I%MRXQB$p-3-J`e?mHQyPrct{w>FN8{-K%0M(OU#gEZmRtbXckMMZ^& z?Yw{Dog)9?fPF)(65FVnF&O>~*~|E+6$eVPrb>46>;S4*oCRtMo(Rztl`%Ykw)ry^ zCdc}T7`V?wOI>kNA0J5%}Z0!$W6X7z2Lx`LoiC7PG18#>a-@8=V{N)_5RrjEFp zXw6-Pz&@_qqlhCNrwM5084&1>2fkYZi^tB$Ia`YT<^I(Xcb?@&&E_olEVh2u!LKJJ zn*xwa@7@}06JnYsyy&bH(CI-k*|oe3S+ocBPU-y2EZaQ*{_T{YcAqvLny6Adi5c*I#yJ!`D4`L=|+bNy*f0bs=V#vI@FrkDqiy2?vNEV;Jwsq_l_U(gr#C#*y zS0XQ+O^{OgO!D;M#^#%p;h(7|i};oVKJw27viu{7w)am#Puv=*i9eBVm9O{|JeQM# z8MAg96pA^S!?W_mc+xPh~KYiKx=?60H> zD;Iv{n9Q8&CfD@zGm;jh=oHU_q*Ff`r>b`@I3ubjMI3(afl96Woa@Cozg|!2InV`Z z51bcn9WEbnj`PR$LXd5|;(@#LSK{gpEz#843pIHd81amgoxEg?Q-2<_RGGUN76S#m zyBMD!f|PR^gOB%RNdqBH>Cjo%$ua^fVVOLnRwYo2wKM##^~j-bgrn}mcViFza%K#( z;!laV`d;o;OIHbY3j*7WC3lS4JZyo<`&tUJM_N|FW(OdAcIq!)^JQ0>%Yi#dB3y-1 ztj>^Cr*<_IM4C9gcr>PKNcqp+q>T`Cgv8pnW!!KFNf0>vw0k{6&T~z~10FwHGnLD< z9H33pKP7b{%QPX+kdYHk-G`NdW}<=_2p(jK%Sm+Qak5pK&sUeu?B2-beRS4$xgepM zQQYdQJ8H6_M*zXuO7=*{*pN)#oo>f`5LrRne&7rD7UJ!4=eKxoz}j)8LefOQ7Lq<+ zf%?V9K8%P!YWR}k)dad~HX84>f&4q+Max zOD#E+IM>+a5QpX@J9ZXhwT*q=PFPm|V&rkcAWDJ9>Q@rBFmA+f5bbL2)B6h@#D@oe zB775`w5A&_&OKZ@{lpuR0^gWCDbLhgWAONT4!wHF=lZYKkFfh9nLvb479RkvYZy#2 zvMg{(b~w78&|<*(<2?>5CbbBwBwo<#C`!R$<>l&3XqCa7b^dP~y zZC`YT8fZl~F(9>CCz7nlE&ADwEGYWr zL$vTILkc9+cU@0PSb(D+KGHXGso|rLKGbL0f)RMvgT;}ab`b_jMEa#ho16|| zj*|)*D~7Shzs__RI$V0luT*AwVrZ_DvE=~v!L3cx>@?;g=Dii;v=fy zxXU;Xf-Sm=RKVBIgy+4;$R#jjL+f6@Dke~3*IxM1awTDC0e|V5|GNjXhcEC@>WkCj zqv9AC&1mk`c3}QXBaA4zFv9h0C71zcL@?Od+#LB@3Ka>=n<~q-LOj*`90q?EL+CHdbhj$ha&13mdnZ$L zt2-sBOWB<8p(F*8t<|}VA~$tvYOLbb_=M$mQAsC^Y}*%VrC4%$1XMsB3tG;H72y?~ z?N_#|PF?GK)lm1Pd*~yhFAqz1h;ZZ@BTELFb_W&YL+5aw`9~I(OWBLAHdv=n^3%P! z-EMUynwf5zf)XCW2V(+XOh?; zaxJkhnES)K9c(^lYE!-^nV%I;BS1OfS)X7267R{RaI$2HJTXsOeuQ2>kPjD9VX7+} zsQzEQ6NrbE=oNL=fL*awGOC(gG_2Fifz!9Xg&v1JS(N}Cf1Og?KBy#ps@L(qg^<=h{R|%wa}j12z&Qi?*CZwfN@lRe=S6>Ng~0w$ z)i2%k%1T2OoD~2Iuk|^|;%{-^=bL8e>v;)hiF+TlQ;Y@>xI?$8d@!T(d*c(1+9X z1NV-;1DEzbz*|^=Ig*3S*6q&W$<^1@RYxoluVPl(F{Y2lD@#k z^@%FHB_Mc%gaTk�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
5aa6Xx z|Fl2)BL1-^pDwFRcwU0U>b<@M7xLS7vKqz;-`s1P>v&5XnjXm=aCB?H^82LV-9<;j zX>`gLrqg9B6k!rhnLRSJiY18H^u@F~H`J1+huSJ_S|rMDd{{?K$}*9b91Y}78cD5% zPBa!d`;UI{qF( zF!`P|B&SAT56mzLS^*ffddjAsp-VtL-2Wscb{2iwyV12M^GWqMT&! z(GDGm!ql${xc6AN_gz^w;Jx^Mq`jNdua15BBYlSRa(RP4zmPvVfSKy73x;#3x(kX2 zSEBc&xxN0pR8mT21b6eZz_;bai`inm8PoKRRmP-6g@RbprcEgkJZ5iGwkvo`GoiTk z7z!`PTD8wJ(>Vd74kun>Ea&=apNs6d#BmdR?!Zbp=6GC%B@emU=TN;=!A`73xYFzs zmwm52ZDuRC&bfL1u}E2^bln4hV;#xYHA~cIFE=G?qcK**FoTuhNT3Gky>g&jkbAG3 z_JS#wH4uK-Ic2-YdMwodli+RD6Y0L{5^E+sD$e1#C)eM22dk5(rrk*4oeJHUuD{WC z+}Cr=zP^<07EyTX^#m?GQg+=;;Cw%@Ao^rSgSy)PxK*9|es-PZo`N*CRLS zu-QiZsPOElTY$eHJ`s7vwSV^pe-2p?F`wIUK@`P{eU{0>_{ie#ca!BLD2#AZy~d~& zr+IiU*I_`$1W>h+_zfd?Pqpz%6I6R_T1-Ewcto{n7lpnmNayFw9bd2OAp;~j!~T!& zVVGp7urp7%sM}kdvSBOPac7)Blu-Biz$-TpFl3oVl}4$eTbpB(`)VdpNYYO|zUnf^ z_YuAX$RplQ7{i(pwa@NBzCR$>_4Y@*1Oo2_PMQ4n`UQ_u{sgtpJ)%+I{mC(1W6(L9 zX+me|Wqd%l;T(LgV+;*5d#`bkC5y0U*JmZdW;IhneVPvC<*u}OzLNTUJ{bwqs5YL= zp8=86mOAFs!Yb?n2(ReEY}iD1&qpWfpqLcGi1sL~U5ftM-(X4k`W>t1h~a6DkGk2c z*5LBQ`z18Th&3^^wwWqi&bXsL>QKBZW7fxw0QG@tkfU-p$?}P z?vGwpOfV|1X}gUvycQjB$)!cx;&c{KpazEl^xt}Wwr%pdO=Xnm#}07>gOqqA{)k{j(^Jkzo!Yo@+ zmUo6MAS?@50f0aAM*;Vh@|S_R+JX@ny)3S`Y)-jhmXBRHBYCDmdo0uph5QKkpaPSn z(0f)+2bE#xQc0Mzt?nIsm|25Q;{9an5rZES!Q2}*k?GH3n8hC&SY48Uglr3grVv7? zdyu(0NV}5G`$M{1`lHD6JQdBICq$*+q62wLh~{oZIA#?CJa+QCM#=UjbOj31KsW4b zvI|jb$^IIhm2zc#utQFH7AQFC88o?K zk%Su-rCmv*_({QzCF-OnFdxCyTVU898{I**gjQ>d8IrtZ9~D?s%7CAc!4khJ2CLm! z?pbegjZxrR6$;9np3^&!rnGWT1P?~wRjA5~qg~-<{1>0Fv+E0Sysj+PZYo9i$NE&% z4705HVfdaPMpb`w$cT$j=jY217SyEh)I%l7{R03$2h|px5m{L7PLsHJ>L&2qiCF`K z(;Swo!vh6r=}kgD{k%*6Lq#)G>em zcHffEr*WpB6#WMe{R3YL1DdXdfg5cZ)7gES>$A*Wqw<|D;bDQ+c2yg~b=U)z$Z9k| zonIlEY$_PuY-Qh2n_~Vdltgn|f?Vs$v5I=~@?nAS)QC4GnQU!P#UzqeI@OiQEYpp%;ar zMTD;~J4vIjR)vhE7M$k&AOKh6;J)Cj<571vJ%5Dfd8H*0T;KQ&=@#0Uss<6&eJwOg zSeIFPAtL!#*zZS$AhZQOi#Rd`aW=LlIe-)c;#)}kOa{TQX^&S5Sr}XwQZ-(PE+gp0 zf2fTqM@84BSn`$N=LM{vxwSV{m2VYOGq8@`fEJeT;?p$q&{DIgC?h&KuW|DYo65Xf zc8wpC@b5U0VWYM;3(0y=Z-%w^4ehJTXM|+hpIt$P7VvmPDCLRN;8Z?pDc5SLrFK85 zPNn(j&kRS$*2uVEt70wtps}P^%ky&^=?mR+pI7cLm!`!ksW*5SUoH&RUJasbnk3$d zsvXr%jixaE$!yFhZRh$-hcguVsk&UvlsZvNxksO7VN_08XWEe~R;0DTX1YmD_Mod) zy|3#(I>peo=F{5=qVMS$=i-r9{ccu568Wy z(DqmAHGbZ)#w-Ut4OA92O#8ZUQ^x5>YMS#Cu8_bV5$h5oT$7rIl#LCeuSSVAB}nk? ze;MxfNkz@VM6(1hb(~uvkrM7#@2(J4d6sh|tG=~&RrvbctMaz|w+{WpeGn>z6$^j}{Kvyu> z(TBlX&l@`}S4|C)@Hc9V43SjX|74>ibg2Y7-Y*0KjH{w9;f0Buqp9qi8=+&CZBlLF z3;1JDh(W9A8T;C(((+CX4T^-^I)$J`VMyZ=^bE~}HipACE8l3FC-PCjg3)<_@Qz~* z^`;KW6tIZh*C`+}`6RCJsTZENtmxViRGPV_Q?Hh?hXJ&uY}{RfCuyxQ#e-5@3z-D8 zsEWWz+gC4-^7BdpZg`KKCAJ zw8ePT8&BU2mfCAs01Pso$2=(deO5RCsd`G260U%)lUSNA`3pZAEDvqJ<4OFa;Qgqh zg=T4uuX7EYryL@2d|b_zI?lye7uu1gWAU_8YPEYDCme-_rFyeKwe<@BfMY&t0UvlQ zEID((Q&P~MeMH8g-BlVwQEJj-(nA59^a8YgnXwm}8StTRVB0R?DEq@Mi^zf#D%yZo z=l!bX60?w}DWZGX0{_(g;o!79T|0-|E6*p`)L_WkoSV-StMzDdJyt$9!(Bzn^nyE$ z_(dTqBDqb|(9zoI_Pet*t&>?Q>=mDyD?09_b$sUr@Ey_kIfY*(f{*4tS4r(Ba_IKP zx8)e|sD-cUbdwmy-`hUYAe4F+SNcMjV1k9(n05#aXtG4EgvGqK4!o2;$%?h!a%2*@ zGq`tPOU#d8k;^$C&dYuytCDQcnF(ck*Co9Fqm!P-Q}zpBC?> zLRp^HmUr{al;#CPXLJ$W0d!6d9Qyb{71cll%entDK4^s_@#L`4z|w>T27fEYePeAO z^H{=u-oN{{U8JGNUE$ffuneC5jE~zO5;5TgUTTWMq{;DA#Sdnyy>Lc;u6w9o@8$91 z6bXr)xx3T~1z(g)=t6$a@Irctay`L}rdHP(wf3Q_FknL4u3p0EkkuaeAu)N(ZJKoj z-Cb~1rn@J4dZf$}S9KRwX9TQ`BZ7d6ah(m=t0FhUvQveYYF=9KbLwC#QZmPm%&>kQBgrbTnR*cFCh2TYz!DI^3hrbPF>>@#f;*ptesxn_v6^0USWGKI>9*1AG0Y@17SP5JO;0$N1| zC~-to;w`VbXT8=N3>_!!w@Q2Es_eafj803|LpJ9FvR>@@g+LDlptFIb>Md+xPZq+4 z3RJ)ZX-qFE_wV=p&{rw=`%2-D)5n0Yj=q%S3Ij6c;b5!fN|Xr3I(&HfT7A5j5QArV|F5z2Cv4!$Q7ZZX84atCTsexeff@UP{gUV{of)-$SyC)dj#T zz?mH~l__4Ov1nq2@Pnwz`qeH_m+6?R9AH=1dtvPeB{oGI_9z#2yg}XBJVl6WG3*X~ zy9LXuG+8M4%jve=<3S9uW?=^RPTkSN)y_Yh{5FD24X=BYEfLDRrKjHy`UEVVdgcSSgBW~R z^mk*7oGdeB7kU?KSM6%D;H$%^m`P-WjLNTZ*`fp;JNvV?Sgp0{+sf80;-lkJ1N%9s zwL;1i$C06vl|w!-6@ob!XrX5`h2OcYKhm{^|^g0Bz# z(q!}-Mrb=Ey#o-4u!*l?R`kD@6winUv>y#}=&nhw+K5{eoi!d7xFy9jomTU6(dgKtJ(dUyBU$ak)n8gGmp7^ab}JAfy1?70ooGN(bR9CYic&+ zlmMT8so3S#cTmn^mhl@ASozw5qmxAQK1U3*77wq|BM_@lf6sq74bAWsa|{D}?aw15 zI>PO)BKVIFxKwG!P)^awA!deNSaN?(g3^mwH#ku?#|fiF)%@D3OA&$4H~{8_A+t7e z27k`?5KoY)WPZ^B;Yx|-PuL-GhTD3E%+BK%1P^RG5zg019+at)*rUn}a#`GM<;W~z5Jb!JY&U4&uCL|ZMYirtr&h!YPB`x)t(g$5-C|w z(niC=qW?+e5Iu1I+9e%9TYe_i1s@sTFNtRZ>wKoO;1E|R)R zI=g*BW_t&|d^Gwu=L1RZMSwJd!}0Ik-W_9!hat`=@+;9?pcavfDO$HeuxxT@{m2Y9 zQ$m|i$vQ^g&HknOfKW_VGuuN764G6}G>o`sv|aZ9e`X$_hhl1`pJdo~uAAtD_R`M>w{Se-PtA zX)I|#j85evGUi;bd53WNkQ;=6vBJaGfON?Jcc~^;{W=|r&Q3np?X;i zDsb2#E6SG*pJ2O%rdZWBpMGp=FZ%BfHYhR8z+F38G&;*-CnU=WUiXt7X|Z)RLFS5rT_JZCk2d#`J;KS zRI+y)Riq?KV`fy@&GN;=A+o+^W!eP(!d&hR;tdW#xWfo^wh$;J-ycPgehBx-&a*`h zf1rHGr>*P~0z{dv5(JIcKDl;U;cm=(*8?Df1TYHu%sM_vCMLihw?U;wVFFKSJ?D%# zLuB}Wr;jCtKVaW4M>I?kWM|yHH1y{(jl-wjsG3NUfmKxpx%LEeBf>$9$i8&4m++LY zEPs)?@cd6{=g*Ra{5|-CBM%Z5a-kRebk~|ALT)5@y6X>^RuGIMA^DYSPuGPTXW&ji z6i{`){oXZ1z0dxa>irOB(m1tDEdMc6<;W{U+8eKryfZcLKlIK{AyQ<&vj|`g!a)Ae zTkCUx!bC|b{Vz|*sM@*TSrur`gB^AUHp1;%f9PKm_rFhqAjg937u_9tmM(~sxc|jg zEeM=W*d%B_l5mx19ok@3l-sh0>2;qc5{m!K`MNlB^mi_Tf8;p)KheU~{ePnUzjtb< zj`COfBs9@pMV!e-X^`#)?Q&C@Z=aqBOQCr2wz<^%hs@=0@~r~_%I^G|4}3b3&F2~v zX@mBDYZOKzX2r;V%GBMB8!id5?C!t;xea=^b<1c!l3n^(K}HyG3W|zSK$`+t(uIA5 zzi3nbExm_O;RsS_U|COfhv{Bd(oepoU@e1AzP$7R=IJRuaoV7eVfWph3QaLjz=`ad zr=b033{!#Dg>A9}oXn}_9AuK!^`Cm{$32`7Cn?ove{^^@e-+`8`N#a~!*54@6i}Li zv_9F7!>3hX)TJb)BU{Qp67zcju@HPAul~zF__&DHWl(6Vc=J#5$<*zEQ z)WBHTIcx{f+a;BMB8aXb9;Njs=CIIW#ZzK61$l1+Ty8vPP|#yCnSVVvPs~y1+pBJ) zz2Cp41b5AS|5DAU?part?Y${~*q&~CV{2o%`}lD_gA-c=Ei;ArmC3V{ z-W98hQxjReH?_Qpw7uP*-`@A8s_2dD)cw|3W#eOPqq#7P1j74Z)cv2awW(UT>Ozxh zedQYM=*u&dzL!emP4y~VfbhUYXXds^{kvvydm#yzGg*fS?^+v<$6%BK_sxi)w0!#$ zY`dOYpU8~9bpi%_y)V;YqcDwjTt3G6k70^i(~+?N-+#cyIZp&-$xqa8Jtq3#%>fz2 zj}FlTDat?MgC4hVzN6A&r^U)4N{}&b!^P{r^d23xP({t#g-Kc!54cg7>xDi&O-`ub zOh6wCX~z}X5uz~5At%gyC%qeLQ_a0=!dTXFiHdEZcB&joi?c&Rl_$b|7M^PT;r6Z9 zTp4SxOpYxigBedTbK0)#!OG{wuX|TRBc_xhf(WAh0InN>!HSXm^DCvG zjkARBX~PY0r5@}K;-vKsQ+5S5d##C2`C}K5Bq}f=?k{ewydayX(ZC4`$=goY|6OYv|UkbX&Uttt~IX5gYGgZ(&p}+*@%KI*1 z^uDj~i^d!B$!~-_lxWt zEAr#g4--Gd6sbl&Ac&>8+iB&7I%tXI=(`#x1=-$5S?E3-Xvj1adllOk*V*pIaYto# z%D7@79m8WAlEA4v)wfpuC%E&dcMx3c>j1XSNY@NkLu%!uSBj!YAZXy+PjUq*J^at- zBL6uG#B^FsB)u`?P?36cYzhU$Sez$kP7ZO42M9C0+1u$(g%ywMkKzCH#QASmo0x7A zT_D|pi#II#_9I|^+1gC#p$JO%Y?~`j!ZV_jvlEYb2m@pL{le+BOGVKQZK>g=A}AFr zGY72s^|^Grf}m?;>#>)PgpTf!(Eo7fqMBSj|04_E$1~jZy&^o3I)tk)x}p-yN<&3k zIF+-W9OT%@&YMaj)7f22Ax>sgxn^mp50ysU%7IUk;NQbqaiy(fJ&M0F+2&j+P-7<6 zwMXpVKUO{w2ZulKuBV)dD$H0q2NNb;V9CE|h28w~F}MqrKX$#tsb@=A9Jx z9a+%Yz4pZeg|@tB57(PpyH#6+|Y?ktocE$k>t!y)dcwH@w{?2_6+gOaLeBl{*$PJGpq5*SB5VSnOS zy@9jskbpk{kBzDFm?*y@HJ+>8Bb#1#>imO3utaBHU8iW2&~5?AMSWD3D*GD36sP`E z^M^So>K&ZHKv`vWNd%$dV%OvBPkvU;Xw8X+ugomgi4MzvQW>!p?MTRvTu3*nm+Jju zQ*dWTg=rV55R^zb3zDWhYg&P)@)@sdG#H(9@(JfPU?44^8-zQ2#pwred4Sku4N#gU)xGK6x@D{!= zpCPovYV0C01mtxG?MGriIh~f|h(eARsA0kX7*eeyv&!61{w%QZ`D{U?w$besN?P_C zbfUJ^A$vGVOGbI9+X>yxJ;GRl^wCaHC=?D9!umF|QyreLi`>hPdz_54m>w zGnN*Fc#d&z?06&4uSiICG(z8@l}3*Rm`;x+rp-XvT3mY(YX;3&C5i;9ADn{~&HggjGebkT@g& ze37OXC|hw~_x#zG*ZfH~bJcfBMoF1NNY+}Lh+sYH_tkDez9f*{0nJU*rAJSU4^=RQIY{KZYg^@36?b_q!t9 zC(G9sCfQ)V_G`W64ye`sPSv6}4~==c;zIAK#QRjG-{R}`+#(c2vI+1W5E6hLRPLj1 z$bm=UiUc)wJk-%vcx0{`>^`Mb+9+ocrPr2GG;;tiu1Py^*+vcii=&ms#0ZJz6 zYXuGF$M)0yz7%6SOh~LojP1d*jWLP{+h9fvw8N4)3gw{;#w)M#MF-)DNCAGht}77q^)3fT-xyQD6V~^Q;EY$7q zRGni`jYFfPC|?0w?21d8>)9lp0QkC;<1JFV=&L$7T#~*tUPoyIwW^C+?3)!sAd$&#i{Q1 z+F@I8(d;!Igu@@&2F6Cuyqq`$71;^A3M{^97zpMyDA1}QMK!!x__PoiehWrhHqUl4 zpvG=Ue*P#}UoGNdEfCo+7^x~@_vU9cA02;CCY-dDF*eL8WObx?T>8o*Got_Apv;xm z_*<%Aj9Bm2hIKipRP-ViR+Xg(vrGwcIrTRs7L?8N3r~kv1&_zBu z&FWQ2E>Lvttsj?^XHjvFlxp!3>!E|UF0SQ`8-mRt?lKljp@Hzu>)W}*i-6HlnCy$L zcrG0oD*?1wr0oQmg4+%4kHxxSpr*OnjEV-OCF!X!VH2LlOa~+di}xMuql`07v_Z>k z^3gQMUqMG4s>K!vplMCk{)0r#kbqWY^h45-zpi?;Nn1e2k*R`YQR%uURIGwDg1(#Ga{vT|d3im+ z_+M}#s8mdmMMX{o@`4(XM%y2d`7w&%McfT1yY|AX*x&ttYD3EWL6?)%b_mGt&(83w zwkNQ0d>LslJoPNCtif>iJGE%&+zeZsF?Rrn%v|JsDv9++eatU8M|t*WogoM6mU!~9 z8+xy;=kCF4EjQih{k0|J^qyB!d1b5WM6lMdec=8CHB1qnE7(g^-LU0Wa&A+EmZ?X3 zMS?^V+4GwbK2}J=ckaI{-|3c?^}iN<-pURItC=HTb7yNY_$hzcBf!*l1bllnrkIJ6KbhY@HuA#4oma;`52ydpf;ZFdLe7%mDi&)4U?2rnL zEqs2fRP7JOB86Y_&AD*aaOevJO-!KS$>$yTZ(xIZpN3K55v+^kusrX-WiU`)yMtVg zbgQL&Ucd&D)=rWiLT)ta_ZJPl&`*sWiNAqrzjdCuh;!6~6a`dNHTrAusRSo zhYfQ^PqrBqPqRm%XSsib_M`OQPP6ORRbWTtM>DOrEl|Br^T>ZyHZvp6IFEF_xD<(m z3@V8oVa1-)oaS&Au^}trBgarW<+izHIoLRNwFi zgzyLZU-k`xrJ|;!)0#DjseOg$6L`$&%6M+soQ8-&?46mGH6jSSmB#TML72QO0>wD} zl=l@Z&t|vt%FHIscXcnxzWzxUxfTkEZzj zDZ7M!R(1m*I~_`&uTeGn@mDkVBU~*JZ$=qVG`Q8T0+~r|;bGQj=TJHO*nB?DQ&?_2 z)mf`(iHecDh%+2+gE;x^`#@JG{LL1r-<*Q@+TD1v`&VH7p}QSvzUG7^8ST8qJ2`cb zTg>SHmMR*dj<-OYdsXBUT&M0w_;DV>tp|*bgD@+lFtun@dv4WC+ear^v5HK0*fXZz zs44QJ{(v9PMhmo+({wuXIR2|LHDYb)iyw)WUI5Q*ND_B%0F+t7OD%~+NG@nx@0dVZ zVvcr_7HR&%dBEFb8nsk>gW#Z=E-2HJF+_$PiQ5iOPZ!Q3{=OL}^Dq4WzY5ubNUCOa zc)9m6LU#>F2`~t;Co@*^04X%jY?}AbLWr_->>Ldabp;r88VsBtvg&@SwLlyo@Rf({ zhzS4xG>;K62kBSS8M1X5A&l4jtm700H)Z6v$z{3wP|-=>AnrSJ?O~2h#0=kYF(snySpYyC$3E@; zfWgaopxWK3*IGNp4;q#c<8b+aY4rNps>qnfAf+V!ONnV^{GwV?;N;H$Aie$JH4Y?l z5@L|fVuH*mU~~7s5ar_CZb&yhYjJDf3@+MvAX~twi{v`9EZ;UwOd<4IXJ|T?O{p0~QW3p`f%9 zN`)mlK-f*!Jogs$84017mHE15P&RjQJk*xCBi51g&+mHjkA9b=yYNgKwfd&7z3#H6 zOptX0z3w;AKh_coE+T6u&#$xeuJ?t7$)~Q+VU<=*lhQ9RY_n zR;g3i|7P2Cy%O$mMEsBh=cQ?J1Q=5?dlVL9Z^1r;RtpECvxXkntx9A)TgmJZZ|m#Zw|w;o z(bWs-$()6UreHN6KLy<(TUBEbmMycD0(ZpuZTT*3lJ@3iH7(bibYHLYT&%r4Te%v% zR+~}VmR}yZHt9QM1TZ&tn~pZkbEmX>STd}_jCxyASdJXxIVZTFK;qYeeZc3fLKhl4 znyOAkP96=DBIj5&HI+7pUio@97cBKQ_IM^#^se-nKCPDY%zHH+n=sUG%PS-|A^zL_ z@MDFhFPDk7{xpo5Jx=_@dy(W$w4vHznkzaq*F#^wIX#>sPQ|xblc9Ktp>nBJa1wt+ zh*KDAKb2-5{$WihO1m&v*28>ol%zVzHtz6;_8>?p3QkxO&&+73Ci_8Bkff|{0&ML^ z_h_p{k%2wa{e#4QXQB7#V=#slfkcff8<4G;ktCC|Xl)F2g!&@cY9)`3>K8)=5`O+*n)<>J#Jhd=~0BypOe<6J~` z9UyN=W$$SgUs{U!m>LND;sXp1Z z`;hub@6R7HykI&fwMjN3gWzdZx_5p)Ct_*Hy^dvFG_6-SYIWWPc?ncR6jYdCgQ#oO zsirHT#ijX-~98TV4@8|NaYqYGLckh&B073h0?TKX)0hq@7U7Tm&pWoXX;jj~?p^3mWSl0`)0qrM6(jj-&4@62m zNWY}?2YjYNV&-0whb+(1=^=XG^k)D`0hVse_ip=rJUsXW%b!ag+jw_qNibW%m>>Y7E7mcdUqN>}t(Ac;wf)xW6Z(5e3o6 zZh#GsTbV4E!=KmdzqfLH3_qwxTI28^+(97%{xjFE>4UN9+k(7C!EiMVq*qJ6!Gaiv z^W8y@5ofmO5 z24qq>BA(inB1lQjypKbHMZKUQU{_M;RmA-&WWHDf4T=>y-QrOfhpNQuOXr*?E}GiB z0|Z@(pOR`OJVKdFD!djLNI89KJAQ9zA#vV!z|>ANPX3?cV!c-5ELt zB1IgfR=Waz$o@%8myhm;lO#bVt*x5?PwqawCx|fh-MwvP+e}IZ+$?%}&eY}zm^?em zt9tFf_QThc7a$8c=$#U2cj&^871YJ0DbhDh0Zi;~KFN@6dyU=HSGs`8b9C{8yy=|e zdYr55wt&=FV{=TAj*L(XuAIu3Bd&Sd;b8Y$PMr|Jqkg~{>bjmLYKZWO-b#%X z_%&FuPj6?0dj{e0V!c?dI-qqlxa5xwFapjZ=k;cTPn zxLq99V)0~d+1B-~w{lD$Z|nE)8nMLoJhG-*(QjxuS)k#f_cz?{Yip$TiIlX z!n+_^8eM$-@5*jM3XsDghfi|^Yd4)*!N_dLq)Y@C+1s{^24Q&_LzX%exribnL3*9K z))<9TB*Oweowx1#^12u*OzAzeq-+yJqS0}OzKVg09B9V8P9okXM84(VPV?i3M2Kf_ z-`s#a+t6e>K^ie^9P0jb^l%C1Jgh(sjGJnb3EQTPAy^t`ud7n4TYa2{BzDEkB1kvgXWVI`ia? z#-)Zfyx_$kJBkejSZREuEEU5tRnWjWlC-+I{ema|=LP4n)C_GO-3M5+19YyEU!ywp zO3nH~?9-7{_BCx1tQpFj$(cR7g6LevvpZZZi_+TY5`jG>Uwtv#{AK>|v5_fft+R}z zp@;)wv!7JnMw-3IJh0=9K9hrYR3|aai?PBm?UNHXY+jvqc937~)DS^c4KosX|2)sS zRjqc$of@Vdllf|r9|Z#ry$DmtQkILmXL=I15c(0kDFu9cfL^qV(}Qf zMNq-_6Jl~FuDeNy^T^nop~EV^&Hcvpr&uIjw{~prUs6ks`zl!E5PkKj%PX$VXM-Kh z-(x)LmKG+`X6XHHK4q_a`&Q84#??)hMHT{)(LZ$E2mTFi2$uTtQa-Hu zFnScHwzKzV0ujqm?m@c*z$*6rNV>J#&+8)}P4+L!O8HQG=x*hgQ)uYRI*5d9qYvMF zNP%w2T}RNG*W=gX8y8LIP#vyEcO0W+F)^w5_~}8_TOzjsrhdW2Ki_YKvw!H-^0(7izEVPJbj{3QubrQ~&l7 z3}7H7FURkjMiHNN8+yltz7}T52Y-gD{U7-z9%US-g!g0p7$h0+r@eP@5aByTlZlfI zaJl;QrIhwnJ?u+2%(ZzVZ)V}HGtqneX5bN%Oe#%boFx67LbOzLh`)hQ;cuzZ8B+K( zg$FMS)WD$E2Bn0uJ&WlXV@uNLz7FrX_q6ucX26Xw4xW{aOs5Yz0=vLCpPqa6S)vse z{RZN`n{1j_=#UReREr}=LX=%XSN`n@@Gxn_r0c$^9)J%x`?G}T0dCi2&#RyCL0mph zVipel896WvSb3z&h%Mctks`9ynLT>b&L6+rNfGruhdH=m)@zxcgE1=VTI->|u9I`+ zlS7|#BmTcyaR#vB)L_LyDsvuoe_8QJdR0fq*$_p>`7s)GIw?0hj*U^=!9$-)Z)M-R zJ(p=|;Jw&+(n_r;TEM(MOx=6w@o-8~d`?6w-F{ajzbsaAj{oz7SyAl_Id*|?4jg)~ zRtCWXr^Hj0r}9P?k=WA;s=xNWYdX1~Gv#uyGo94sa}Z(oxBf)IU9{lfv8aN>2vR=8 zsp~uA9?8fR>ztF`*cSD4>!gC`DADKyuDeBo`2uczVicn-E6rchUC8Ok^ zWXVC2ND?JVzH5u!x4Y}yzN7oSbl2W%%{-s^%!}xG?$t)KC8oYSI>w;I zMn&QzK8NfJGgb@t`C{b&FKM5vxL}Qrt*5JfcPITGzG#9bZJ`z&8IUUUd#BM-U}myu zPcLD2TFFngWsW*Ug3w%{IUH5%~d)u_aGs|zdhLmgiMOwhNpABucU_h5iQt#K*JZE;E2GdPjZF|^thgsF3S#>{d zXEmwBmLHCU$;FD90$WYae_uTfOpRem+mPJYcUA%JER=do*6Ue|0P8h3r4*SKi+JRM z+?gfd0@pnO)a=Cn&r^qkeInZS23t<)^&;(=ISy-m;avP(FV4(&jv%2*5zLbf+a{1h zD=CfT#2>W+t+Z&Ovm$F-UvV0>&8@!*9T(o;jw_+ISBnOtqwO%V#zd^z%+zkW_^eh{ zXhqbmX=tr#VbZNy^1(-RZ??{@#d)H4!V{|1i;RabQNLAt=dT~F=064C5ie;S9v+sL z2#wl#eBb64M{vJ6kJo#N=&bDc6O_a!J&x7gOB+QLopeB{He zAu&sCyX9E1K)33aqyNT_t^hwu+Aa_Ls1qrs0u}<66?3MUD}0Lg8kr}?M2!!x?x zZ0sGef|xBY%EB?{6#}~?MB_6;YF?ATJi5`r&J3?#(?O9iLADIu#ZO8rHtxUx7=-M9C?GRc3TXdAY((XlWc9nXrdB+ zW*{(;&{KkPUB~eQQzVw1sz_!|b&B!>7U1js(=Q!UpcZg4t>V8Be?eCKHk5j`LaEnp zr5;HJN-bpsY8rDkbE=05e-fqu;lvk>F6lyHk(>$`4ykAf0FTzI-VbYiXTc}$O;n=a zq`t1mR2W%H^+C^Fc#P#BN>nq-l(Rpw){0JJ zOuSSNrk$KFD0<-yqpKi%S%ZzF>MUwwE(Az-YKFZ27^vzEoa1o&7fxL$kxM@rmuCB_ z4x-@aHbtJXA4cX)PIEl~)xA)vAxf{Ofa;Ug?KMf;Xt)9qYBT<_PHnNjsz2-rNuIKU-QYlvrBYk*3 zi691-!Q}#cp`8ktm*lh0zm|g%UEUqdm4DtC`P)bSS@C!0{UPuXR|XnfuiKP#K0R~q zBM}(;We&THCll9D?Ty_v9?A+=)Q&}Ap|D)^sMHV(h+|By--Zs z{k-a=RkHRLmto_er|v{)t(;qTYNGDCp(z7tFo_J$;?HVHab9j(OLo)m4v{J$`h4K5&g(X1r{af!I$^J0^DZ)}IoT63n{^q#Vt@3Re%i*3`)=*>?o%H{ znvta?CsMu+scfNlsp0KnSLg#@o|+r>1|r(weqiYXVID6M{cDr~MD=8K_dkSv53E7h z$2wO4!oJE2y28}YTL#n;4U^f$g%f3IFb^{lmpG)H&|eEj1sy(jb^BFjCnNGKOf^H( z-zp=s9JN`90agG8mYE1(qVxFuTuGXc`uqvxH%COHUu-&w#w|TC4dvjskV4HG>6jKX zFICaSixDBUevB^Qa_eh!5g2ahta^Wcs;vgMLX^j(8ZH&O-qg)&2)puZNC0u^#!#M9 zg9Hc^I*_H7Hc*B>`nVaJ0Rqr@Kt&N|MDsYnV51#5wF`^+tM73XoLvKH?T0htHC}(q zdFB*O+^0T`p=v?FQL*D%ba7)TOLDVfbnAGm_`>G)I}<*60r)~4Q+aMOB}e~jl%@Ip z6;Z_b83C|IFYfR)n{4U)T*Jt-xIjv^5^ufpGd19^ZGS)5251PgP~6`4Z4)6%s^v~o zXkOE6ROoSgSHje{-}^b|0z?p9ePPcZ5*Sj5z^1!DP7SN5W2zW+Q;JIw+m}d;i&mRX zWEO&6)+j`{5rgJv$kl&l@H&y$cTkxq$ugn~bnr6odyEY{|H$RlDV;+LW;w0CRQ1~m zV7@=x{KlbM(JK;U^(pR*P5Fw^p;PS9OdQH4ITzkGV+!kEp*TD~$S$08?XFe3!TPkB zum2l!LL(JtwDg?E@IIGL_~aX(95>IzAP47+aG! zDY3yXH#wxZ8E<@^U$RD=_s4nlCG_n;veLt?*OLOD+w&#kpMRL8!HkmDWkhFnP$KSC z89T^*crDP7miq1|z4T@;b7!0|)if|d+2+Nk^SEqI*^Dt;tDJkHsB@=k6jU(DOf%DQ z&-J2X_`?fPvOV`&n+O}TPX$Vbwkq|SwD5r2HUuxP_Iw|EQePx15fX3dN>VN+A=(-fZ6IX zQ=C3SQ8+rT%4rVP(yO-_vo&hma`1dK|JgKNQpCALRnz<-ocob{nzg7X_4KW-DW_dY zZYe2uRox$K9})!I<(yI1C5ReHW8P&&ew+p*o^Ic0ZiLMSOfWzR#}$G~<}Y(P%l_XP zt8ywXSn-D|i$B$2bJdxCtC6J7Awcs_$;@(5NIrN^4tv4*ToPhks)c!#Wx53eYxqH3Hx`ngf!{rNcp;m+Iw0!p;Y}y`=JAyE7 z2{+E6^||;~Pj?XgQc{1-6u>kdsa!At1lLE?3%B;ZZt)w?VP*@H*N4aBIfFA>3xBOs zbnBB)aG(7-u75e%3wS1jqkBxjQwK*3q6vK$gO9j1y|?Y`CeMi?(vHT9B&prRL`>lY zq{$lY9DBXP<`(08MrJY4WB|>9QLN1}z_u8L#emCUctM_&a58%(VXa!72 z^?q-Y5mpT^?ePbos{VUGCa0|0aerZyi)tV))75GfW{oIL%VK|uoU0_ePK~@-{)vS~ zj}R-1cq}6UMXJ+@VI`oJe+`i;%!e5<@6H26_?C#L#EvCI8Gk=+1sIC1R4cI!0S2>T z8nqma3h3UgeANG%_V6>gzLkx~l$0`EnuJ62=4E~ftt{U5AGb4Li`@0T_Ol0lPEPTY zWy9Gf(Q~{$BimN0@BFqa3I&V|3djr%X&KcNNBvby6QDJpPH2u`?lm1aCq;r-&OPak z7J}OI8PQg>e)AguGR%|WJ#jHC)0|ptP3HpB@?DZbsxf}ob|KYfEuxv?)g15RCtqK8 zW>bc|!;90$fVWqVpEZ=D9dS{4P|dmTV zVixa6ITN$$+R$y&;@H`HLU7J$D`oVY4CpXF^UVy7AO;GFGZ-F3h8&HJKJSz2;^Xu6aVkM=#u$d8i;Ki;UVyK)3O^_IfZpRkhJ z^*za-_SWMHX7S@j!NDq5SR2B>adX5pzF)?5-zskg{9+I?r`ybodYD z3x>TnysiOiEE_jz0cX^ggQYydC(g5hvE_rQ(K=_J=yY#eeZZgEZu;noM##aYX_6s| z&p>~qfiONgcTNDV&o!u>oySakJG1cHV*ImMGx!0K zUcX#YP#))G#vM!D>nVHwZl@q%N ziStD~HWAGId&L5nktELGK9@R|<_*f531WJ@tKThz@A12huym!|1xW>Y6GtKfw6gRb zfDHmh_lgVZ-2!bM=|5w87niK?CZ zMp-E_CI^r~C2Yp;zQzexW{*1S zf%e>&_Wj;e48Y-9rbMV%MrkqczRSmNYH-nu@R*mRk2YFvu?Ba4TFocS$dAQHAVSm6 z{@laUY3tIUgIkH6&#*$sl7RlvLp1r#SW|8<`<0mRm$q`UQk*&wl0TE)c}vjCuGIdV zJ9ce~QXSkLYS^7e*~Hks;oz|we_b|Ls+XZqA&Pjy$k)-xBr==h5M67==sjL4^?{(U zY=J|PKVfob>iDHY|5t>Or6mp2e-1Hzp^sx6uH5-iSDJ$#C8YPMB}?$@cnDa_E`G%l zdoX~36gs&3T@RQ+Px<+U{PQ5rHj!|F*bmQGHjCnh=ZO>{a#(*zTw4(r34!c|TYh#)&&*wxnW|`Q$FmPSdT;%T1L`F;C zG@4G2PB@{pvg$wTmmy*Ob7u>Oot!Abt*W)JC4rRj>ft;~{gva9>BgbS<9=cI(cFtV zhL}NugSp_ny7*#&)iE)*m0|9*N1Apd6pHeKi8Ur%O%5DMp1rz49I7G@=%Pq;JMta?&<+Pfk0ax9SFCKn|cwM`GbOLMPXL3?K zmjtB`?{Fq3bOtcbmA*)BQ|d(~7O}4xtRJRzvq%0A1Z%b=5XGBxN!9X<MVG|QW!T4Q8M&6DPZmsUx@Bl(wje94(zY%lqMD3CA68Bl9@&v%no<2 zGjT%C3al^Cckr9$ad!(baI--Y^Q8=?oL%&sT&+JKSWFUjgQ9fD6QZ2n4S75 zF&g5$n&HIk-<|^K_~O+iu3x$-3YJMf$v&l;7;&?7xuvjY&r+oUG<)JyFM!R|B(b5& zqCwM5h)iW_Nuo$&~uNh@+Cj?CWc5?Ip|K1ey4#41hkXu*N8d_ zgV4-1;M#)H)5ra2t?I!i{h>~J>gv=Tg<0vVKig)g zR{aOYt6o%kDf~L+o8;0Hz)gQV>Lu^)rNyd406+QN76wDF*LW(mJIwZuL@$r^nZ{Kv z99eNsNax@B9)^3lk~=O#;X-@D^vl@t?;iHElHGPaIpxEHgk+wtFGgA)GSBcB^OZ?T zHNcQ%@8{G3e|H6`5iwrx`bD58mk1E{`K4(RZ@stIeJ^CVB-^xZRWMBMZhGokE*zK~ zp*G6ZxeEzI-X`CB5p;cy$GpwV35E=RKli20tZMI>(dULrKkGDHjKe+Q*{YwNoN}?$ z(?b#ZTv4ixUiJ<=4TW^o2*!iGAngH)nrqN}!Wd)nnM;2+!>9Enx(q>4PESW&G{KB- zL_7eDD%hN}z=j#fyr%{RV=}O+Jo8V-3nXT0xy1vw1uz`)j6ci4bZ>;j8b!-1UcpOf zno_{`xj(axqaQmb$-HCUozZc_$;k-e*Q=r*m)$}G=adt&kw5-8uV-Zww0T+Iwv&@Z zXUMq0%-W$Mv1LH!zEch#>iVUow~ge3F61{m8wXf}rv*k3^fyt62-t3Y$+yqZS;9` zFeQ-*Sy0}fnf0Y6kD-Y1UjCeL!*>rZNZm*}jRtP)e%7ak)2#IAA{Tp00E!v_4DD%9$xwR0pyu8mw=UmZq9tUpS z)P9}|v^H4+mz8epaMagCbgRIf1A0GcB|5ly?N&|nEPQ$f?AZlV!#bH z<%<&&!ESEJ$ZD~UEvoG7NG{Gf7z*wUiZRyMx(iZI$60Z3JR)4;A?Vt!_50>4EW(KU z3}DQxf=`J`K#ExmqZ-BL0%_w0cY4rb-^QtE3gf$>P6Bbb4wGIk!U1>*g|d06m%L@q zLutchC^=^mmvDEe*c7f~Mt>;~{-DRv^X zQ85jQW23<}h3;ljBdO0bc>Kk`?`>Va^=nUtL{;^)8%dMw22TQJW6hz~u8f@~{7LSu zEsY5Vwhqds+GVdx!LvhkKR>Y-?wgwhb`x_mSx~*Q<*b~);fG;jkh+{pdR}hp`idiPm(90 zi{_4@&zlT)^n0zYss1tP*Ll;uDs-5)jae#Fp0nvzTu!=7{EIqvHgfeU&b(>L;@^BI zN>Z5WYBt9o)z$;RbD9QvlY zYxRW;!i>+rae}+kT4#c^U^=`pMusW(8Yj>rtEikwG^pk@Uqts~w^AiQ7kAFMhur{_ zkfDwp;48Gh5t|JVC+62-A@9zHUw54IDC7}`p_G8V?V`%W`I%iDnoI-F&duXs8sbn@ z!y`gjU)1Lq)jkI&;98H%Vo&&(BhWk}0@L{sNvx5Np%<+_Svx*=Nl8418C)Un@Ma3Xv3Uu&9zi=qVLsmdycj+#MUI zsIkZvt+{WW6T%R-=GFrC-4p@E3q5Nir4F{=MT+cBsDRf0?3D3ZFIo&&=XoP29+S4> zdPQ9iS3ZnucUhvke3l9gtKjDMbVC&KN{Bh5wNm=;F|p;beu}Q4?Cds^Ud`TNuI4yu zX4Mb*7@?_g1A}WCoAe6YMW@m0^B~SFzjl{hE!&<%+!>vS$6NCt`9j9i;j_I?_RQPS z?Jgr_^$$f`tSM@pp1m?3%i)@ka&0fap6xVE>>%~?HH(d4EnHst)kE~9Fh&YjP>0JS zv!+3v0T(8Ue@P9SN%aqz!QiK_fDRW0UkHVOkP`PU_-X^#9$tmV&fhRii7i=DfarRA z@p8f>siV;njE+_u@v75`OIWP{_&s$oddBGBjiAk+#NngXa&B47I|!1kJS+dS_j z$QVKuX6$55RcJgW**~VYFlF&2)Vc1-t4xwP8G#A5t{-p71=-{r(OOaZw-M^m<=L#t z*1fmPzxRrd%4S5zT&~T$wS}21vIC9qoo}t9zWfP#1T(j3FmPEHE%{3W ztC~yHZ&=Jro-ijuQBThqhq}f%t)Eb5By~hXtvMPSYiytU3*1tBywcDj%fGeTBLnE0 zf?#b*_3hV@BRFQ|FYdklsNMGCN(PYQVe|S!u;^u1)rb>{I6mV#1`{E-uL@YdL}0=S zE3>Twby$o|I4cj%#m5Z+99mNw>wkdD1h)1ARgog$??&O@AY2Kb(F0To2vBZ%`nB$+ z=DC<7!-WY?N11e zZR;P)m;z~~izNDkEy?7ahimBqXbCbdBkGYpz?>?k?wl`q!yA&1z#!}VUh?s%<-fT$ z6k9g8PFLn#Ce4!&v2SfhBIyolJA4UTd%d5gX-tJ0bXB>G0+I*IPYUiUG1A~ycEhMR zpZy(Y|F?ME41xjgUM zfT0xK<(^>Rh?2`q9fJF^4R07;hao2!MY6Ub=x16ao`sRArd9*I|CTTBQAwJ#{c5L| zkey$x#z@@`@$t`Xaj9qgjXp$4U`#faUW+kgv0b3lR)p9DURpqMREKh&!|qmL->(ut5+Fl=^cR3i_bUGF<1gS(LLF&A@b4Nr z@<06!fL+y`s`LGdchstJObq-ff%AiisP@g{{h%FgqxyUgzI;Ew<<*Y@qLt6QR|D3> zel{NG6HxhNAx!-|gAk_eXP+ikL8K;00-`$4KpJ7rdPU$YR`vHb2{@Ir1ZFG~phX%8 zYh{9H7j!4j<^fs|2LF{e)Bq6axbZ8O#tKozGFd%`KN#J)Z|QRw{_Y`q3Ge6n&iAUt zz^@M-znjs??z3frHjDvpi+X;fqCy3ZSC?&4LcY*WGuV@O||7K_+QLqd=2?>-2R9 zvn6^;i~cf@GY~@_Jv*d#PZgLWlZv?b_r; zNQkMfc)waf&E=7YO>x)}nSOVt(fQ!5ScB z?#hfU1NfF#&G7#12muTLQ++==G`Y;r4+esqB!fSht%IVOkab|kjM4K@Ty>NFxv0hl zP^kjPuuQ5x`x*!kFT;7L6`Ss#t^YSe@pq(>KRM8pY<%g}SH0-Ih*Mj{AV{}*sIZ~| zsDav-W&QtzZw~}90e%u9mVSo&hx(AF27GTJ(uFgi7N@2>#XC7y?8oS+93M@P75KOy z^2eBT)^4rwG*nZc?uw%Wx4JoubbbTQ!KAsf9Xn1jguo?yD}z@5_IgY5c-1CFJm%)2 zJS-)E|K|b&ydI_bsi1fFkGc zu&mZ8oC%O<4%lUgiqXT65l`mrkiF;{!o%BQ5m0HPQkpXS`p#8E)fuV*K*(SMD-VF005aUVUC}$+5z1+#LADF zblC-~Tn3n_)JI>eX6=+Yv!pCs!DmvH35iF@M;9@1DyyL8!6F>{B2m>EvuM=zP~j+2 zerzwn)+>(?#{gK`fjh~`9OB^8ipehg%T6OmdRU?56&W{+1AIZD<5alZNzVSmL@TI8 z>$!;AFsQf?ec1K7drlC3Rt|=GdXqZNR=KJVojtE5u${L;T&Y%`wHzyZrnmvsXB<)3S}OmkAkL(*l;c~K`6Z~5T54ETYa zAa5z=!OUmIO}-*vADEvdhBEN{_s{J`d()q$-J%EUJZ$Af@x$|2qY!WCp}q>{8vex_ zkB|AygUL@?gUgPfH7G$OWq^&lY`Xc_k0XM>mQEcgUl8l=B&bPDDat4wDw;0g>uV6* zFlAF=B3s6TAx(1g@Noi2z8oW{t~CP}p|$eMb6gy{^IJpM?u(c73w@X=PEt@m=nP*~ zse4Bn-o8WHqj3x_t3f*^07S-@+MD)3C+&(g+mrVUxWA;4&yIk#QO^=+~x8$>PH#u$rU>P3H$j)+=Y^A%;rflX@bta>*WZwa1O5Mlf; zBXVyVa#x7Cy1n&fk6W7a+`0MOJi8$OGYkwkN^}W7v?{WzVTJqnc80#)Hr4y?(m9pSi z#*Dw50@gYjuQ7cX_saDD&H6$>^Z$c&m`Q(l1ER*hmPO!lP0{{#L}H@Mm)wlUxGyBm zU(u=}zxE#ALWCTmdXPP%`VKoIxeob4Qs2=#fJzR4*y)o`!TP^EAI=0sXQ=vs24=uR z4*s3Kn!30TeDs}%@lb}Ay$fz~#E4(Rf8|No&b&jx%n)+_g2c=c&Nn>U};3L)vUPnReXl#CFKu+dcO z{(V<)3dyDGl;EyRno*NCfk04^{g;`>=kynin+e^tVLZI+d-|&_*YOS?RBb8+sZ!DCn6OMi`dCP_>0$KR+9E8%%KZwF@GAiPkF!yc4x8U|p&A zS~9VE5Dfu#%-all0$Mfb@^MB1Oq@oMsWk{jH09D30M+g~O>NxhcN$EYKCvYzasJZ` zLS5?vqC`|4priaXL(W{{XZ9H_lNre|r8!}XfJ={5If*sdvW$%kT#L78tIaG)Ff*m7 zY^ji+cR8n8nRV`)xn{)r#YMFp4Rrb@t+<7mTGiJPbk(HOkot0+S>{(x;iszH%b8nk zyhW+6hRUbav)xN0=MB#zon%%@%h*qS{e7AGd+-u6+-s1ty7WJDR-D3kPiZk7PEPwe zqoGdRtNN4g3Qs1X8uQQyQ%~cq0xvxN1c1lqyQRbyz013Pzw~Nj3+K!O7;5#wv+xkb zOR>odW~1S57q~es5?(YYCnZ`UzOs!ZaDGPhC%Nd|Ave_OdfIQ6_ha2{k2Qlgk8se* zhg`AqQ&=&-ja+!1oks=X;G?ou?TXi(H^uMbH{=v&UW=hQpORy5|LP>9u;*eG5I};D zg@zyj6~Xf#1&s57BT&~iT%-qVrUIp$e}o3gL;>$iaXry)8;pRf-Cs$C_6m}xFVq8~ zp@Y`9#>7h^i0Sz`!|29RhmjUw%0$BRl0%h=`Va0@f6X7=T~ep_zB28!bP+gN3kH0Ft3*J49dFMk|I-)#Zkp7C?8}43?=RB$-cRKM&S;_9s&P>S zp(gJqqcZ339VyP9`)j^t3Ynkhtp(w#K4uedZ4sWWoQSW3A;{wFhdL=TjN+}FoD0Rg z2@YnRX;zKO@?v%V=k<f_Qtfk`y)t&iZsWa^dVqB zaTB<(r=tE8;W+MqA%$$qo;Yaw{0bE<@U=^)^tOo|iI8t!BzJV~>r_f0m;o*d#hzoL zSHI8c9~$|_Y5aj#$~qxNj6Me(3q8) zb)Qp|fRraeqDCkWFNZPy=*U2>p31odTg1q5V*iaP0tSy?QaGWLehQCz8CUF%!34s% z%16%zXX4`RgC$NrF>Dw37-Z8R-KV<-ITSGD{*Ps)OmREjpgfDlg7?O31PC&t;k{4G z7TflouJYlHE&yApLe!tSOn3Jvn?04dW1g)${9t6fvR2$;XS-XkSK4_uLYx|nn6Pq8 zwg@rv4J~;U(@iVXIBKV|9OD!-18&An*l>l||1pTxXa9HwhnHRp&l%r6E8bOl@ItsB zps;D(hK;+*gl|oe`^I~f^nCk9gB4Yt!l8v`mGSj?p#p>gP1ppeoSL)>V}RcWQF4BN zhw+}v7oJrYWwf@P?^fRB^3;c)V}ct6d`8>=J|4ixX)y9O?(EBba{R)QBBuQS-u0`g z5=DpJj?OkoEb|T$z)(q!tv#~T1Jc{K#IXgx#c&c>d(-3<;RDkUN+Q44gFeNW+#4l_ z({Y0hup>~$!tG(v%rt_Mc`sX-G?d%%hyX!eKLj|DO1D zi;`)?cE%^GtzFJ7%bIrFzip`*_*ei_RO`pZ{!~--{$M8y_ui_qCDu6I(K+PpLiPtGf+=oaMW?2E0)5V1Eis`>eDAv{=Zg=++lM93OrK zm%>kf4K^Gsa}$iP!SgRKxY^$_jc#N@5e#C95xARlFg^&6Yz5Wm-$*c{U!SO8x#akz zs$YiKk5(cb=-WQY6dMgEvP4!-nVfPtz@7;ju`Wy7Kh2|ceyVg`K_(&-dZIR+U7pzf5ySS z?dUQoV6o)Qcq(`8@f;(wDz5NT+Z!ep@5} z>(`@OdmFiGxQ(b4AMgS75vI8P_}$?#erJbV;C9tEXh&zPGOD z6b4YH>pVU)HOgJao-SRK`K*@>)$J9mL@R;#-{Krm)mA^6JS$!CV_j{`XbN=AA*34) zj=wEPz&ak>v%E8e&*0%g$js8g1ad%l>Z0gWCh^aMoWu}j-Mgs zrDPxM#J>*YXX}q}A@As2Wrz#(S3dZfkEKewEuUKA@=Er7f=bPE7{vu!?LlUpx}PYj z3#!l?Uq6hVhbY+>&h#7Z?UnUg6n;x9t2uIVG7eIPk-^F2_&UL{6w}a-4xR;3rorR3 z>wJjEq^Z+idP=|IHY`QOFoh^jAL8|*A78*$&{MdhP@_($c!maqoym9m$haZ@P35*G zW(V(=BU`}T)-)#&1&xa0M=2^`@Mu)#{`o>?mLMzpwJs+*48_%;JWo;4crY>qN5Iz< z?iPrF{b{cs_6~0Yr&HSfoN@goc$pl_-a#P{{*;{#Gr-m|5=$uGQbmVW0%||rS(U;X zsH3Eo>$8@dfS6_Ja#L-S$Azmll-}Pe=+ko&=Ojj&23dKn>VY#LK(+6jj-Li44s#I^ zfqZIUbbq&m<3XTZUG&l%h+2yP5VgNDPEduPj`+e!^*Ic}zvF9U5$BV>Xy0s~Zlr%? z?RNdJPv#uv6%&{@QogT8#bg}%)p%({inFb;)MqK$4#WHT696r-Adf#B8SfC<lo@3m;E`fbSx%Km1=K!&A8DA>_;b({?%HfJe2*#0cLE z+OqTY#*Kg(rXNd3hxC$P$#$egJL6tlxPagyK#~Pn?G>-~k2<2~`0b|lgQROWB9{Aq z-I-OC;G6kEPrSXl+@A#4jK1frW=7h|(U0WRF!Vs9Llg7uBYcXd+8Ld%zLYg!eviM# z_8+m!k+czkk63AX62~O>9)WR;>^>j&LZ6J|s?H_!InYa@!;I7(mS}Hw>(!ZlU8jWr zZ)+olZs@r3M1XNMj?Q2TvI2c(=khKMb@&+3f(1;{uQc=`i_a@UA2I8_T(h^g!=!;c zAB2?UNXoDO5co0al0^C)$igz6>7Zy4NtZ8dg}*{h$AXQW)}juZTF zAV=HQ&yeIBM6<`$FsG#p%A!%txjmTgr1t~eBbhBapi(vBX+Xwzvqgn35`wQt)bUAqlnT!*SFSNUM8yA0`8R&moHMh=x{R}FL`CX(N zs!zaUc5bfyw&|Zn%I5d~CO^Mq7bqhKB<>@uf}8J8N*^qyxG!nmxdc~Mg&LKVktIHxT|lbmdBT$=G@B;@G1&9T z-g7Wi_bflAE)zs?as3aTf*?ivnymQDRiI`;>=tSeQfujI`e|%QX#nvc+dU=yH4+$d z`OPpH4i&`q^dY?`iwSzip}3(ksu9NG?z2`xEIwt zR7ZOhJ&lyn90sVvjte*wP(R-wHJQ^H$^Fsy*|| z>FqkN=MUF{WHe5L=Li;WUijxs6XanpPOu?4hWvld;tB*Rc-b>M+(5#ETHFr8#Gb|6 zz65Y!4L1`a02L8j;l>AGvB@RgPr65vem^8(Wjh7Bj0$nS*d&d85Nwfdf4~Ni^#DdF zFsKYZ6~H=Z^qFuT@J)bF@?Ge?%R|xZmst0r-GK~vL^7-b3|KUtT-JYBegEH5gfD_) zj&FW|#Q=Kp8`DsPoL4r6qDeZE2s(zD)+n>H^bk zffC5@tzI(q!@7u5xaXh|>nksD{30Me?mj_iqx>$3`QEUY|62g`84wfR{zwW=j^=C_ z#_a|;dzftj|J%Mkvy{ zu7pf65hIs-hWQo2pL8PUNE{^qNw#{fBf=M-r(uJPU2ha(lPP~##E)fePT~Av`q6-x zeyq(FQJ{6lwu~`ysSObJEg~ z2d}CX$l4cFK=x>FNiK(WJEvAZiyaJ9h#(9WJ`te)#?Iysl>U5A9-l0@3S494ooMj= z(OGH+SUP`N8oE)^g{oT6;|0z3T72*)f2U=xIQ!*vOG(b(@`YoauA2Z#W>;Dv76h~l zyy1NwmlcpAWwM+)GZ1E@=GE*%fbCGZC`f^=4u7H*8*zZh2knjjeOO2w8+zK3naSQV z#pOf5H*2{T1R*cgm7VYX4SmQ=1bzl8q>KRT)eTty9iZs06f7(OSP)du27)s3bAO9} z!Hbe+DA9{uWAOhwLaR6OxroF82Et#`8h=gy2(eAvQ?k764qbgbi$y041h0eFZg^Fl z;8#Tn|3bK+nUU6j(^$^Ta9?c-VBnG)OWl1ULsJx}_uA~nAZq2w;juy^SKECGCtTcO z0LQq_9+ghZ3%ZcO1ROb^K+g3D@;`srIz;LJ;wQm3MMBvLfC2nH5L+edDRxw;%nC&4 zNvQYr0Tf&g_suJoH@$)VpE2!BD1nsgDQnNOD?sp?PsJj!Ye^Ci z_2|!2ARYK8fs{I(tsPyEHOs`-u3T)Q8_&Ul63P;`(qB_`?K|2VSPf|zkaCJ>gADnb zn@`-DZh|llswFc5HG_)Ff2X0uRs!%U9untH;2Ydf-SOJZD5=t0GOEq(h(1TI`RD;= zFonPewh9&#)~;zM_KWu=F$t9!u_($goD3|VgOSn$wf;5i^pyiD0s=P4tI*08UYYqA z?BDB#k_d@Y*gyCnI!`G&E{j=L9j>p{Wd@(O*6c03gx-u|Vi`lOqg00me9OS8Zi2s` zO@Bs@gdP0m-JeeD13(Lr#HR^^Peu_$*|B8ky#;t1Iz{XdOnY2>lqmXRmR+UFXiqn- zq_frvZuZ?}0=B|p+;R)* zkDrroBEr4^{89+#tae|16o3Vkdb7CcKpMNw^UVb?Z2kaK5vcCoos2alI>W$`S#`b! zNh05(YTyD_e)WlCc}bZQGQQL(v0gOaCH%zG{#`(xAY#As>R%RL1AxWDslg}isP7)& zH`_bk?hjZo5vOIWni^3}ODRl*Nr3@Y(g$J$SlOo%)FscTD7ixgLzd6T+A#FM!DkEk z7gf`P4?74hNrQ|w|984ASbJmUeXo%_3Kj9jJ1_e!5mGl3q_7n$8iKKNtRX%>Yl+Ew z*mDKcHoz$Wy4AI_z_@TXtXQ!C+y-Hd^n}9t50*jS?HJPU7UPoN1YsyVSxgw#G5SMM z7xP64)z6^zb{$rF7RL_UtTiI&MvQA}^-&Tv1Z6q2=7CXFq&;!*Z$ zitLZ6Dpb@LaX*469qH~@{e^HtEVSo)N;H{aNGMKc=z#*Nh_{Znd%?R?NH$3A5Qn!f zeDmscXCel7eTXLkiX?R`I7CLGQXCvwpe;)z zG(i-9pl|K~`gRaek5>y0k)h4dJ&N?Z>#wkJ4`4_YhBPDz4Sq&>#jp$pG@{~_B3`xRq=%4Oq9UHA-M z@i&t%EfAcgE3|l&Co@jVUSP%vVELY|Nk=PA%dL3eQB9{3Kb~;|(7uYIYzyosmO@XI zmkRfsI_giF)j7-_2&yvgE#K(3BnLBMU_$ZNtRGE<*RG%SCWWt4Bc7fl>Ar0GecT6= zPD;oC*Uk|?w{Py^7X}TgX2H@DAhbrq5%pVNUuyV`{J=S4J$BF>Zu1%i;HFz=j1KI9 zk(6%PB*C(yF9d)vWQFA1n_4n>H{izPjG zfvt3gSRsSohJ>@+51VRNU@%m?F}G(9wMVW}u6$%o z3`am$J7={{z8IIP~(5YJ67cAZE^;m)&J_Y?odUJMO#%47YUWCL+1O(@8Bn z|H2qUECkV|{74-U=xF%JC}BAM+5|Ttde*!<4_9<-aiV^|JFPu81mrOvKK$mg)+EO# z@rL2$9;q|E7odk>c{*(k2zYjm^O0|dVduB5e%JHyAUPHo5;Ui4lFP3h1p%~>Ee$uE8G6`GtG3-_!)SXHrAgz)ya>^K=-05S zdkYBPg$lokJ2&7=TE`9FH6p=(IA3lAy+8ZpCMC8CKydsRyHS5I+2Pzc3EJz2pTYKSjYYtN0hg7%e)@R2Xeurzv>ERB((yTdJu@}^LkIpjI z9o6pC?bN1v$1Y+Va6P@eA|;m4(~Uv&A`joctLvZA!vE&9cgWwBS9$fEyIeH^-CwCAI$=>+whfV%k8ehLAT-}z!-HjxjU*#0zZ`FzI z?;bB4Z>8OmSoHd!)}gYg?fPL~`ji5O_RH(rcNZrYrlw z0LAocwK?AE-7{{#to!FQ$vl$_oXhfj1MRne(0JI||0=z=@q)(VMtSS3sY-X_sHICD zm7}IqYETX$!RaH5RAYdedZD^NH8Z$QPGggt11Lc>`e@0E?PZstd%dXy>sO52ZHlP% zds{5Y>QGT^*Gq0c^vFnP96wR?Ds_UfwCNo$%=CpkzP9GvbOLGMfCk z_f=)2^w5=^+wOQmb?iysLWhIjJ6_hpJlkJtm2Zwe*(@6obX4gO;hHb|m&F!8SoRmx z-`3a7Uw68#tvdpU`BWAsHebb3uyL;-JfE-S1U?%ZM_@N;}Rz4Hjd^HVfwj>~DL_!P~Ak)8}{yy^NdV zg3?ku1C12%MRVv}Oym~rMIOqPR=*7W9#DKBq z+yrQ5*p!$KzFxbkfiWD>t&zs``-F>(4FHH%I3=p?8q5fMF zn=cG?r49{dpu^pq`+_jKrSwtrUYjH@$GRTh4R`uC#plnFPd;0>SK_$x&`qE8LPx57 z{!9IZI_>U`{4K}VO;7Z~t-gFU$FaXzE4ZdD%mLWVeM$RPW58wnFZSLus;RZ@_kHXl z2nu2W5fum$dY7&!A|!w&^w4|ghTazf7BC_`bVU*fz4wmv-fKXl_YO+kH$MB_=Zv-1 ze%CX``FP$Be1I{SnVIvR^S;Xe`u%fC{o+eVK81&ERW)%A-u1n6ROg2sa8R#%o!@XD z4&)x4u1|DR&ai=p$9?jFDKz13YZ*3|_1m04t`Efr6W#p2?EHs=>_{w8{4q+g;96^} zdbZT50cL*!q6W>%aqOELQF9BYNsYVjf@}7INUGlyl)F*Toq7%ehZ zikE7}2c=kdtqTWir@bxVuttD6fJGE~kl!YJeapE-GKU!GG43o!^Pnk3BFh-4-#cj0 zg#>^0EyusBv!FxT(oiJHkj>srlY4ZtNpkSPsvb!h{)C!bzUdrO(&erx;C+)UnF1R8Aj)~4wECzqT@>(iPUah$n+f1|dW$B(=GtDt zw`^qzS|Q4CYnixv1Oq4!qK4NpEV@uZKYG${k5@#>3&2_G8X z$RFPA8ti8ic_WMIHCmd|8J)lmm+Cv}LHlvO$#QSK3-0yw6kU3RrYXKRN)VBn zHu@038@BP)SCCL*P~8hiT<)dAkneyrJ>_8GPIS4~i5u%NE1&VMi%Pu_Y!@IHVc!&7 zt6UDZs|{m^MJmvX!lTV|Bj1D@ItHjcyJ28m;B0)T3=jKeqtYY~i=acpHI0hj^F|tD zfq=|(ipOfO$wy%%;tXZu$@rG|GptbINx$>l^QFHdvZBDNKgt|#?O1RiJpMTNy${z= zFyy6$tgm0qH}>AAtEYj`MYC8Cr$o}~$Awp3bGPzwN7L_o^fKRR zc;oS-?{Htt!q&^n>x4nRy11C@Gzw#s8GE&FVY)A%ReI{oE-`bs757#} zUky9$X&|^5WhlD0a=Yl>f~pxElE$lWVuRQYO>X~?Q_`wDJueKQ~O#{w46dE-^YZhxZUfF-*cl(1=xpuH(D4uB^!#nq!EOl>(i( zHy9$&hdqtZD$Fl?W@qFuL&-p>*BF1@Fq2Zp?u1@9E=1#kG*z`Pe^f`X4Sz0Rr$5mKbK z!|_w{XwoHxgjU@gE@sX!1XrJtwtq5gdl_$4nR*ePiN>((3IC{cu{vab{OWW_w3$Y! zid{){UPf5dS=w#}pkrj0w|J=$bpC2+lshdoQ!6%$TEjhwZ$6bcPO^Fk$G?vpE{-gr zL~0nCf9FA`5abP^+&xH5V$u|kU{t|S{&8Dxg|#w;w;~y?HqW__eedI2{_CL?#noym z<1ake8J#gZvVrs8jOau#Q(2uYz4yys0fBXCq3nm7_W~L{`}TK&#`1uUS9ZS5_QtYW zo10(9SBY3`qMV?|lu4ca8vt-jD_~JwO@8@RIW{#L8Gd`<-YGPk&*{R7kK+>#(&c4I z=N0e_=S8??eW_9|9v95Iq=gAJq3qFf!G$a14N~H753G8w&EKHM8<;2Z z9yW{sRTkw-M#{~nhL?OB*N{%zc$2YUuz6#MWK!te`BSBPw@O{8A-h^6@o7|6vc;x2 z-1seV>tNKezYw^_b+G{YG6lDe2tZ_|$@drDrSItr#}bczghhJX5&F$}CwXLL%YMwl zCbGsf*1j)Q9sC;LnJ-H&VQDs7q89wjw6W1x_7MAgB13ql2f$j%nNM*g0MIOI!5*j?SDF=^>kJ8GT zG%?FF`YDOv(!Fgm@l!Cogy01dUxYu9Uu1Gy_$`*%;ZCb$=jCD39|(W)CnoSVvEAPN zmgcAcnSVUtBBp>u8z^1d&V9M(-6$K?(=7+|ypA=)5lwQgL$X2qMd4m99y0(FbgiZ?_WNBM*pMy0DYRPbgjtT_(65aFJ@KSl*0?}w7Sn&~o zyJB>5#lRbpG(GiN0AGE-#k=09qdw>?9^7F^O5^~e<<_WyNx}a4Xt#9TFiT)sh$$&B z4zPcnFCw~!W`o9>EDJ!~DpjZ7PbKE{ln5p3wAkKqX=vAVYj2#``D2Q*P{&s(dG^6B zZVG|c)L!{&8yy|r7CRc1#9x~9xTPtyDb-Ms&aXZ+}fKK_GCkIqJoE z!uPYtUrt!=CQuq;6b&1b6`(oT5W&GKmaq z?dD7H=T&7@{0`9q3)Wa_3=9oH*8gzIlng|_2s8rxj*%05C z^qNf<-DQxmb0dl#2JeTgHz&dz&J!T1jh9=u!;jyMru%j6Nn^-WSAmAGP6WOwz=Dhl zd&!oRqpqRD^n~5Gm9pckMfQh!i>AohL`;yeAtqPwi#R;;aM7-ki+jtl@kB>CHK)&= z;ffFaLOkv`9*wu&gXw)YnW?!I zeg92}!v6dNPBPQQw&IAkw|*Uys(w9WoGyPv)28;}?iWYonSMQ|`-UQ#hC=#oC(gW; zl=I|;e8H9vITw;xPG+4J;fC(~;IrM6;JaeKo&MUp6!m~#zPvA1ha&CuBaY;aSL~55 zHG%kRP~YDiE(lf%jczgJMdt)wk$Zdxy~`h1B-|<&ZN_@4@g^SgRA*jyf2Qq zyAvE{{+3NWRF*}Z?W?lD6T`ax7TZWpuDzE$R!CtgpbPxSEiX_mUA4iZA_5NsuTC3# zbQ=fkKriD9;dz*UQ-zP_;lh|KiZ3#hwo0LHXnbywg}w<=Wl4PK<`=>A-VAPi#LbsF zYcgQD!Ljt57_rxD^3&e=E59$8I-sihms|jl_EwFikJ2y+KRtA9KNmq%PQ>rsy5M8) z1Dyb5dgwWPHKWb|Thw)ywAp@znmql$Tny|qP;qIZxE?E3XNbZ}^bhNF&kf-gAhOxf zy-nk#pH&Bb1{RLXv4880_BdT(24}g)2ZgHKsWjyV78BOm=J2c56?(?D`7Uff-Tt-9 zk-l$3w0{{vVLeLNm(@B>c{?Q<*pMHCuKg%3NJ_nb-)oWS))>TVgg;PZ zdd0ZBvt_~IR#+Nu_-r@XoGWVruU~x6DDl2&?hK%GG)wFgRm6Q9ChmZY_T0Oe`vKs_ z=iHV$Z^0e2~*IH>iW)p~Civ`##^3C!Q?8OGDH8S$f{X(KnsHlp| z$1k1j9M~G`e#je33-hI;;)Y1Q9ES+!F}!PjEaWs&q5qP?o{+jsMzAm1)J2}~ikeWR z4?XlKZch8$djn_kTrb5D7wRiV*JFAHiyrB1PPsKfJFTwFH68(3MXmM+(?3`HPS}$t z;^<5`lFi^z7s_XYZl$MjB{f0!OTBixN5d2hiX+pXKdNDzSKm)P9M+Q8$FgD0M^o7u zgcvg=yPZefc*ecVs7fqjWRg4csb0XMD{2_^rSwd*zUcnzmZv%~e0fPBGzP-Xzt~>oSKd*2LPFG%jKn9>PFH$5R@7@YRoIG;uhQEHKv}Z3Zek(BY1yt_&M2eyJ z>5zkzg^9R)Q#);>g|=AVo5oy&mt3h$JAh}cG1eRYZ_7I5)xQ)Ae-mOaOEZ|kWvNnA zS&D@P-}Bi`nD6H=K~;j`xD4fdX|3`w4!EX&qL%;fWFj?c1csNo&iK=9J*93k<;Yyz zk~=I(C&g6vyoPj!rd~>^f6RXFMoDU8A1yA5RUhMmvs5ig@l;PUfg5JqQTKMF{r zD6%+?9&<0BH`5_|__k@3vh*UZ_MTg9cS_`k!3T!k9`jqArTY`r3J^~21Q%}9xI&Lf z`12~lO3e`NzQ%=7tpjS#K7m7N>Vp&lrwXs zZGCBz8~Lg!+}!T+vlx{-woXC)2wLGo4B+gr%&6OBI1 zBShzGS|nvmRY|wH)ll|4swk9iE^Nkw#Uc`spC_T66HMs+by(1dssFuKbopS73%f;& zpSWkeLVUb-TcQ<5WJnt$dIv~wBbVgH0W1~-4=n(T%-U#S2dtytK$yeEVNG^ma9AZ8L`MIA?{Mp+`}Jn&g-tu zGN+%Z-L!zOTHk!5&ZQ&AgQEshv*kA;5-1fTZV~VKuG#CH-Dly>lmvmv5nHn2zS29c zt`ibeO330;WdhgmQh2>>YNJG@ZI2zfFi>@$p}7&t$FnW0DYG*F%OhlV*Y8GfNYxY{ zN^9#0pc-pEHG2|420V_sMT5a)_^%s+!F;N)PLG8-Pr)!^z9F zJB|wK?|l}DtV#W3*4%ugqCs!1O+8}U^l2+dVQGFELotUeWH@S^X|3Tdry1(`=#V-* z)NZ0$d;`o_iuVqS$AUp3a@B!S`a4TT7S@jX}K3qyOo=|=u)M#Pj zLIY_l7>OaxLlkupPA`+7-o#LE^vZ_Xir4+3%prz0YjZ=!=&SC?D9v*;aT*UR?V0#5 z?-C=~SL1lBniJZf*ziaBbxIAA+tTRuo|G^pJTD2bUM?fgC-CNroF6*;bmBb@!^V|w zpVe^#39C(E)_psMmm4KsrB96aY8+OSPJ3?TiYeE?8nxYemZ2siPmd_RXV2bFx6 zot~Y|FE!;PVJ56w+ zC6j2vw3f}YIBP5dP4&M%So%D&Phc66%geRG@$1F*4UI}VbeJe$iqq0StCUoH<_oXG zTP9OE??1R0CNv$^$&TYS`LRt)in|whAvO!tG)G=7*F>L&{iU38>Y`E1AG35lUuPLz zfrioMb}}~jD18UG9OlxF->*{$F{3sfCQmiz#A9CL(=TNFT}ZhK z*jjp|(77}Fala}^7IjMEVzmT$2P}y6>txE!ss>lxe~a-4$iZ?(Wl?O zp<~ow;xc|%xZ2af-%dr)5g2gWaBAVUDMAX8leX7&m4c=jse`-^aX_8$HM|52y*5@qAzoaM)4 zWbi23e&#m6CtbK5D+z&>-Y4V@CI{s5o9;|{lsySysMxB!l)P4~$9iBTra5p0W!};> zPruu=35ksV!acuxWVI5J;d}&(kdgwfH`-7F5M<-6iVSP=9xFh`U-XP?o)*)I=eOD< z+aH@tCzqw`*}9=BSaNTn-l^XuBE{E_gj$VTD_lLyETKwyuHBtnaWo^gIQmm)welb; zddt&Dgq3tuv0ZK#qh$N-?MKfwqQ=BXOvObgQb&E?P~+SemZ^5}<4dGxnZ@glrqc@* z1Tj(-1LxFa3H^{nAl&Qt!pCmx(q#P6YXL10xYuUfE_&Z>R*OKbelASqMO%fSx15YF zFR9&{{`lYzdsK;jWPLBQ@m&!8*E*7c=zm_Gx}x`KT;BFlI_ug3*wR^1DGJ4a_M7MV zQMk1B{Ee6((|C`Gu##Rlsz@<{&dS|xY6vRpKKGz>*laR%H7-5jGOTjSUQXNSXx&G4 z{_)<{W=3aygyO-QB^C)7aDtKLRL_M?kI5!225;0ZHWZo8ga`BZsiL@wgI{Xr$FBv)1m;#zP$+kE`o9ZaOT|wwL#&+hO9$ zPVxkcDR-N~qgNd6`gx({uEpOlmq9%Jz?3|kUdAcGmh0j8sh+>nU7M3RXYk4ybxA?u zj%V}vLeOxFf;$f)?s`8>TspQu!#CC5aIzGpdl9`%`g3;6b}P+wRQVr3J6g2}R^?v> zV8P)T$G>8kDqQ`~o?}7n?d-O9QDi8Lr#v|JB_Ome`L|?HLYxFE4Uolc10MpCVOZ6V z{|>n4{9nZ?->7n0Zn8asl2V6I-8Jc>8li%t?VSRd|Qq;Sy*M|j+BO^H`}?%_$U>NImxwet^6I8d@n9RVPBh@ z8IF{652mC%x~#4CJ~l!-W7{zay^w1HsgGRFI*^lpd)*!Np(J8{Uw>_AKuu9ZF3te|M)dvW)^q&v?Xk zdCd0-%d6$&Ju=m{#W!nDvR*!3$~NI5k2`igClB+$QS1;{#|D~%a^s-y4X{27E zR|XQZq_EQ+XkDbR5R8Uba%lwbp}W15^`I;-ICQPf_osbW2(BiH$84l8?b<9_22Fcd zM4Ua1Z0)E8wfR9^xac(j{_Wc3Am zj5W-Yc{RAkZG|AH^qzKVx%DX~?Y+Mn0bm0Ey3?^Mc(S^~g@`GkkmqUO-M>&4wla|N zJ|tq-qIoC6N#dH3CR8E8Y=3}CB3;**ZC-cnM*2~@f7^HHh_4pQEGOG;FvObF+WbVR zE$7-bR`=;^uA_se8uWHSt09V3E!EWjPm*Q z4eS?WIMk|#{CoDiFS=6e^V|y^&G|nSo%!m~aBE4EgT!;ki|+y{_Iqz^ZIZLbFngn? zh9Xi%b-HlYjEq0w4ekr%T+x0@ELJFy?N*q@IY>0EwVI);@$&FE$rB?o%BuvTBkxD0 zXHUPK2e!a&g(WVM!a(`5C(yx)l|y={kxGraU#rQ}Azeg7&~R_^BFlYXMzl4z#JP7` zv*u>>cBtmPb87|b$fl-VYpt^3aWve)7`QGXXEQm*uRJM~cA^pA9EGXWGyym8Xx*?B zu^;S7b33yLu6f1TG8P5QIN0S%zRHM`b`O^KSLmcPR#Ev82^jo$hpn z!t^Y}XWs`CTd+X!(&xg0%ei`OD~${ar+c_pJr)ibf4np~#nr#T?s#h_qF9H{9p+q)?OX^ zZRN7Y+J1B(?7PcD;Q8XV)V(cMOC_|hy0*!B%e}NF-V8kk}?b8~2Mc@!Tp zR`BI(e3w)ulen=(IN~#}O6HZ_Pjav?aM(up)<@O+i_Pb%hp+DuuU(7kj2+*nkJjyK z^*{73nlYZ{L<^~TF=f2Jei&MnIHZ*uAuy1DeW`Y++{0uG~Oa&p3Yx%qp}F^22(7};Vih&5`qy{kHRO(Jji5V^=nPgt+WyoexL&|`ta;9gcg_Bc zirVxCJMNdS3@Y zeS|%C>Cd-P`C$6SmeI{~y{N%-?v9#<6xWMOF=6{(`;>#1T; zfHj7#nBkdUmwZhhC91qoFzoICgbS4*4+|&Wum-~R!u6e2a_)HxhoSsJP&@7DVDt*+ zWHzM>$-T6s>Q^uD?Nrl5{#lR-wUVJnDSw^Bitdf~@T(2wfqJ-gs)0FKVi?-?3T~4))W)Kt^*}U{- zE7LQMRhe1T0hZ%((;a>5mL%KO! zzI{rO`Ep8W@#@7B!Tz61WPbPWV%dJIuUWA1_w=JG4~c;cDo!82mH!%8b?vaTbJM=g zQuwOFN6DgJwX%e5q`QQ+I>k1M5Qd*h#7D0>ck*$bvnyoLcwF~^WuM&^)hB)Y&E{9Q zrGH&FhenWhBAND~{o*_hjBp~%Jk@B*g-8e;{+0NO2iuQrI>nC2FK@^;{qAvd<*w3y@OTZngbPd7$gZCwDG{w|u%1GO)BtJ8-zr z{+6H#-Ytg_$5X0!UBr3vwo?{+K%UTE(i_avHb-XSrM-ebam3@V-s^+-*py5HGa0Pv z6k5h`Z)*HlMc@n#)9ur@m^$~l-!i!L@^YsQQdi)LIIiNg&h1-zHv%!vw|P3yhu7ch z`mHxyEXKF83g{z7xQS-~-?X=|79fLplZmlA~d;%?`qQ=I%xy=#@> z5}i*O9s(QtL$KOj^fW)E3nx0V))31v6-O`XdCCYhos@x$`A0Ram*yI zgU*+`QoK*3;-d@e;gYa-d^_2Ou5bRd>e=M>CN%$Cvc+9kvk9fpAUtON=Iti zC|3H*rP3jtWkjc61(Qv4zWBe;V`j!)&CS*xa^5&L_6S&Hl})>KO!NMnimEs9`IiK_ zP}A9ri>!#8<(7#A*ED`lqLq2boBy+HO$SZ zt-f9x7nu*;jG-3yL};gV5Y*&t`wL3Rz;<@>h5qW z*&Oupd(^UBu{|57?)8*J)((&)W4V(HmB(+Pc7=OyZjSE54KIz;I0)MpN|7!*RHmj~ zx#0{ef$3~~jW3~n>A-}{cr2Wq97ez~B7v@de;v7Vl43X}#47i_8 zx)$TPLQA+dx8hivz8i19ps^QKWck|qo-(P+i1w^gp8tDxtlTblX%K0>QyC?m5%V}J zaZJ9duWhm5!fVWeMnuZlTaQm;=eKl8$L>!{Smlo`|rMF^mXGt;68K%YsVF^iO@?79`vlsDxjPubCw6@tYzjeosyuR z3;MndJUI3oS{G@4yVtrqjiKRR0Yj}7fczBD<|>BW8Hk8P$tKh8pp~b;Or9+MO$Yvu zM+0OZ#02*;e@Th_c(MAl@2kwTqt;2v<1>f7p%Vt+C5sxia%v7I+RAiWi?|yts7)+p2-2$Yhz_6EJ z;(@Dx>2!Ftv|Uw!^C)kvlvh)rP2cE;vk+sG?ryc?wLr#-d;!LT4&DA7hbPVTTNzH3 zrae0Y!j(Bm6|H%;mIDpfSbZN|I7@l^A&>jdHL{S|H+C{b7Ox=(EAFnOgD|maP6hV~ zT2vk6Cs(|1lL_3$!yMa>iYzcHtq21_`dd}y^b+c*4Q0w)VBnZjaSb}Mdo-c6TGsQ} zLL@Qytoe;FesAD6#P}j2KY6r@Gjq?{Y`40{)3ymct3_QwCa)Zvl`6LwT;LYkZF82q zRzd`6h^i01ZUcqEHk?3Q1>?FYWN*yDrX5esjeZi4uz*@?jp-YHEQRNtcf79C-lS0s zq8VAYxkx|4RR37lR#;F;BJ=B9xBZTC%RId9C2J!p#q2O800u}L8>UV!v1@`p+z(!~ zpWPc`2t2O6${6|3>8pRK74UEY6I`B1#8L!Mp>jbK;;P~!LI0(1C~P#u@emGMLD1}k z*SNr0IOkmrTI$)RgOAQXqUv)EuRyn+(d1O5H<3FZ&_LSz!~gKqA1&pHZrK^qu2o0V zn(%tWmT!|EUu2CY+bJWt&>g}$j$(wHMP22`4qj(xZ z*TjFqrRYG9pV;oxW@x9|zxg2tCMoK+*%p}Dzhf0LaE{CXrir@^X&MUG!%QjIZ7VZ% z%rESRdn`BfTnG=DtcD!5d|Cn0P*TH(`d$x04DY?uiiSB36M6Szj8(fUqlxE$J>f<; z#DE_v@jj0RD|q`bH7FmmI5~f09z0rfD&LCX2mR8U74;u>8OeRH$64BEZS^5;dkP5oPUDy2#B`=Y-x+-_rBVW z6o4cH8I+y)i?&cX<^v0Dv{~_5GyRep3%)b0%1>?dvjIO>lv#G=je&y<6D{EMN*`t2 z#VDa``)eB-CDfT2W%jb4#mel`L{lXDc52vq$n`;i4<_z{mp7}vor~Jd51Y(;?mMkR zx7$lD#Aq18d+azsbCO1bpG`!Bq}PGmu7rp#O%-%kQsj73SCY6DF+CzBbg? z=^jTgn&LsDrqcp4k++%?FxJEMO>nOgp3q3PH|Xe54>B{`XBU+r2Q$7sSsEFq+cw!= zdN%_*@*f**bEWRxN+#+hr`y7GTn7vy;SJh5qbyEb=6MV9gTR=v`S~b+--oRFYu9mU zLESj{!m_#aPSPnQu~`FJmlA7=MNeVz=Wypx&*Ab_vhq!(YOy5uUCT|fR_0D@$HwQP z*4M+G>79r#b3#c8s4=Dvt{m|Pjy@sq&-9}oShyE;ObjweB(9<#=V?8}K-cCACP96V zg;cyS)@9G#6O{yI>ZpJh@;EW|lrNDt#3z;xQgIcp#K1B_$^nXMC)kM4+-5PtB6Wl( zr5lY7AChC)kWWgSvFjkSo(+zIwN=#?a6SFK&D1CjJ78Iyh}m0GK`?BF(4OJHQ2g!9 zxK}g|#2^-8D%L+k93rn6S1wQ00RJ-l9QGkYc@)4mQ>hskj&T%+h$Sv3%(uzAXC~d ztHHpm^9hv@Qs*Gu4)@wVtHY{nw)nDj-9l=^`O`h1T(0VfONlsn9x76A(;+!5yKn~8 z&2k}kuPDYOda?IlFwF!b$`Bp!Fvtmf68&qg0jy1fF5*B^&7*M)H}r1}cCUG6h9|$Xj7}DK0nI=x`}*^TLqm$DU9>{NIT!-it1FL6a|j0mtq{(0c)l)# z#AJdX_iMQug?cgYi|j(%KW3;#_ij|*hCf&jMn=@|^S0~ww>D64`159QJv+qn(#gT{ zS1lHPeZ3AJxi-%(tsBg&N8?GQ7{kvqp_wge z&+vd1s3>%5AUIJ@5%@}~re&BrSmnzzxF|FiK#jWJb0zyMGrD9yg+7VRz-A_9O+7${F#vrHqRd)#{eAdon%1PIH zxfYZw{5UVCFDhGc^p(>DVcBlfO6p>_K&Lb;vCH9^8m=i_|Q@CC-l+zW4XXa8F3tqyHZ8YC#*GYL9kzmJD-D@+w+6dd}t}<%< zqg;SzUrgDpscqDrz~gth^cwwf?^0Id+{~|L-JK0(-A{UiVf_W}S$$~R8%1PFu0Oh~QQzE%Z+m$$y6n|P zXKC%N4H><0`f_Ws;^Aw=M^(|>w!iQJzt@fEJIr|2!Jw>tX?!@v zXcX#33_`pxeVO!~Jl`JmLh}l4NfL+=GuPt-`hm_a*5lRoaPzb~-qEEiw=k}%)R}mz zXgJS}$R_bz_y)^jNpSvrgs2^hSbKe9sn;(T^+_E*q|fX`hWJk2h90urLZvxoK)HS8 zpt|0p+NB1)uKBjU_kQw@;}b*kz#DF}0J9EUCuN@eO}N!41~kBo2aUWFeOBg$K*8{; zeq(08_kp}hLiZo3%CXvPDeO%sXj@t@Z#dLq?&+*O%&YTuTcPp*N>gK!v#+T{SxKAj zC(}lXACCYHvO@>jcEpvgX`8hD4d$?WJGee{_mup8&)v>%Dp5|$&pn32o}p`24IA8l zc(a;DWKt10RV`%-J+TV0;Snjs_F82}98|Y(hB71)ewcZ5Z}cZXj4jTu&dWPJl+(ZX z+|b;!g&#{?h*O`2_Boe)iFv)9h=)EA2194@4s1VYl*fl-0#Q2W99#}*V^3c$v?ovf zdM(fE7_cx~zjr9gg1SqBTJXX&#Nl2yjdKr7A&UYZ_IwY~VyLOOtm>JuvVe!&mlskO z=W-?9YE&L>`igPys3o~Bk=?O;qjJYm>*7*10Z9EDDaGb|6f7_W5`z@Znti%@akiRe zpMfdQ#guYVCvJGMZmjqOg%tgw>&4$})*FhTyCCTfKSS0uW3X#RJx!dKuqH6)ywurC zuU9fJx~bKul9I~amvLF`XkL!E$nR@{fzRW|z3YT2fNb9sAbC;L`sf4C?l|nt>4WRDxBW=5Vom=JGSOHi#-%H}dUiqrBLt z!bjg^Wp+>Gy}YaJn-EX)F-02Z;ZI|Ez?XKfQJj?l|719&3r@%m?65yFaFOrp&t&5~ zO6JDgHKlM#;a=h)1|4454@-SSPaQVJFQ+H^v%x2-$?jL=5;CIW5z?dG);u+EDTW)& zd(;$`4Z9_Pc7e6uml56cj6^rxWo>Tz%G7W&a|D;nb?M9Fq~`Y#DY;(;%ZkEE=&Wy? z(-I)KW7o9u`suM~r{vRX6Q7v} zJ=BmN{*=s&mZRsA3h{uV<@ntTz9d{8!K!7G{oV@p+atd!(-BltnjnLXo!GhJHqvNT z;kDvY6}&V$>j<5;%LnMkUQCGjSU{N}vA-`Zn3GOqUGwD@3~QJdCFgn@pFq!vGPJIV$+(p+J~60Svg7;JKq;n-1&upcNz;`}Mc6T`L*Buoz-Nnvlv$fET()c`;9~YUt zAGVgB^{YHnC|b|Ruc*Y@n#P7G8m6bvkB8C}hCb$*837!dmGdq;^h*Kt_Vvji^>|bu z^t(5HH2$xm+2u~dofq7Kg5=0&IpIPo5zXCR?o_p+cJPi`2JxM_Q*wb%_U;HONuwdi zscMtEWXLAbWw6C|X<}AVNzF7LjbrnkOxY=o-Q>8wGy$@l@XvsN2tcC*CD4{QyxDpB zZ+2Jld*DmFW0F!8Jcr`EBPRuVYhOFK9TrOkHRjUWDg3Yhv8Y1Kd>~>&%t%#MQ%kYo z2)k~a%!Q96z0mRZmiYm-5Qej}qU5E<5t|zEID(b42AK9z}31l zZI+hRvcaWKWI-9Wk69L$tQ`Rm;NjW_b8j|v8`mC`FVTs>Q`B;uguG|3 z2ZyvWyUE!!>*NG-NQD$^BVlhDUkt64-2C2*l?^H zeaxUDSwZQLPA=gcZ$MbDsu(2+#EV;okI4Tf?^^Ty0}XGRdG2}!J0CO~E-ypZ`^+4t zNDS7g3r_Qe8Lt$Cy5RXdP)^jsTbai%4T+8}MNl*vefQB*JPS*5GROF*!Lx8v+ByNN z$)<}*(ZB8kSf@4(Av(+qV!)fpwXT|dJp{Gg=GV}C0^ zna=pi?dR#e-|N*ZI4(muWmaAp+pw*t!LZi)AXogTq_nUhYlxAPTfRi2*tfH02irP3 zRtLjMJbw$DqWYI+WpCof#n_(NiJYdXJC<<01t2u1ecKe0`n0eFaK|`9LN*ExbnQY zxuF{txh#?X*VyvC7PMz$_reiFDk<6&TqX93W~X9BOAwyj9Qn8yw#pu%IQRE+CIcsI z(S4sDLce?L+lp|l0aOba`7>}6pLB4cZBZ0j-ZrtGU*z2iE6-b7llHYG&_n}jqmA>x z?lUX%(e;wa_w|5S!JT5rq~X|2D|WK;*>VZ4phX5cYEAeqPgkFR%SM2m>}GoZE*JEi zAe=lY%ufAHGcxYVMF9epM_#d8qFg9|3}k0ud+%ByjJgUJwB$8eQu1CXllXW%P|MI? zpV8l#syh)w&OS&{Hqi9v9z!~2sb zcY_@DpY6mc8oh+(Cwt@|yyh+tB%LS7S?UyIf4Y_(n&64R;+1ukp~i8IH3=e|CW`)s zg=I=3&KoKT(b}w6c!95Pi6V}spXG`fT&Yss1I00Zv;_It*2AUDHh$_tDOtZm*d@qJ z0`I!Yg6JtF0f@F7G$JY`;Dfe#y;Qln()V<6OScW-f1Pu_^AQKB}6muMvKflKfF zpImyNKNI3bI6s@>K3X7AiI*2uyfqREmS+ihx?JCj*Sy@&Tp(KK21CEtB>wAU@kF02 zo`)gCI%37K^L}hbp*PJQSU6y|Z7(1)e8nlr{a8BenP+e*nNZm-=aA5xv6QYDz+LVz z$bGH^<0e7u@7INa07$jvW>rFIOH&d3Bv#8b9u! zssNMRfB~{?3#NJ%lJ3a8UBG+A?hQ8Y+t?>eO{tdnLCw%V| z;;X5RNAbea_vw==&h7ze0x)eVS1S*9m!zm#j70YgYc*Z6s`cf+Z=4iqjQ)AGNu4#~ zV`B|*li1$MyTIthrDa_@Tiqyj5XJ1BO#>N|SjnCdRE!=8IYiTYRUo(WO3xNptw!K` zpBmQaFL2p*bQCx&_OD62TG-MEYRTkkEa6~vxzXsXoi5It=HWs`7cx7ZR#39)Q@=G6 zZS#g(aM;tmyLUKMp}z8nOxUJ#cA_|7VCIL5^YCzP|B<81<^}rOgaR%)hE-4^=Pfb0 zknoSYe;LbX4#~FMxHUA_#ZTC#kxbirVj15!v2gHqm3}5J7Q0tlSs5E(;kiO5Cq!7H z*q|u*b^%Mg?q;Vi>@>dqLExcJN3Bg+{w6R8uv{QqRk&kmi=!^(0)&m%z^VOuT8w}P z5V_4a{BixSAnLo{0Tzt#p|zAE`_`?P0^n>d(@-k?IpYMYOIr|=2#C0Zdt)Ey7(Uj2 z+s!!n4OiiGCr$`_WI#czms*ED)Xj4oWx+SkaGSu)4Mf@5ozMPx4>}?K-Lw<`Kc6Ub z_cz*=oC9oN@<;V=!G}>|*`)ulgul{ym$M^od15FO1$-86!6u3(d04#kpBno6fpFrV zqFEI9=C9xh%wFwjASB)QOPD0Fd_TFeE3c<5vEX{M5%zBYVX&wG=+xl2xF>o{mR$z% z20#u7N@ndwHTv??DJL&J$A4amg=ckuJ9rx_t zFT5c@p$dHXI|Eq}vGShhZpFuXn~TfA+xvS3moW-JO%Azsy1T4Wx;aH|=+@LN%lGjC z&EP@fiOm79+%_y+o*WoeFQ* z^OIZ8@Q=6tPc_fG`lmh3;bcz;B~xTi5xm8|@TNjvItFmd)z6>#$1DA(ZTZoE*>jRz zNmi)4rq~$z=uC0~*YAUY+4g_9ZU4=|qW$0d!pT0_=m0bc$31|H{fC0cpO*ad{~`yU zI$bVi^NH6`W~V!3G0?X1XeXbIOyCdb0?fVas&^kDcR|Y z2u{coGyXq+-;ds%rhfFN>-C2dC^eOl z7n?Ew8v^0)U|vY&;zBrUKVy*f$R&gr@ZUWxCwxNWyh-yn)$Bj5%(WBdxzoMfv|2Mb z@q+vC49$W$97P3(ms`o0ftvUUXng^oz75p>^pAgYo>gKXG8pq4&7}mag*$5{WRcJ7 zdh?3_GWoI{rg>86yU$1zjyX9g62&Dtq%azjL2+_YFL=x@{Y~!qr;`dk=?YPpn#%=% zPuHAc+AcXkbuM6@f|H^M?J@QPfBp>&{!=vZr*&|m_xRs~$uFVcq!86Qg^1r^PA=KA zSYpc~5p7ifI5K9T&O7rL_U2y>{a=`W{0YXMcFBPqU_24L4pO&)HpR607C&%TVWZLi zeDzP?(B|3PQEoEGWEDN1bj*7_gqaeHZR-MQm97$agw%`j^QfB%D!GX+kMr6DTn zZw~UOwhJ^b7r}%~6~ePV8ZGhJTwJo|w&rb(hYou(K=c3@7D`%8ysX zVTMXACm(5)=x2rjKU@wC#{b3Kd&f1oEp5YFL@LofJ?i>$UEi&wp=e(Uw3&7|aCeHpcMPFgx(+UAzZL<}sI zZd;wOY#W2Ms)md3;z{nl#3KE3vhAy#1c`aRTb>`BYy7VC)pmVrVflA&!=GZYtl z)qxjEWJ_{>lTH5f^}R$?x+sNDVQ8{RDAMa;w-&d+AWkAKx-8RqJ2?PhBALX|USoJpNbjm%rHW zzi$u)B7GOJIrbGnl3ika_L|bdM{NOGI(>=dF<;M_I^QLlGH1gVf}e+=7|uzC{42Ve zrVMwX`2=;gTic&8G=5jH->rO**l5FtdPjqtM59cTQ-fZ#B{rb_>G;aMYj0k&$bB0LvK*TB+$pIoPg@_b*o zRR=zyUphXe!2wb^3E%N~| zx=b)l*}#abSJ?o`)v4rY0iVH7z>ZY_pb{!7i(oOK@pTJz6V? zDWT>t$cc*Q--h3OL4ICH+gV7wDB%OhuZ|xHtbsx~@2cj5 zC19F1V<>6>)ny7`&-v7w>Fc|p0nf`W91;3E;mx0WeE(62>jCW=m-3B5@=1`Otr7Y@ z0P0~@&gfV%VN&bmoPimKndYnrpg=RTxCviwN4&cATmqUcxR%RmtxYr&{4gY&+*32fHr z_k-$B#0TW7`un}R)A{BE+{Tv+o%i6%oP3-DJch;kgU?Ll25S%!@rwBPlWPJcUjzUc z988yN7LZzw@||k2TsW3@X{IF!z_k6HL6g#i(#3>IF;k(ENdN4#dQiT#RmlN^O2&%{ zyGB0E&TkO&D3HWWM0RL9B8=n!XtX)KxK5Y{6X!{W|>Kyr$SWycaYo`WXY8bLqT zTi~zJUzPBGh=NV9_&F$O{wCHC4is`VIK zDCo%M35|0dw@2EEO-1WGe?Wl~H;~9*ZE>>nMj>36F}S&e;>Z*OMF%|CTM~=pEqik6 z)syO>m(WS%u-qJ-sN`Ya-(=3uF>{%V9L7m(t#gv72!%pi8-iv;H}rUx^iR>4Ec4$t zk&myD10bk8>auR|g%84VIJ6lA!skrtzQXymC31`~I2@c+KzuV^2de9AxqhgfY+|Hm z#34`tx1K8RTf|`4ym|PAwHG-BILe5ggR@?_oBQp)#rU$x7Qp>lA>yY!p*^W{=FOF? zsY!dK{R0U!wLw%bvTO7Y=zddGW39~`~AH=O8omLr&Pij z#GNObr5;T0oOnh6Ob0*No-gi#wF;rt^t!+qDHM(xVeceG#W2Kn9k~sYAMJ&&Wo^Rw z)U=$HaNUb^l4*Mf4>Z2d^OO+|BB7<3?$_5VCLC%O*wmoBnw^Fc3M<%q()+Elshx$$uhs#C3%>YeR4hLNvajb<4g=qYoYf9xvf^S;HYLEig~ zZ{P!=xJ68j$zehai=VGk#s*Zwv~sqEk#O`rLrbuF?c@dYbD34fv+`AMJx^jI{Prl; zb(T{Mc-G<#QCz|TV~~s@pa@DD*=W#u>oFw^!vV8_8Je?xQX+vzj0|RSsNLw6IXF1j zvI3>I*ByLvs-fV`TL=@uBj2HjYE)!Kn4TQVYqa|E9HCcgi z9tcV&&sB|DTJXIHs-mqp3*au=<==+xuSMpUPh(ZMI{R=n7t-R3H|9E-+;_z#}GXxq02@8hKPgz9uueo>Em zTjMf)Lbt`BXk6!cOwC3Fi>&R)gsA<&wK5MwjsuW1>6qfx=M$l!8&%`doo$Ub_5vLr z_BPpj1djJSj7y?~6(!WVcUVpfi-T@cKwj_QDfL?Jv{DIA@p)GO_4jvOG()Jm>BelA zNYop5ctWwjF*Tt?RVxwkUbF>&I6XvhKM`lK6`gvu+DPmEUl8;C?oa*4;W|O2KqFGm zQ3K?68GD-5ej~>qzY5j13Y6=!!Io|u9FDnP81VIC!5|kBU+QBWdZ3>i( z9{_oIkJgPkebCi_xXu|wKgzEK^;5tp-~NPn_k8D57jMtSe2QvJ!q#8`C=GG#-@)^? zRQA4eDj0-fA)~AHneInR`yI0K=g=F7t!{Big749UC}@%q0?K83dpS`s&{KxZf3DQ& zLg%%Wke<$}D@7h7pg4aiCVh9je$Oe_-Dh0XB({p7V+0InMrHijw^GyEVOi=3OFQ6gXdeq5m?k1iS7ab zROKwBmu;k^p@#lohkFTe()L%-B~!ftU*^n$sG*z_6N~c_Y*DWvC~_&E5mlr!_mcVz zDe|8mI$0w*fRn|6Lg=m$5mm1vvr<3WKGO~ZIcSw^gXQohZ}SyI)4q%SV7bw`0;+>K zzs8!XF>(nEZVl2IW6VQ8rh@hzyjJ|#R~Mo)F^#KZ7bEsfSazB{6HNTJ zpQ7I5EHf;H4%)pBHRS8|@S;?>QT5+a&Bzg%e!{is)+1+l2GfYw{jcEx zxxU^V0lG|1lU?f78=pSb!$eT{Xn}ywn0G?u@W#9gS#Lm(kF=z{SH9}Hm6L$rb_+Xv z3kkk-F)SuO^9{76Ec1%DT6eUiQTIMAO06QnEw|YKKF;|rAyd%EV~T1BaK{ZDe)iD> zO$XyZr!81XXcJz$a{nu;C;?_F;*E0P+3vm|>Q!=&A;wu~ZsrZ`!LNF?6Ng#GJIjL! zzF(ilIQZQUspcGnn(R(rQvbk_K4K^e-;=y2qmfiBBGtCO2kIFv)7IKm5U_(_`~Nu#$1t!P4K6< z_=Mtn=Fm8tPwz2i%4c88et3;Ht{1cR;l4=x8&zEqe>M5^^g6d4c_u!T+VHkKTX;6V zK*bxVb&6jANNLSBj;Cex}&}RG0j~V2x)YJyI(tMvE9yh4-_;woGSap&?SR| z_m;t1jaSi@x|O@nPu<&>^V`3E3CgRU=hEWdS-bA9Mzorq(59mWyt}M0Y7WQR6y0)M z6O^w|oC&UTVe9#~dAy;3r`;$TmznMyhYL%!vBS+V zVGO%vwy#SY@iiT6^zFABL^p^XG$xeTr({Fxs<+hucV7)nY@AG-E6~bb450GPo)%Ek zueAHnd*u32B~vha#86+rp)Z7~J8n{7Zbnq7Ix}1)Ym4_F+F6L_c+W=KQc*&zzuHt% z`k4Dl%(|t}t)yY@m~16~V)mek+N|$o(iB{#_%!g-Y4z`Du`-1jhYw_226NQ-F$0e-5>o<6#| zBY$}{3N&MwG|`kgKsLya$sWKb5k(NpjuCc#oSMuU8U2WZN=+nM;!PH)vQZzS;kvSk zU*tCa>7E8<9lk(erzG8qt7(Zbl4UQ`XoJ2yw;K#SPVBV=i&Ohon_pXCVzuU)Bnb|< z=#U~lx$9Gnb`I4C6}xsMNR-d*WqQdjevGQ;Mnz+(VoEQkr9RwqvO)OP+OYRIDob&ktX$7?$)0Vs`tNjhfpPQm3|Q4Xm0 z*K{)l6U!{-;n}3~(IMa$+6;=!`I__~-aJ<=U3uOnXbo+~H{*KWCp^Ew`iT}Cbd26N ztNj_T|G4;(+~BL8As6r6OIPR+!|roStVa4?+tWe8^3ZA}I5;~oE11JEyYDW8mOd~x zwd#!qm0#8tvIGg2Ck=8I1oB2MZN>91z^mrFDYKy^TitMLp%e4npO!eeMWe#A4+>aS z6kZS+B>|DK@XrrklL;UI>WfrqHDCj0lfzDm)XwS1wIGkr zG2}eZSAVOeqRWdhJe{TIJZy$SeR~KMC%|6_YQqIf(p@Kt@+c+8h=3=@gIlwU$XL-C0+y|if!!niGJ3ogoAmnoO5VZ-muTq ztO>LChkm<$FN%VF9lvAc^KoC2%GJYNFt?L1UVIC+^I9C;Fc|d}|;fgr}}BV=C_)aInR!7C+hqX5Q||p zqSM^*8l55-Uco3=#7=Tk#dgm-hO2YF?|zh@DF&Si_^R02&~8xiz#+3&6&mF_esVM3 zYRl!dU}Ka=c7EqmTyIOlbD#fLy{Q$$nv8C1#W~WrMf5FJDl+t}n&iH_fe_$%#djh; zx`mfdrUBEUox^cACxZ_UI-~N7$H(tk=M6yYJa5M$vvb5Yo4LU(1gFvz2}hyMR*vGsH4xsYg4WD%Ok8y_F3uJ7I}0o#w0M z{Kmt8;4_ilB0BEibxyEz`~N{l{@5r5AZQx+>J*QDafuHRL47?}VxlP3mUY!s6O8sj z%Ac!!=G#}r&RHp$_n!$K=)5~WGD7f0sfD*J5`1~ozlzue6!Gct%-ppV=z%k#vVX0` zPpdet&xEr68<)Zj+fSf%Ils4aVlH-qP@~1Q5x#kPttFlU=rKP_eo&~mL zyEq`-82MTy(4doPF{3E47lhgF#OgQaa@@hIUogt{x>uef25l{c>gLcxJ)`4oJ>avU(K>I&QjYliJwzfy%KJg z$w|ZtbAT0Su#}CY@jX9}u&`Ev2ul$oqkbP1NktDDCXr(xSUVl>ci64l`Yh_oUe}Ad zKFv&v+`72_M|K>%iDkVx`LRJIUy}+h_Y-Zm>jV@p#ro+ykXgKN;f0@LLI{!kn#hV< zLd2$nVI$3_)vw+nY3xlNZVIIDck3oE-d?|RH2{9=BF0KBj<>a5dq(?o-YIU~>`#?& z_89W;XQ7m&=K*(oEWIu7Kk#IKzkpI03BfnWPm&IfPvDNA5I zcAd9~Og5Onw2+^B!I8v!_~K@SqX^JF=bS^D?7`JDu44b2r-V!%pDGsm-#+F4Kku@Z z3whQF7??KaR}O2`1~=zfwraPm)_r!wu9G}2I434w_n3a=HYglS5VF<`2M&nsY&QMR zJw6oiUMW;|lj{a+KLbJ}_%-JkSb{YsdHu0S5bA#N4=(8m;1O$rlWDH>;rMrt_WO;* zxQ@)1)rdr!gkM-C8ekBCXmol{*%jdwbFJ6GRIL&ak^2DFb(jV-WKMs7Ao~e-- zxg#=Wi*ex;?hwza;zj=?;ztF(3b__SWZ4;5#kd2V_J0LprM$Klb96t)u7C5N{fn3w z3V4a>k1GM%YpveqZlRy=RWWek`|-E#-(qQ;W7JLo3v$q81g5Z2kSfcH z00*=g&mI?v>fN|A^wxYgaqsMwodM&Xws($AI=@)5go5d7Fx^1)$O%y*;%E53)cd)x zf+K)_JhYd35KW3JU~shRMq`kHqmuR=eNv~6JU&fXcNbtGa~Wxe%=cz>nW8NyvMES@ zr>6Q*HS!;>$^Mgk%SECAg=0C_V?ZdSJ6fB&LCq^B#4QGw`N~JRlZ6R^ye2>zO*Gt> z?QGTm#Xp}-`Eya}5$_QLu6_!9c_FgUVxdXORSiU)Op7Ejf^%69K|dPaq1z$Ym;J4m zSR+NiO2i&l*mMFY6%xun^AGO$tbkTqN{ETQ5g>6mxRwP;%+HKb)h*I&H|q}UOYU*l z8`Pm)r1a+pFwtVJWrLsti|l&rO4c7uL-o`=$XqqI_=AZ5Vyu5>x}}@}IRZ*o00?E; zbSInx`!w+Q&w;F(_5PQ3Dmj__QjvS>tL~eZC9D_9MrHPTDNehb2P>j*47@olYp}~p zX7EJZiGT9MZ(Hev%XRZYmO`H|))Z*gyinjKx&kzhz{HL{R;8Nk*RsAy_dPc|S2rEk&$Zj7>ovy-UPq{5`9@Y3`eCq$&(F<`g2D?2Vip+yeHDdD z0%&t5U|cs#P1-^XS8)8ItZchrY?Jwb^gL;Z%9nP@G1=)0 z>AM}fDi;gvHpoaUiRLHZG11K1n9lu~S?N!=&K4ZeIf{q2x-5V_LEzDog1U-_1m5pte z2X2SlDo6{&Yo!cy$NbCd{x4qLmW=dFPgldm4F{u&-Ou&w9;mStOEio!_VGEg%UEz- z*)-6ks~xz#R_l|M`T!!8c>26)B{gyBJpP-dO9C%Tq3d9@x#rsg2tkVrvK+@2G0AxR zM^n5EQCN_mY>{fqIW?qysng0fByo+|XvhRagPz^Fa~mwj2`c{4f8aO-gJD8-9E=Xu z4xRIpLU0_N$iD7&Vw)JKcYFgSi6_TxCv+NFpnC}>>uZfm17RiAXEjdu;A(_XM*F$f zAS2>g)PFNx0C7Csnj){(N0Vk1wqAQ%f}`c`_&_<)c>BFCLGq;*dW>8>!PM+$gldW* z;9edd!`-h$=;_H|n)mJP?{^18r=%pGU*G$hqmp3kW&M3;b^f`rts9_5C27wHd3jDa zXs*La^UYw9UwwDaH$hHDaMh3BlVk6!+=*_@x2?HCb&`=F@nN(3{=I{5J6kTtT|e>m zTKViJtzZdMUTJsT@6#RY9|GwUy?IeWR5(1y@QvE&fI*HtxAFg=RD9PanZNjH@-cdS3V4;-U)tR^HxW`ss`PokPU_sRLh3 zKBOY_k)FBj+p3(WL8K;avveRW_#O15iY3wBP2aeA{O8BTPdxsS4O%8^fVhSuLdniu z)1WsHPt%9)RhaQqRe8H8o}nDxy>Awdnrw~&tfBFSXnvrs9_zg7LSTc&W;6t*F)%xi1!%Mx@?k5kLP{nu@H+H3n#ad$_mxQr~fH zz@|*WrO%7)CL61{zqGuPHkgA4{LNxvsjC;5abMqCO{kcVQb|dEf79R)oHU;$I&i&1 z%$Z%{&B-CPVrz6#M?pd=$C?t^S??uNZuk8KrmU&CWOF3JwI#KsEo*42T;lGwtFs+? zp}?DaWT+X%&UDse<>^4^g`&gJN{)*o} z(s!Q8CllEo&@D6cp3o)vp_U>lrW|4~9;mBSyfwfUC8TIEFx>xs$uVePyTewpLFoJQ z5`mPxX6Y&OOvmES4*LUzI*tPyMF&Po%f%&3?sUiO@>+2gA7V7lA3k2ttwm4W1+JRg z*DtTzfPHIu7;MA(b4O-~`*xFAPL%9Oi1V)?oj0EW?2|Wy&F_zE+4Y4JL1h9~1TDoj z@xGXi+x8mI$2lf0!JB8CM)UTgT3OiZ-iMt=T(x+5*VW9iLBkRR3`^$_QWro&LLxs3h@nDqpAQ)2n&Hsv z;J{1I=baHV(iCFK-4>WadpGrRA`V8r^vXoV%<3}Y<0bG;lyLID4K~DrFku69_!PZf}5#E60k(j~1YE*3w8v=R%aD~j*`s9oA0 zkKfDZ-Y_MSbyzC{dK@|YRXnefk*P!CCW$K(RvRORj7Qmfri)=~ zpr=H_Pf&0LieXb9=q`WXntOtVF|cX0K=PWBnEKH6^b5C^Oeu=-ZbcB3jNRR&VvE2S zV~KCJ;@F{>YvDYLN)@7ap^GUFZ8E9N1V<%gkyE~$Kznq}n}e?!6_I)qn+Ul)z(qNh zG}P1QRvm@2$SV@l$akwnA0J~9!ydb6Pa6X8>E#DC>z|*k0r}4OH+?{%n#0dc7bmNj zjh-$Tl5(8tsHl-iPpn&INuIViZ3nYrZ1yFyJGH0n5Y&TCdC$7u;BqR4&GxL*uW$D6 z27GIRefavweFm)@%?!^f&Q1tyw!fa zpX;DE&)}Vy@TJe?!Af$xS!+E?##yzzawuZn3JIsRl11NnNtN4rnQUMCK`P+VTd=M` zmdLA_oMg0_d&umHR&S_kG0S)t{Mg$Rr9aw^83==8ov1R$tnXyJ523 zF!GfC%1B|(X0F`KyTSQlrKDBE zdM2d0=Qgq^H@arA@?34k*%G76Xa9VZ{KGapM&^?In{QNGq)gHie=t_*+Xr|g4B{Cc zpfxVZA(WokrWx-f#}p*50{SPPiONeCtnPJt8Juk&*}$}>AAPKd>8RN}p~l>e=J0GY ztVNEeSaBg@m^eKH&p$Gc36Z|W7(^LWKW|i4eUK%2O77VMw7p02EBBrT zKFxC57BD1}-&8DMGaBkC6QU=CzH0D(pJc>+U=bL&-CvNp%wMC|>TdJY?_D9D=3e)T z8?(MlBf(zeX^NGYO~k-UDgWjW=Px~T&Pu^1vK)a-*!?87vo3hWg`oOE6xPsP?+&sD7ske}aUYG zu%qoaXlMm!Mu-`Iz=a zalJ(h^sh_yUOH$kF&!75@T&FhxeRU8Vj#$1g@%1wwi%}_c(;v7h;(Jr`<)2Dtbjs_#a znQu0}Eub%&9*RSh>Kbh7YmG^Rfsz`Ug9C5Y{Y{4%OQ*BaZE6gPlmg2xbA{h$BouAL z2B|g3+|_WH>d;J)fxO)S1rfiYS*6Q9k;V0J-dV#mTD&{y+N(*{%zcKv$ny=~oSkpT zn{{=38nWTnFPPIzBY#>Dj)eqZG|NVBBb|K`_BbZU!+AQN_?Lp<$RCfc|MSL=Ch^f_ zEPDh)=?nMVwH`FVEVr4-?=#J=8eGo8V`F1U&U2$pCf)eR5(Qh>j^&7`2U##_oa$QZ zM~*9mh9%ww@2>UE!I`4YW#5hmX`{?ld7~woUV@{;-b%s*Hzn%Z!7WNJs!CV8^>fXU zO1Dw(uM!lTj`iid_?1S;^sRdNQ(EdU1=VsM<(pcHAKG(n_U75k)m;HYo&s>w3Br=jzbQF@(XbT(dF z>+8rGeNVkGBHm2;%a?Z@yN0pufPv|B-M1W>j8eo+p(Rc_AM_QB`}?@Dc2OAjLovRU zU`eGg9_et*(&QCfFQ_gPG>5q>1#ELAdXd1O&mr1Z=ek8XSaD)ELPv|Um4D&!%4>YH zbqyCgB&lSOb?t6gHpto?^rE8QuJn7YJZn2?}D)!uTOlWxX#0b^!+3Sa`yS@eq zZi>vF(R0;Q1!KvJX zur4e9mVHrOU&&3-`N3ziecSMJ2t>)#aVTDUNAwCVwlrqAh#gFy62Y*<(Nq5mA_S7U z_H@kfVf3#rypBPz%HQc8p5&&M`Ji;3M?}^8GE%()^DqlP{@i8Nps;;}(l$xtuV(#k zIrvwSUv}-ila+SZnSB6P7qaxWFVXM488-L8q-G)}!H0WKIQ6h1S#y7+J?dL-&|dt8nh8S+#m?14T6>(3U^?0Na@zy@*sI^V z@{U>)XO0>VJHPk%Pca?C21AsNSzp2q7f~XLFNF$BzEWRbdrpbS{eWbz;K$KSF%9FD z!m{}={dnO<{~2GW^`rfxgPE07H~aXzB4oXWUp`DMY>lyR-!Ls!*tiqI0k1W&SmdLt zYQ@}mC5m`>Ni)!amyRiAoGI#Vh>EmQT9AH?m#b~pJ0r$MdMILbzb7=FEXf zlMf9;|8mFtt~>rDJa`wJics?e6DlIFIMk3s_IYyE9@^cIS>|49-Rf3`X2o~DWWSxZ zem{sabT_!YR71{hn61fAYEQVt0HPF_Ei-wiO<1YpMzorEJm>8&2<>s$?k+oi;{#pY zo4bVU5A5|WBZ;~yr?6x*jjETh1rIX{svSpM-^aP%tSi(aq*sntr7lgnO%CH}MPb?1 zej7a|htomBUJWpFm}Oq&`Z-o%BuSJwFINyBU;3P<6}VF^E&Sv?I!aSZI} z;jb-j#oGh6C9j`RAHx<$jfg`WDz@hhx-|^+Sg_LvzNrxbyXyLTykhY86N%Vh@ z#P#;4GdX(pI}crIoBH~TJXF}eIw9@YE4GZCQ&UUzz41#Z7Hk?N;!&rOWZ8HatzCgW zV<&qj4SSL(EqK2boTE||b|=rnAk8zWy-{QVLV5-7^690D>(sjRF>EzCqEqMDpu@8} z1Q8hWzRXkbQWt2>A(L23q11n87=fVC!3ydkH7kqjp~tX?Pn#4IlA=XmkP4f(H26#p z5x<#-Ugsk`qALY4#<%9;deeElMDq69a-O{|SA77+-*|i@qOGM$roI?8{3zJCsvS*< zc+fWn1IqmdC^s^p@8ge@TMsBV!Mks_uu12%@Furxe)-qsUJN$&I!sN5fghs-TeWks zQWwIWfvpDX!mY6$oZZk}^i-V4_9`hn8uhZ;Kn}OY1!KSBMKmF``*O&hX@m896DO}1 zCX9G2j9&$+v>5(~zK1X?75@V`Q1CeckDimWPD>|&9gs%=AuuuKS1m-_z5BoMJvdV3 z$k@3;kt62SSzv+=;(;ZS#e=0;-x+Nd#t0*%Ee^{1vy^W!lWu8&U2&>*wwbU-NLq@y z#{Y`Dp*X9Vp!pk42SaYbhf97S7%~`f+iS?JBXk``D zl9q%tiH8-}+vY0H_ZM!`zd`>PiQ0=)i@i^to{xAmJq*1@6)#}nA~2^4GH%SRDL9%( z?n*t45S9bs#VIX;S(>px)65&6z8O8YDlNpd~(y6L(`Jm_P;LDLf zd5@p?h^9ID_xSRQ|E2R+xe_hVRyJR)t#Ul0@y5=g@20ubA1OQ_{fJI_7jFgJgunfL zQyvn%=(&2j%j+Q%XFLeM?gP7@Z<{HHE z_!er(&)F0M5XwmCpZw99QqtHoqJ7`_9H#jlDEal?2vqwFt5JyEt`LfN(_POIL)p_? zP(YmNZ7|b7!8fQM&Gc@Pf@ZW@APQwq(024+TCW>)H5f7X1OJpw;G0SW?oPIDL^btLp3M5r)7qeN6o)x5)tP4|)cH}fi8YAQfUtaA7nzxn!olcp=Q!(z3i z-rj^=3-%ajY>xog>7xrX%Rk!blr%e^Z&YQl-I|QKQb?`&3VAEUCzD=fUi(5#5;$bl zhPmUs$JHKQ5>h@S=l7SUus^I%dOf4cucW3jii`2!q;*qYX^h$M>h;W-@i@{w$nESDgn#_V6QL)RJmdN251@-cImTKuKMFLA%{cH*}Gi%me(X48`= z;Gs!q4-ScOHCx3PMdnr6&75Z{UJ&@L)kBZyt(Q>b$u3Z;K>8{S9J>RuLc*mr#nXen z!9AN~5Q9w%yE2VvtWDl1?=g~h>_EIScK5J5b>F4I3-59v9&cMx19= zctHyG-}!T?M7{dkkw-~Gq%wmYGKE6xa0y*)T)uqDzUy)(efQwYK?>)Cx1gRX7&2ic z5gxdDR9h%ewzmk+ELB9ydLw(<#{_*y_7(8#ULAmErO*l7kHF_Y{%u8}F6 zM3{jexNct>#l=ZT82}*m&Q6I-{jCavclga;P<}!bV0AfG`Jc-25q-=Do3~)OpV0O9 zf|dVgCKRkZJr!}~zl|p`fa4JH$B?}JsfC8w4PzUw(Y7i+`%{WdAI zNU?WWPhS&Sp)gL5+ulzr`KC@&cZ&F+USqH>ThPgqKe7X{SH3me(0Zwgjwh7o$t)V<-F|;1U@7b#rUJWa67*KZAwt2ir$9~#LN1(FVbR-1475U!S4@T z0KYERwPySy$s+`Wg=g3%A)oE$r$b4OKkc=SDpcdL!N|2<)o-%Xxt(6^EYd&Z9m%=wJpn%<;Yg_7UVsPfU2;2n zhj3@owYH&Vd#uE+AKpK_4@MH^1YSF$=(a=5-w$QVK$xe%L0qWkBCKurjx_ z`g-gjg70wU$hz(zeYH3WId+g96@K7_Yw_7O*zHYQEsoO^2$T05YI%{Bnf%n(yw8{9)(Ow>eEeFNTYLw#%!pLIwAh#tu`fZ&%rg&r9Tf zKAIc*o?LA+thwcfd*zy(Q)yIl{PeZY4|H(Hd8JNQRiS$lZa}3E`f3Mfd);I&84@Uz zu2**;4z_i?tD|Wj>b9$_o)z5xzS%fmx6{>ponmy8#pEz(%(r*t=zYld&2jE4az_pF zdlSdc%HFrN?Fa|<%M=Af34O38_@hk%JvU&T?z8OsWd^laE|0r`8gVs|@bwtG5yaxU zxG%r+m1SiAo&CuAyOlCrD#UH+`DzWljQdzr_^Flh{r4-SxFwmP2^ksRz0@k-${O+7 zg9du}XHLUsi&pdK$0AlI9C79AO=YDxfw9ol0*FH`JELR?E`03Z4#TiRC$5iv%##&I z1u2z(%gMNHaGxfzb#%c^I}*xvlec~4aCw8}TsQ%6SI{a4sdalG zkssoO2s1JXcbdq*g|Z(Oue)a*##d&AL`p0ZJQ_xi`d1DKo+f*^DTC$bPJ{7G2}bGR zP^4iQ@`l8+^q0tnP7n*`9Pn<1pZKsIoN%CL{Mvo&Xr10O59=JR-VwSLw0(V}L91}o zb(nYbjl(czIEQdZvYhu-=h94EwOsCGzPVuUx@M7=L%3GAp0;&BsZfg-}AM=i_M=gMi8kR8M7{l(7f`-7dv^U>Zc0C};%LZZ|!w%q%Ha{_y!@KpZd zD`@Hl{Isy;1R-51Y|bZ-9s&OHYoyL;3!A{~3rJoo^xC9Ki||xo1fgDq57$e(x#J*% zixq+8MXG=x1s$?7pMG(+MY!Y&lhGyYAw7Z{*Yym7nN`*e%cdQgjeuBQ;(}nO-fV#o zd~cyq1x7Isy8+j7Ru`f=E4&%+z+K-<`+<+MA(nf+@`Gp1C2T-2VU`}jmn+HN(0gWS zb872k6B_PSfHrF}hviX@&C-LU0?%6WKolFUSADbOiH|v~b@%0c2NF_SfYw?u0rwey z0GYSWsmj?8y~Mb=Waq}Te^s#pmn0w-7kw1J+qWO#%1PSrY~s`d^neT?vhv~ z1IQGFcy;iS_LfY87R+%Hf(=DTV)J!ic@8l5Ib8AO^bl})k|Nj`SJ@)oDo~OEy@U7M z$H+SOBg#Ct9BdwC7bFaTkcVu?=edm zZBKZ>Em{hhmT;R!7m%mdXa>O+x0{DSKcdx-w63uoBiTH64w=&=T~6`$pyaPiw((Sc zXw>esOjFH9Gm^0Gf7Z{je>sh;S@9Is{1K{2^AwkS2qWHSVP9U&8y~*hAjaF!Tb63r zmp)zE8!}f*Pd%-gv7rMCphp}{>n)Wle?(7r?9H$oY$WXN;5&Uk2b*Wxp9eQ;*NikH zFlnEF<}#Psxf{*X+TR7B)CS&nkxX2JyIZ zc@x-{ZcPDx64$}2rRM4o;=P&j>I3RdmWQez9KUx4u!9crPk@KZr1M_xKL@Zse-OKA z>amj%cQmm31^WEj^k`Q4=$Lml)8Xu#@jIJGDANnrK4s^nn#t2Ow()EYz0V=EA}~G4 zqypTm1zO^sT@$)eqT4n=0`8DOiyV45xTza^ZXqi3h5q~AIqqPaQ=n;XWw*o2U!1RRC%=1Sy1a%U(dg0G%tB2cVU#fv9= zKcoHbb$DH2_0(PFem)0|gn+G(ikc4>L-f2HQ9kG`u?Cmj_{DdT<}gn_aIp{r!r;Ai zNHF(zVD729O*KC_bHEY-n(v9SH0l~(hF}#PU-Ey4I8Wpa`|iYm`%AX1uK9W`GU8UJ z9C6GoAV+XdLih;~;en{F=!J!b;-{2|EZUxW${yN0oG3L?zn=*SA|qtBnO$SyYGEiL zd0OHg7@buV&~esmO%G@`%5vG}uiSW&{!t^CBALxi*SYWj?nF^hLn$2Y@Ig$tA@&q{ zsHUk>6t=7EJZS7JNi_;}sHOzr?*pR{$R@a1Pp23~Z>=G|+$SNO2SIMFPFE-0AE-Nm z=iJwb!#0&eb&mKeIG1^pwbCMc_|mS8r12ign46_|Fsb%Dzh+W-+iczfEjU~>;m#cAiev!fxsup!c}Bgk zxo^loT3atUUQafpF4-{cd?{0f-KiC6xrU3!y2kO0LmT?szR`_7)G7^J9s&&czD;AyS}ZYfj*gl zt0R4XnYCeOsnZkp=Zpkz)LpM^#IW8z#^0b>pyqhbmtT4Wwp|hq2o4;QK;fr$^%?Q5 zAQgsI@@|_btP(u><$c9}>X+CA$V;Ol6x}hsueg8}BJ9?_JIN_uDc!fBl;GtpBoJ@B z*VVUT0cP1vPXLWpOOZAgu-*l=Q)%=RX3vw0I8-j0hWy*Zjoa#;w^i)v_vKoVi)lpn zIWmJq56j*-3m*LH%(@~I8WsW^R|&thyk=g^>Onx^xeCT^N1j#zOGaFYU3u0*w<4!? z7v`l*6P1RL>u0zALnrE9zMC8R_i!PpIQ?NRL5odkry8Z>ut8<#ydsv{y8+`ueSY@b zlCQ`SPV5!34Kyr4SNGpABFx+y&B1O1V+UL~&w8798c*VXI{cqd*PlPwJpRouWqu;U zl56a>F|?gJ8223<4djOHH;Z%e3_`A6LZdWyBE)LX=dF)gHXNQbrBIYFa?BRe_umL?6R6lfGwGu^s6C|7q{b z!=YZ^xI1kssbs<-6qN>pDN9*P_BBIf50x!sUo$yHj4jy-S!OJSWZ#7uBFQdm85&Dy z?EAcr^E*zRa~$vduIv5%@m`ny(#-Rn@AKTx{oL#4zMq%sbzK3yr@66Ht`Z7sMd-;9 zgyvb98wBk0xWiqSt<1pTm$Wu~S>rW}==Ao*?~B|&$r{l~dKh$NXh|skxAlM_u;~79 zuKM)=YvBy`;^Yku-?zcxR=ckmD+)VJ>gL>SOuzB+>({R+!7{79;)$MuPD_UEgQ-k= zSy!8To?|{Ho*R^ZQZ_r{RJ!oqC|DIzdje8qGgw0QQz0`gMX zoB1`9l-yd2fi90Gq#M@4t(!-R0uwUeHgD`f%HAW`HD;|GlK-?}kK%;7j0s(lNTvOH zL}row3{z4JZ^n8I-gx$QBx`OngRl`>5xomO%F*AzriD`2NKy64Bg(uGL_LSg z^~%fw`;s0msZs97;mh-)x(+qjK}#w~`hBY(G=8aFoY5?uhm%ILiSv_#Hq~7+17|seobwyYBW(Dp>_^+8ZZu=s4&i zh1ma7y^i< zFdULxOkyVlBR_SkkJmnt_8%3sgHAMuEfwMolBARvf^RN&Ez!y38_&R;q&m?+N--9p zIm_2GoX;L-h7Z0QHXwD#d?;BwsN&MyF1UUwk@*Re$2aJdsIUYxb`2l*pzEZR6;j@p6)GxZgs>+#|b%sRPk1@oPP8)81@8Y@-{K5Mw3IDxz9 zwDuv1`N1TeV9S{j0AC%n*EgmiTG3 z&=D76bJKF`qqwCM3aM++^u%Es_EOGre`1o(IbD3uDWKBr&~BMx?=~;=enHg#6#{bq%y&csy6($^u|&@JnbJo|57ipbvd~zk zFSzqx1;L#G$oysNH{3=Uvxqi3a4jf4WWY{CGPt~WZiQNJd0g;0J=>uby9jr-Fnf8f zVSJ9kr`~#)gRB38nSRiU@FGe?THOue;$IYG0Fhe9(e%&dJ2gsqiBI~jluyLk0Zaoy zm0jnuBbMY>d}iMuqnKPq_2>Ap9d z{?>8h=vDTr69JnHWQk6oQCl6CVx;67Ahfep!h+i|DU{i0L^$isbGvSI%k5RutE zzb1Q6(h9mS5`m01CQV!S&*rNc&lJ{*yA0$sm7O1CGKqCly_dm{T#MDzN1BK%wP0fK zsX@s3HwPRgbw?*s;(mP_=wmPW8sBzNj5;{5&aNhlqGEC6fL-bMBZ9OQn?Q@}utkuH zOQ5W6>H1U?Ut$kd@XQ19G zu)&R|Y}tWbGEXKL`R%s`=Czd|y$T}6v=rjt@kwyf=bR$g;dzB-YpxcBW?L?gfL?_9 z3SDL)d`x`J^`jw=-!(rO+;iGWOL7upV?VOrmUBR%DpuB613L3@vZAN&`KbLLi;bRhhAKt z=C`(*GwincH20~_F_?32q=0V3zQ~%$bdGNz{=*c=-L@{ztdUziD4*uv<5ukumwZ_5 zOn8f!O$NJG1)2*z>&0nwv?dhiN3XVEWwRh7iX5DYF!5STevlN=Wl;9zF+E64iYdC- zrxjZ2=IWxH?heOFoAeZ>E~$_j_%#RIRg!1*=chX*bFx$CHOnVqW;2E77gOhh05mwS zHYGZUUaigD|NJ6NKQY01xSC+?GmG#y6#>X2QxV5`mk7v0P{ST~B6VHN(-Y$R)^zIT ztkX@^iqgfHG8G>=g^&jO?L#slaWnbCH~8OJpQ1PUcKo;uFP{{M($N zey+KR3dFdPGRWIN_nE>2j_#|!ap6J*g8Zn{0)4pAvbCHf0UVK004b==EfvXD++5?c zOXglen2}<(moBX_FzH!w)c993z`gRZdY(7=%m)E*zmg+wmQ>9r_(5~E$dh#V$DLnf8w~dypUObnDEQ%ob4mbQ<={Q0d-6_W-K~*>9}rPq zNW`ShzqBf6Z+BtP(wM@$s=WzupJns|>3rl6a%CK1jH2#2CymcmoesZG>PN zjnASKyuX=6)zz>jQhDvVaCV!o>uj=U;^ju~m(~G?)tIM!Qfui1+}Vs+(xjAzM8uHq z1k2sqVZl9h+HJYE%-LBQZtgSXCZY>3WSu4P=vNCZ84Km#u`)6bq4@!R6S)AoYqCCi zb;BqFPPB-Ozbp^a9N^6=w)|EUuMG1o6n(9)1%b7RxYSS}Wd)sYK^;+?y0q47Dn(Nk zk+?^#=2H1=-jrkpIg8Tfm1|IFEc7aEJ`66k0PNX>0QObXsTR`8nr{pWbD}@RVpmJfz zUY-6E0TD)$F7Zx8{$^*Wbp048c<@-OTViA_gS0cR)MCHdq%9ysNHtQLCU*u#%OH1H zMuFWF>)w4iqrM53I1xch#p?@KTBrGf+Iv7z`qXimY^W|Nk2VP2*wj>u3?E#aJ%28t zCh}a4bLKWEFW!LN#H@SR`HO2!Y&iRt5-~omv0xLiBM(O5!A*6wpi_ShC@`3b$nwpV z@$WjrZL2`EAc|&C;om%!@eiGlWnL;zBkVTZ|n2jtbZwFehD}gJy{-o2Z9V<5Hge;QZm6_mam*+2Kz zE~$>E*V#CIY;i7CoHTxZy3Ne2HD51S2i1x191)^TCmTqJfh{GUK2U3>6*w4 z{hs~$nr?!)l8Rk)+*6ru^_TQ|pf1C_RJ~V#+W{jdY_8{^=KqRasau(IKxFb+7E(}3 z$Vjq{E&ro@pQ*rI{G_aH@>-6Oq&I%>Wx3k7DF~A$A=SuS()(G6oSh2y5Z{I~)^AdrmMn zqf6^%gj6OX5U~WdFjtkgbQWS^Ys|Cy#gmzaJ-7f5J^!@sCLdsIUoXB=6M&LSK5%Y0 z!l!eFuoCKF2rT!1&p7br?519)51)|Dl5roJm|DHgnaX!*49+`|ZTf-D&*`wd^H34m zuo+x&l*HMT4WqP^uonP*s~c^CybV9QCrCOx?=7-#6XEov;-c#?#(Ca5~!lPm=`y% z0DadSudh8)X+IH{7rzuMBf8wnW5wJYb*{UmbR{>(dVqLKY_d0RrSqtG%VXO#(<4wE zU*dIqLE^I~H%2QvR}k`#-pI4Laydviuf>KhUsG6H3-4|W*UpQTPM??`v8Q9~cSvK> zV`z3BorZ{)5z_#OA*+_m_ z$%Z65_9UkcodzKE>KDaKxiq@n!>{`|xR5RN{Z#&(REk`4Pr_-VVN{JU2g?(5qi9Y_ zDgEBl+3W>vIVQcIM-a#`u((n0lpkyA83~b``)!j=cQLybX$hffbk_St%ki z2KXq*C`efNPA%SYjSE5(L|j1>Y(V*C3QQ@RU5ONDqsM4wIibu0`*yP6qgz^`SBLkw z!}U z|8g&yPY2PRbR9aF;(lMU$~fUILYUCp`Sh-HRT6tY+>|Y&xf%U7AOa;9h+t*FhJfEM zpUt6fO^^Zhv*XzT_ojBXJ#u?EFOR2&N*frUGuJ*J3OgwpUVPknwBf2RS~UT!oP!qa z=CC?l(AI97_8esKk@`T5l8Ww20k#L=b@eAV?jPNb?Ws3h#D*x5mS)%Ea7@AT)wiC+ z!2ZWFk45&+-(-mUP9Ll@cF+-0%nf7K)9yIO_Xkm>n2t2Gp!WhZ#DKxiQLP={oS`;wd%Bj(Q(J za_zl@G7S7M;}dieIZc5`Pr9@}H*xf_$a29)ZTV}_gBmsp15y^%4$Y4-eNXOMOVBHb zYiu}-@kWYClnz(UE}XE`uVhOvSkuYK81N2Qhkc=S^cuhSfc|pnIx{|W`~6s``J3HJ_&UrG*2|PUKK>jc)uUIC2JcFBM_3#!yxLPa+*qxh5w`qBeh*&W zt11p7prGKt2lZbc*!lf8V{4?FBASq2sI8Zuv{F=<+^312|DXkama0o!VS}ky{$p$u zo1R@@7E5=fLDV1}rVHF7u0p;Y0)U<* zw+c_abA`h83VYuc_RdQjwa$Tnoe^bM4RHdCDxYP;K^!g>U#ELHRNlhWA_YwsWQmZz zkY-}f;7!H#HJ3%#Ke}z~jP-^j|L;y3#Ex;TDc-4$+Co_fRwj0;U3KJ2YZ;5KVb7~N zN50e(0YHu`i2K2rY-<3=s=j+PE|5i#xR93Ry;5IzHB8s44rCMm%Xgk!sTT~SM=r`B zO9yh|44kWNYRhduI%92W-{TewNRtIegl*@1-igfztuOYa#6DOFq?oZGWcGpDiC}Ma z#S^VQ|2aT%6$rWW240xr1>J)iHJ`W4$GC4&5(U~ohA zdZru*Ww!uTB%frzfp^~GSpVn5r^I_K%X!uMT0dABC?~?O#KG#IB@ofa5U^V7(@PXA z%h8=>X1SH1v=s#pTl`Wy^Fi3}21C=pB8J8-{Bu#0xN~^Jo9QB+VMeSLi>QHrT1}Ie z8Z~)>1yk9CT)MCFp)$ga=fy@QC7fx2qeOE$Pc+;L?HO7qhC*+}q%sd9Q&4XG8GNG4KrA82}XW5?ZnY1Y2+3$O@hV z=wLp>`w`m!og+_s8mulnVQ0Bxx_V-&&}|`$#pAYjz3Ebl>%!Vm{_=Zw4Sxe~AZgj` z+r2kj6HLhEL2T^5+ZeZS`&i#WM5CnrQdK&(+lIz(3ih-s4JpGqXe}45} zR^kIs`^*3T{Usa#fSvCAi*DS{>;3naz|Zmj>r4Ogk}FuigeQ0&Hf)nP`RM_GTi;LK zHm7b>e+}-t@3NgF`LTeS$Tsp;w)?~es;zVvHz>U%gLVM@&hXPtZu86wBOo(Sbd|%~ zx$-|q0hoBtkLhnmlN~1Bq}mP>Z}Q0w6aR5`b|mqp5c?lW;#?p{SpkO9_#SSkuvy>O;AA|y!%(8*+0O$$=9T4HhMh<4I zWwq&4_HC0W+!R3I_+8Jgoa|uhlLR2cisKdhe7Mj7kK8-a@$oz#Fn~IQF)~#*m{UVI zj8o&)`F>+!m?|7&S^=ODrh}m@y(IZE!XzjSCP(k2>Ys9a>~{tMB9l6!E_Y1*p@F_^ z_`ap!wJddUai^b%xsA5FQnoKK2yrGj@e#r!W-aS*09=Y9rOO8-KZ&v_BS>_AtCJIX zlvd~B6&GhIN?PPU8|*mM-$#<~9sEqMX8tKuTq8>#{1-c8N2W$M=Xrg%G1}-jREQH$ zI)uJEAZ?z;{tt8Ro^_xf9%x9W5A&B=1MjrixDFA!RS#vVJGEnY?MF0dT|<< zZB$yat>p07Dc&+Ly0ye{^7%GQ^ygO~1_4S8-#o=^+k0tq_$^mpN@JWRdN2QN`CGCs z0Ih3M5vLnI&Nsx_C{vhOs6+q>69w!m$0 z&U{zvPHv&|wlMl{DtmSv;U1J9Jp^@vh=xsTvPMFP$%`4PG4<$2c**8)XhnP7MeJLw zw{pW}O2RqvCJKN7*HC3c)9)nrn+01bF6pq1LztdV!-fzM80VT0@2*I)?BQQ_H}D+$ z1tXFR(FBcn7;6H?aF7is;8?f1yQEIa;I9$LL*$X}A!x=~!)?2VMuzBm?;;%yBZINL zO-kue&|9w{-0v2EJwWKZbhdV<{PhMSWL@A0Wd$HXXf1|4oqrB{0#4jT5= z3t`!qXq(Z_pugeht)p9LldTMU|6{VkRcLyI$X5bEO#oU28WFM+~%qfL#U~vv5g>1nw z|I`Mjc*}u5y670V9mwhj+rhWwq z++j4Y&_OcBg5Se~ghPNeL6!^xf*+IzPAG?0vmALMf!+W_F5HD>w&}z06S=N~o>FR1 zf8}iep+9KyuyPSB6W??B896lB<%!tH{2GEA+sN8Z9NjTvhJg>kWDP#B!{R^f;^r3Z zu=o~&V28yw+2beT>`3t~j-$JhMNb#+7`i`Npg__9cCt$}aHXAirQ>I{7ui zAU6u~bg`fsc45+4^h1{{PYCF`xrLzk`!RW;>p2n)u>rN#STi>7T+oETe%)F0nXF$8 zsP>cPLGNLGA4&)xlq43@s}(5>-`j$r{z=Ygj$<}x=j2bI{2TpM(a*`aUeAcKDAW_R zOYNkVB0qoohthvOwACl)HBVXYEwCeexMXRsrd{E&_Dmp5L6DjvnQ3@%5xC4WaExt4 z?We6C{Yj1fhYo!Dr&?s1J)jP1U>f#nD0YPaI2xz)?tGvx58FFPg)|4potSN#hW}*C zfv(>S>{5g0??es;UyvnQltxyRH@#M?(E;t-*9Y1I z!f5$#O%z_xAxT_ZTu`v!!OFaS=SCZY7MGftZY3;v_U)YUopDua?)&G7+3J()#-1Y);Fd-EN5QvIG9tdW z)S6&H-Rj(B{K^o^s6n~MQG@iE;jmQ>DFupgJFHbZqj!9^mLp>u|)+R46>nX)0) zqi1o+(_1{Y#maA@K%*_%pw-x!nVDcEd4ms)jpzXeaO31!IP0DhAmv(9g3lnzi^yd> zpQeEgiKyl!Wml}X*Wi}QNq zH8=2drF`Gilw~E_k!27+X}>Vp2aO4>07=kX+u`~HFw0MG&ITHQj(sOjstkS}7_3*+7^qbBFjw@&sIQe_SX%r)h9bl0;%P(BQ>3VUsk`-?qKS zZj(>JT)B6rF{(WdW_<{OCp#xw4i09^`a=^{(hjPD9{xpYW22#t=`S0Gddc)|^XTfX z$xwqvrqxm`nA{TG-W7neJsD+vCZZUQen%VM>9K6J&F!U|q6AD3cs;DHp@PctIt^&X z`gnlF27RtjvugIn@)R;E7?Bor;wqVKEWl0=!6I5LrB~2h%G{y`0F8~}qY8veT{nw= zFz<_RWjmWN80q}XRS4ZTOm@mv;?$sYvls|o0N%sK;2RFGZQSzNVN0wB@a|RpZzm(f z^Q{NsG9fC1lFd;EMK_(8O~vukT7UkE_JmK3D%>|zLV@TbCJ(^e;_f3DTR;6u#!YkV z|Ki5)K;M3__n$Q0fxi7oiXVUMK;O1Fi#yP_pQX{J%-MmyZ6S4cpl_S(@e^_Wx6n6$ zblE9G`770Tr1*{$|F0^oE`5;ONVNe!#3s=Gu&0%0DmpBq7QjI}GjyIj+2wiWH9$xL zSZIw5n;08_nbu0&TH4#P@MV#|{Ag2SBW%FydDIo|r=(8twZpGn=gcqdl|E2YfKlf- zBpnM{(62v=BptkSLDN1==s*q9A0>VOYbQ?EZm8E=&Fh(Z6UifZnEm!(iV`-2a@PHt zUxoR1{KBiSCn`0sG8X;c3zmn?wdGG)w-(N3`+&UBQtZmXltLdOo6^JN3PDZ|CA>t5 z$!^izY592Sfnq$5;cBzA7oQ3U-$(NYyz)ifPxmhO)zr&2!iIOSc^vU8esLBtRlFL(=!REb_e||t z6xe6_;!0hOpxvcC6$x{sm*S~f$G-bUdfkY7dl`p3l$7uHDR8mHz+6f1?Ch)P`1{i* z{EPFXh}D0$4_I;-D_hA0lhhvI;wn9=o%9x9AN)PtM{Rb;?C* zoAe0lVkp|(oaf^H6Mm5-=zEn**op)gW_FOYYqrrn z3iZ*9lX_%nPhpeC*_WRa8#qqka$l7`Qeh@#D~eO%nrIma>aTYNl-yPkJXZ#1ET}ri z7x)nQnMI}%jz2Wp7E@SR_%yI*k7t~fBI|CqTY@3h6Qel3kp1UGPyd3n5jZ`ft$$8K zd?GuBdDI0q)uu#Ux7WRbL6yQtQS{PiPc-eLoYk`G3iqbzF+u0aQDlBogYcSN7=3G7 zhV!ditLW?6O5$IJ8U%TBhiWU*IIRUmBwo-P%LimTjBD~zZ9w~OU2WwKv-x6bJo2RK z5bX<_2*nbCbVhUg0Q!L@!>C|_)jFm@M~^~oRlkz{iG zU-GP-!cwX&sX# zLH#Q(1X$Y;*I?@dk38QUz0FToS8)|hRlfE(BukT2U^QWGuK(W3I%x0eod#wbml?i| zCOxk0gHNhtd4@F`N%SJ4EBDLxAA}$oIP*O%KSGqeDw%=Ea0(EALRYacNgO?S+pQlvh6!cG)8xY;x~rOV4ZHpUyz^P2)YKw9s;(B9FN-SlbkMU$*JdZJXdJ4 zG<#Xk#93T!t&tK)vDu4gEeSP2v5ek(aq&o^arn89Ib{)3)e6QlnPtaE(u7E%Z#1JX z-hWNsdYH>L07FkIk8$jmQ)#L2X&YJZt$(x8XqGX9hQ|*;iN!6Jb?V#duCkRSsx$>5 z+{1@2YE6aEl2(V08qDc)Iu%gtUP2yf9f-vRg9~LVHDe0qR}CgtzU6?9*yWd?i3FAd z=4u&M$%?;-2ZyJP>gGWJ0Cx7xENRyl8I)YsReWZIfQ4)jPU*wr1K+}~NJb#UhsuQf z9v$R5_j%>Jk%UKuyQfk6(yuSv2XL`)Z9Jp|&u8UvPF>h@@yT~n8pb01%hTN%jkf*Q zxtxeP0aGFkz7xG?4=nEIKL#)NtYu03GW&T$`tz)bUOUKAl_n(B6kmZE>+j;NhqmOUp;rxBL=jd@jlFT{Vg1>*W< Date: Thu, 2 Feb 2023 23:20:58 +1100 Subject: [PATCH 103/122] Remove unneeded files from the gem package There are a bunch of files in the gem package that aren't useful for downstream projects. Removing these reduces the gem package size from 314K to 293K. --- webmachine.gemspec | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/webmachine.gemspec b/webmachine.gemspec index cf288866..7a1fb920 100644 --- a/webmachine.gemspec +++ b/webmachine.gemspec @@ -31,5 +31,7 @@ Gem::Specification.new do |gem| gem.add_development_dependency('webrick', ['~> 1.7.0']) gem.add_development_dependency('standard', ['~> 1.21']) ignores = File.read('.gitignore').split(/\r?\n/).reject { |f| f =~ /^(#.+|\s*)$/ }.map { |f| Dir[f] }.flatten - gem.files = (Dir['**/*', '.gitignore'] - ignores).reject { |f| !File.file?(f) } + gem.files = (Dir['**/*', '.gitignore'] - ignores).reject do |f| + !File.file?(f) || f.start_with?(*%w[. Gemfile RELEASING Rakefile memory_test spec webmachine.gemspec]) + end end From 01a5b0a578fced583f0a8714438d78d373c51232 Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Fri, 31 Mar 2023 09:29:11 +1100 Subject: [PATCH 104/122] chore(release): version 2.0.0.beta (#273) --- CHANGELOG.md | 6 ++++++ lib/webmachine/version.rb | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eec13fca..2ad7b0db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ ### HEAD +### 2.0.0.beta Mar 30, 2023 + +* Drop support for ruby 2.3, 2.4, and 2.5 +* Remove the HTTPkit adapter +* Format cookie 'Expires' timestamps as per RFC 2616 + ### 1.6.0 June 22, 2021 * fix: replace missed URI.decode with new Route.rfc3986_percent_decode (#261) diff --git a/lib/webmachine/version.rb b/lib/webmachine/version.rb index d38fd901..ebc973a0 100644 --- a/lib/webmachine/version.rb +++ b/lib/webmachine/version.rb @@ -1,6 +1,6 @@ module Webmachine # Library version - VERSION = '1.6.0'.freeze + VERSION = '2.0.0.beta'.freeze # String for use in "Server" HTTP response header, which includes # the {VERSION}. From 036167c394606cb94f6a097003e853fdfa662349 Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Fri, 31 Mar 2023 14:44:04 +1100 Subject: [PATCH 105/122] chore(release): version 2.0.0 --- CHANGELOG.md | 6 ++++-- lib/webmachine/version.rb | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ad7b0db..80264282 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,11 @@ ### HEAD -### 2.0.0.beta Mar 30, 2023 +### 2.0.0 Mar 31, 2023 -* Drop support for ruby 2.3, 2.4, and 2.5 +* Add support for ruby 3.0, 3.1 and 3.2 +* Drop support for ruby 2.3, 2.4 and 2.5 * Remove the HTTPkit adapter +* Remove the Reel adapter * Format cookie 'Expires' timestamps as per RFC 2616 ### 1.6.0 June 22, 2021 diff --git a/lib/webmachine/version.rb b/lib/webmachine/version.rb index ebc973a0..2dccc0b4 100644 --- a/lib/webmachine/version.rb +++ b/lib/webmachine/version.rb @@ -1,6 +1,6 @@ module Webmachine # Library version - VERSION = '2.0.0.beta'.freeze + VERSION = '2.0.0'.freeze # String for use in "Server" HTTP response header, which includes # the {VERSION}. From 12728ae1a48222f613c4c8f14df80edad93f7efd Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Sun, 18 Feb 2024 18:16:12 +1100 Subject: [PATCH 106/122] Rubocop: update configuration to stablise new Rubocop versions --- .rubocop.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.rubocop.yml b/.rubocop.yml index 70b0b6bc..2f434748 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -51,4 +51,6 @@ Style/GlobalVars: - "lib/webmachine/decision/conneg.rb" AllCops: + NewCops: disable SuggestExtensions: false + TargetRubyVersion: 2.6 From ae08faf69d8d45462b7c278655a3a0a107440b54 Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Sun, 18 Feb 2024 18:18:02 +1100 Subject: [PATCH 107/122] Rubocop: resolve Style/RedundantRegexpArgument --- lib/webmachine/quoted_string.rb | 2 +- lib/webmachine/resource/authentication.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/webmachine/quoted_string.rb b/lib/webmachine/quoted_string.rb index dd5039e0..bb039f8e 100644 --- a/lib/webmachine/quoted_string.rb +++ b/lib/webmachine/quoted_string.rb @@ -28,7 +28,7 @@ def quote(str) # Escapes quotes within a quoted string. def escape_quotes(str) - str.gsub(/"/, '\\"') + str.gsub('"', '\\"') end # Unescapes quotes within a quoted string diff --git a/lib/webmachine/resource/authentication.rb b/lib/webmachine/resource/authentication.rb index 427c9a36..6cce84e6 100644 --- a/lib/webmachine/resource/authentication.rb +++ b/lib/webmachine/resource/authentication.rb @@ -24,7 +24,7 @@ module Authentication # @yieldparam [String] password the passed password # @yieldreturn [true,false] whether the username/password is correct def basic_auth(header, realm = 'Webmachine') - if header =~ BASIC_HEADER && yield(*$1.unpack1('m*').split(/:/, 2)) + if header =~ BASIC_HEADER && yield(*$1.unpack1('m*').split(':', 2)) true else %(Basic realm="#{realm}") From 64609405708833da670afa28146c7832f2144ade Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Sun, 18 Feb 2024 18:19:22 +1100 Subject: [PATCH 108/122] Rubocop: resolve Style/SlicingWithRange --- lib/webmachine/dispatcher/route.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/webmachine/dispatcher/route.rb b/lib/webmachine/dispatcher/route.rb index b7a27ce3..17fca693 100644 --- a/lib/webmachine/dispatcher/route.rb +++ b/lib/webmachine/dispatcher/route.rb @@ -37,7 +37,7 @@ def self.rfc3986_percent_decode(value) result << if encoded_val.nil? s.getch else - [encoded_val[1..-1]].pack('H*') + [encoded_val[1..]].pack('H*') end end result @@ -154,8 +154,8 @@ def bind(tokens, bindings) else return false end - spec = spec[1..-1] - tokens = tokens[1..-1] + spec = spec[1..] + tokens = tokens[1..] depth += 1 end end From 4a6ba14543c590bc8622740fd5d84b6bb93601c3 Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Sun, 18 Feb 2024 18:19:54 +1100 Subject: [PATCH 109/122] Rubocop: resolve Style/SuperWithArgsParentheses --- lib/webmachine/headers.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/webmachine/headers.rb b/lib/webmachine/headers.rb index 747afe21..3ca52595 100644 --- a/lib/webmachine/headers.rb +++ b/lib/webmachine/headers.rb @@ -37,12 +37,12 @@ def self.[](*args) # Fetch a header def [](key) - super transform_key(key) + super(transform_key(key)) end # Set a header def []=(key, value) - super transform_key(key), value + super(transform_key(key), value) end # Returns the value for the given key. If the key can't be found, @@ -70,7 +70,7 @@ def fetch(*args, &block) # Delete a header def delete(key) - super transform_key(key) + super(transform_key(key)) end # Select matching headers From 8afa76fba5de8bae25d616ad4de18ce94122ff61 Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Mon, 19 Feb 2024 15:44:01 +1100 Subject: [PATCH 110/122] CI: add Ruby 3.3 to the test matrix --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8019f413..be954557 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,14 +9,14 @@ jobs: strategy: fail-fast: false matrix: - ruby_version: ["2.6", "2.7", "3.0", "3.1", "3.2"] + ruby_version: ["2.6", "2.7", "3.0", "3.1", "3.2", "3.3"] experimental: [false] include: - ruby_version: "ruby-head" experimental: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby_version }} From b26429a2feb23d19cbdee9392cbd7dd8578d5dc7 Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Mon, 19 Feb 2024 17:22:09 +1100 Subject: [PATCH 111/122] Add base64 as a runtime dependency --- webmachine.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/webmachine.gemspec b/webmachine.gemspec index 7a1fb920..bb86578f 100644 --- a/webmachine.gemspec +++ b/webmachine.gemspec @@ -27,6 +27,7 @@ Gem::Specification.new do |gem| gem.add_runtime_dependency('i18n', ['>= 0.4.0']) gem.add_runtime_dependency('multi_json') gem.add_runtime_dependency('as-notifications', ['>= 1.0.2', '< 2.0']) + gem.add_runtime_dependency('base64') gem.add_development_dependency('webrick', ['~> 1.7.0']) gem.add_development_dependency('standard', ['~> 1.21']) From d37fa8e0f8bd885dbb3dbba3bf9df81f6de90406 Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Tue, 20 Feb 2024 03:27:34 +1100 Subject: [PATCH 112/122] Add conditional development dependency on mutex_m --- Gemfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Gemfile b/Gemfile index e1702ca0..7b2a0ab4 100644 --- a/Gemfile +++ b/Gemfile @@ -24,3 +24,7 @@ end platforms :jruby do gem 'jruby-openssl' end + +if RUBY_VERSION >= '3.4' + gem 'mutex_m' # TODO: remove this once as-notifications has such a dependency +end From d2c0352a96460b170d778b7e8e8a8917195ca311 Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Mon, 26 Feb 2024 19:18:03 +1100 Subject: [PATCH 113/122] Don't put `doc/` `pkg/` or `vendor/` directory in the gem --- webmachine.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webmachine.gemspec b/webmachine.gemspec index bb86578f..0bf1dc57 100644 --- a/webmachine.gemspec +++ b/webmachine.gemspec @@ -33,6 +33,6 @@ Gem::Specification.new do |gem| gem.add_development_dependency('standard', ['~> 1.21']) ignores = File.read('.gitignore').split(/\r?\n/).reject { |f| f =~ /^(#.+|\s*)$/ }.map { |f| Dir[f] }.flatten gem.files = (Dir['**/*', '.gitignore'] - ignores).reject do |f| - !File.file?(f) || f.start_with?(*%w[. Gemfile RELEASING Rakefile memory_test spec webmachine.gemspec]) + !File.file?(f) || f.start_with?(*%w[. Gemfile RELEASING Rakefile doc/ memory_test pkg/ spec/ vendor/ webmachine.gemspec]) end end From c1d452bd71bc00ff6ee44716e3cf0fbad8fee4a2 Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Tue, 27 Feb 2024 08:11:09 +1100 Subject: [PATCH 114/122] chore(release): version 2.0.1 --- CHANGELOG.md | 7 +++++++ lib/webmachine/version.rb | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80264282..34220692 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ ### HEAD +### 2.0.1 Feb 27, 2024 + +* Don't include the `doc/`, `pkg/`, or `vendor/` directory in the gem package +* Add `base64` as a runtime dependency +* Add support for Ruby 3.3 +* Fix Rubocop issues + ### 2.0.0 Mar 31, 2023 * Add support for ruby 3.0, 3.1 and 3.2 diff --git a/lib/webmachine/version.rb b/lib/webmachine/version.rb index 2dccc0b4..f00d2830 100644 --- a/lib/webmachine/version.rb +++ b/lib/webmachine/version.rb @@ -1,6 +1,6 @@ module Webmachine # Library version - VERSION = '2.0.0'.freeze + VERSION = '2.0.1'.freeze # String for use in "Server" HTTP response header, which includes # the {VERSION}. From 21c610ae71b561825594b417e0e58357f90ff338 Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Tue, 27 Feb 2024 08:37:41 +1100 Subject: [PATCH 115/122] Simplify gemspec version require --- webmachine.gemspec | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/webmachine.gemspec b/webmachine.gemspec index 0bf1dc57..ee0321b0 100644 --- a/webmachine.gemspec +++ b/webmachine.gemspec @@ -1,5 +1,4 @@ -$:.push File.expand_path('../lib', __FILE__) -require 'webmachine/version' +require_relative 'lib/webmachine/version' Gem::Specification.new do |gem| gem.name = 'webmachine' From 6b092f943a998d1b0f525e328534454fdac651eb Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Tue, 27 Feb 2024 08:46:16 +1100 Subject: [PATCH 116/122] Move development dependencies to the Gemfile --- Gemfile | 2 ++ webmachine.gemspec | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index 7b2a0ab4..e6cd47d1 100644 --- a/Gemfile +++ b/Gemfile @@ -5,6 +5,8 @@ gemspec group :development do gem 'yard', '~> 0.9' gem 'rake', '~> 12.0' + gem 'standard', '~> 1.21' + gem 'webrick', '~> 1.7' end group :test do diff --git a/webmachine.gemspec b/webmachine.gemspec index ee0321b0..393990c2 100644 --- a/webmachine.gemspec +++ b/webmachine.gemspec @@ -28,8 +28,6 @@ Gem::Specification.new do |gem| gem.add_runtime_dependency('as-notifications', ['>= 1.0.2', '< 2.0']) gem.add_runtime_dependency('base64') - gem.add_development_dependency('webrick', ['~> 1.7.0']) - gem.add_development_dependency('standard', ['~> 1.21']) ignores = File.read('.gitignore').split(/\r?\n/).reject { |f| f =~ /^(#.+|\s*)$/ }.map { |f| Dir[f] }.flatten gem.files = (Dir['**/*', '.gitignore'] - ignores).reject do |f| !File.file?(f) || f.start_with?(*%w[. Gemfile RELEASING Rakefile doc/ memory_test pkg/ spec/ vendor/ webmachine.gemspec]) From 5937aacc295b525325addbd3a0a333f189f6c06a Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Tue, 27 Feb 2024 08:03:23 +1100 Subject: [PATCH 117/122] Move yard to the docs group in Gemfile --- Gemfile | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index e6cd47d1..29414e1f 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,6 @@ source 'https://rubygems.org' gemspec group :development do - gem 'yard', '~> 0.9' gem 'rake', '~> 12.0' gem 'standard', '~> 1.21' gem 'webrick', '~> 1.7' @@ -18,9 +17,8 @@ group :test do end group :docs do - platform :mri_19, :mri_20 do - gem 'redcarpet', '~> 3.4' - end + gem 'redcarpet', '~> 3.4', platform: :ruby + gem 'yard', '~> 0.9' end platforms :jruby do From 72fbaece6a73f6f26a40ce04e99fc9d06bbaaef3 Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Tue, 27 Feb 2024 08:48:12 +1100 Subject: [PATCH 118/122] Order dependencies alphabetically --- Gemfile | 4 ++-- webmachine.gemspec | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 29414e1f..30656fc1 100644 --- a/Gemfile +++ b/Gemfile @@ -9,10 +9,10 @@ group :development do end group :test do - gem 'rspec', '~> 3.0', '>= 3.6.0' - gem 'rspec-its', '~> 1.2' gem 'rack', '~> 2.0' gem 'rack-test', '~> 0.7' + gem 'rspec', '~> 3.0', '>= 3.6.0' + gem 'rspec-its', '~> 1.2' gem 'websocket_parser', '~>1.0' end diff --git a/webmachine.gemspec b/webmachine.gemspec index 393990c2..7a776cc2 100644 --- a/webmachine.gemspec +++ b/webmachine.gemspec @@ -23,10 +23,10 @@ Gem::Specification.new do |gem| gem.required_ruby_version = '>= 2.6.0' - gem.add_runtime_dependency('i18n', ['>= 0.4.0']) - gem.add_runtime_dependency('multi_json') gem.add_runtime_dependency('as-notifications', ['>= 1.0.2', '< 2.0']) gem.add_runtime_dependency('base64') + gem.add_runtime_dependency('i18n', ['>= 0.4.0']) + gem.add_runtime_dependency('multi_json') ignores = File.read('.gitignore').split(/\r?\n/).reject { |f| f =~ /^(#.+|\s*)$/ }.map { |f| Dir[f] }.flatten gem.files = (Dir['**/*', '.gitignore'] - ignores).reject do |f| From 96beba9e57cf1f718d8c5f858ac21416b2d309e6 Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Tue, 27 Feb 2024 08:53:47 +1100 Subject: [PATCH 119/122] Remove rbconfig require from Gemfile --- Gemfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Gemfile b/Gemfile index 30656fc1..0e3822d5 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,3 @@ -require 'rbconfig' source 'https://rubygems.org' gemspec From 06000876bb922739acb101db92875ba5ecff58ce Mon Sep 17 00:00:00 2001 From: Orien Madgwick <497874+orien@users.noreply.github.com> Date: Tue, 27 Feb 2024 14:45:33 +1100 Subject: [PATCH 120/122] Add allowed_push_host to the gemspec --- webmachine.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/webmachine.gemspec b/webmachine.gemspec index 7a776cc2..cbc61ac0 100644 --- a/webmachine.gemspec +++ b/webmachine.gemspec @@ -14,6 +14,7 @@ Gem::Specification.new do |gem| gem.email = ['sean@basho.com'] gem.license = 'Apache-2.0' + gem.metadata['allowed_push_host'] = 'https://rubygems.org' gem.metadata['bug_tracker_uri'] = "#{gem.homepage}/issues" gem.metadata['changelog_uri'] = "#{gem.homepage}/blob/HEAD/CHANGELOG.md" gem.metadata['documentation_uri'] = "https://www.rubydoc.info/gems/webmachine/#{gem.version}" From dcac4162c13b886b3d140856c717062c22863409 Mon Sep 17 00:00:00 2001 From: Patrick Date: Tue, 25 Nov 2025 15:39:59 +0700 Subject: [PATCH 121/122] Fix VERSION_STRING to use ::Rack.release instead of ::Rack.version --- lib/webmachine/adapters/rack.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/webmachine/adapters/rack.rb b/lib/webmachine/adapters/rack.rb index 6148b4b3..b4484d5b 100644 --- a/lib/webmachine/adapters/rack.rb +++ b/lib/webmachine/adapters/rack.rb @@ -41,7 +41,7 @@ class Rack < Adapter DEFAULT_OPTIONS = {} REQUEST_URI = 'REQUEST_URI'.freeze - VERSION_STRING = "#{Webmachine::SERVER_STRING} Rack/#{::Rack.version}".freeze + VERSION_STRING = "#{Webmachine::SERVER_STRING} Rack/#{::Rack.release}".freeze NEWLINE = "\n".freeze # Start the Rack adapter From ff96766871e2f803894bfa076984e390ab458fb4 Mon Sep 17 00:00:00 2001 From: Patrick Date: Thu, 27 Nov 2025 14:24:19 +0700 Subject: [PATCH 122/122] Fix rubocop linter Add pstore gem for Ruby 4.0 compatibility Add logger and ostruct gems for Ruby 4.0 compatibility --- Gemfile | 6 ++++++ examples/logging.rb | 2 +- lib/webmachine/adapters/webrick.rb | 2 +- lib/webmachine/etags.rb | 1 + lib/webmachine/headers.rb | 2 +- lib/webmachine/media_type.rb | 8 +++----- lib/webmachine/streaming/io_encoder.rb | 1 + spec/webmachine/resource/authentication_spec.rb | 1 + 8 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Gemfile b/Gemfile index 0e3822d5..3479e339 100644 --- a/Gemfile +++ b/Gemfile @@ -27,3 +27,9 @@ end if RUBY_VERSION >= '3.4' gem 'mutex_m' # TODO: remove this once as-notifications has such a dependency end + +if RUBY_VERSION >= '4.0' + gem 'pstore' + gem 'logger' + gem 'ostruct' +end diff --git a/examples/logging.rb b/examples/logging.rb index 82e27c3a..cda597ee 100644 --- a/examples/logging.rb +++ b/examples/logging.rb @@ -34,7 +34,7 @@ def handle_event(event) app.configure do |config| config.adapter = :WEBrick - config.adapter_options = {AccessLog: [], Logger: Logger.new('/dev/null')} + config.adapter_options = {AccessLog: [], Logger: Logger.new(File::NULL)} end end diff --git a/lib/webmachine/adapters/webrick.rb b/lib/webmachine/adapters/webrick.rb index d6a3e90e..52c6ce78 100644 --- a/lib/webmachine/adapters/webrick.rb +++ b/lib/webmachine/adapters/webrick.rb @@ -29,7 +29,7 @@ def run class Server < ::WEBrick::HTTPServer def initialize(options) @application = options[:application] - super(options) + super end # Handles a request diff --git a/lib/webmachine/etags.rb b/lib/webmachine/etags.rb index ed438420..4fe28a4a 100644 --- a/lib/webmachine/etags.rb +++ b/lib/webmachine/etags.rb @@ -5,6 +5,7 @@ module Webmachine # This class by itself represents a "strong" entity tag. class ETag include QuotedString + # The pattern for a weak entity tag WEAK_ETAG = /^W\/#{QUOTED_STRING}$/.freeze diff --git a/lib/webmachine/headers.rb b/lib/webmachine/headers.rb index 3ca52595..2de99112 100644 --- a/lib/webmachine/headers.rb +++ b/lib/webmachine/headers.rb @@ -32,7 +32,7 @@ def self.from_cgi(env) # @param [Object] # @return [Webmachine::Headers] def self.[](*args) - super(super(*args).map { |k, v| [k.to_s.downcase, v] }) + super(super.map { |k, v| [k.to_s.downcase, v] }) end # Fetch a header diff --git a/lib/webmachine/media_type.rb b/lib/webmachine/media_type.rb index da0c12d0..53ee0746 100644 --- a/lib/webmachine/media_type.rb +++ b/lib/webmachine/media_type.rb @@ -6,6 +6,7 @@ module Webmachine # Encapsulates a MIME media type, with logic for matching types. class MediaType extend Translation + # Matches valid media types MEDIA_TYPE_REGEX = /^\s*([^;\s]+)\s*((?:;\s*\S+\s*)*)\s*$/.freeze @@ -112,11 +113,8 @@ def minor # ignoring params and taking into account wildcards def type_matches?(other) other = self.class.parse(other) - if [Dispatcher::Route::MATCH_ALL_STR, MATCHES_ALL, type].include?(other.type) - true - else - other.major == major && other.minor == Dispatcher::Route::MATCH_ALL_STR - end + [Dispatcher::Route::MATCH_ALL_STR, MATCHES_ALL, type].include?(other.type) || + (other.major == major && other.minor == Dispatcher::Route::MATCH_ALL_STR) end end # class MediaType end # module Webmachine diff --git a/lib/webmachine/streaming/io_encoder.rb b/lib/webmachine/streaming/io_encoder.rb index d3d94456..3b41d7a9 100644 --- a/lib/webmachine/streaming/io_encoder.rb +++ b/lib/webmachine/streaming/io_encoder.rb @@ -7,6 +7,7 @@ module Streaming # @api private class IOEncoder < Encoder include Enumerable + CHUNK_SIZE = 8192 # Iterates over the IO, encoding and yielding individual chunks # of the response entity. diff --git a/spec/webmachine/resource/authentication_spec.rb b/spec/webmachine/resource/authentication_spec.rb index cf9ebb58..d7f89d24 100644 --- a/spec/webmachine/resource/authentication_spec.rb +++ b/spec/webmachine/resource/authentication_spec.rb @@ -23,6 +23,7 @@ def to_html let(:resource) do resource_with do include Webmachine::Resource::Authentication + attr_accessor :realm def is_authorized?(auth) basic_auth(auth, @realm || 'Webmachine') { |u, p| u == 'webmachine' && p == 'http' }